aboutsummaryrefslogtreecommitdiffstats
path: root/roms/seabios-hppa/src
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/seabios-hppa/src
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/seabios-hppa/src')
-rw-r--r--roms/seabios-hppa/src/Kconfig615
-rw-r--r--roms/seabios-hppa/src/apm.c215
-rw-r--r--roms/seabios-hppa/src/asm-offsets.c23
-rw-r--r--roms/seabios-hppa/src/biosvar.h161
-rw-r--r--roms/seabios-hppa/src/block.c645
-rw-r--r--roms/seabios-hppa/src/block.h124
-rw-r--r--roms/seabios-hppa/src/bmp.c116
-rw-r--r--roms/seabios-hppa/src/boot.c1104
-rw-r--r--roms/seabios-hppa/src/bootsplash.c255
-rw-r--r--roms/seabios-hppa/src/bregs.h80
-rw-r--r--roms/seabios-hppa/src/byteorder.h145
-rw-r--r--roms/seabios-hppa/src/cdrom.c322
-rw-r--r--roms/seabios-hppa/src/clock.c506
-rw-r--r--roms/seabios-hppa/src/code16gcc.s1
-rw-r--r--roms/seabios-hppa/src/config.h108
-rw-r--r--roms/seabios-hppa/src/cp437.c277
-rw-r--r--roms/seabios-hppa/src/cp437.h1
-rw-r--r--roms/seabios-hppa/src/disk.c779
-rw-r--r--roms/seabios-hppa/src/e820map.c152
-rw-r--r--roms/seabios-hppa/src/e820map.h26
-rw-r--r--roms/seabios-hppa/src/entryfuncs.S165
-rw-r--r--roms/seabios-hppa/src/farptr.h220
-rw-r--r--roms/seabios-hppa/src/font.c141
-rw-r--r--roms/seabios-hppa/src/fw/acpi-dsdt-cpu-hotplug.dsl78
-rw-r--r--roms/seabios-hppa/src/fw/acpi-dsdt-dbug.dsl26
-rw-r--r--roms/seabios-hppa/src/fw/acpi-dsdt-hpet.dsl36
-rw-r--r--roms/seabios-hppa/src/fw/acpi-dsdt-isa.dsl102
-rw-r--r--roms/seabios-hppa/src/fw/acpi-dsdt-pci-crs.dsl90
-rw-r--r--roms/seabios-hppa/src/fw/acpi-dsdt.dsl342
-rw-r--r--roms/seabios-hppa/src/fw/acpi-dsdt.hex554
-rw-r--r--roms/seabios-hppa/src/fw/acpi.c685
-rw-r--r--roms/seabios-hppa/src/fw/biostables.c518
-rw-r--r--roms/seabios-hppa/src/fw/coreboot.c569
-rw-r--r--roms/seabios-hppa/src/fw/csm.c374
-rw-r--r--roms/seabios-hppa/src/fw/dev-pci.h52
-rw-r--r--roms/seabios-hppa/src/fw/dev-piix.h29
-rw-r--r--roms/seabios-hppa/src/fw/dev-q35.h52
-rw-r--r--roms/seabios-hppa/src/fw/dsdt_parser.c673
-rw-r--r--roms/seabios-hppa/src/fw/lzmadecode.c398
-rw-r--r--roms/seabios-hppa/src/fw/lzmadecode.h67
-rw-r--r--roms/seabios-hppa/src/fw/mptable.c197
-rw-r--r--roms/seabios-hppa/src/fw/mtrr.c105
-rw-r--r--roms/seabios-hppa/src/fw/multiboot.c111
-rw-r--r--roms/seabios-hppa/src/fw/paravirt.c721
-rw-r--r--roms/seabios-hppa/src/fw/paravirt.h85
-rw-r--r--roms/seabios-hppa/src/fw/pciinit.c1226
-rw-r--r--roms/seabios-hppa/src/fw/pirtable.c103
-rw-r--r--roms/seabios-hppa/src/fw/q35-acpi-dsdt.dsl450
-rw-r--r--roms/seabios-hppa/src/fw/romfile_loader.c259
-rw-r--r--roms/seabios-hppa/src/fw/romfile_loader.h91
-rw-r--r--roms/seabios-hppa/src/fw/shadow.c210
-rw-r--r--roms/seabios-hppa/src/fw/smbios.c589
-rw-r--r--roms/seabios-hppa/src/fw/smm.c269
-rw-r--r--roms/seabios-hppa/src/fw/smp.c194
-rw-r--r--roms/seabios-hppa/src/fw/ssdt-misc.dsl104
-rw-r--r--roms/seabios-hppa/src/fw/ssdt-misc.hex88
-rw-r--r--roms/seabios-hppa/src/fw/ssdt-pcihp.dsl36
-rw-r--r--roms/seabios-hppa/src/fw/ssdt-pcihp.hex38
-rw-r--r--roms/seabios-hppa/src/fw/ssdt-proc.dsl48
-rw-r--r--roms/seabios-hppa/src/fw/ssdt-proc.hex35
-rw-r--r--roms/seabios-hppa/src/fw/xen.c149
-rw-r--r--roms/seabios-hppa/src/fw/xen.h125
-rw-r--r--roms/seabios-hppa/src/gen-defs.h19
-rw-r--r--roms/seabios-hppa/src/hw/ahci.c699
-rw-r--r--roms/seabios-hppa/src/hw/ahci.h201
-rw-r--r--roms/seabios-hppa/src/hw/ata.c1054
-rw-r--r--roms/seabios-hppa/src/hw/ata.h171
-rw-r--r--roms/seabios-hppa/src/hw/blockcmd.c381
-rw-r--r--roms/seabios-hppa/src/hw/blockcmd.h114
-rw-r--r--roms/seabios-hppa/src/hw/dma.c67
-rw-r--r--roms/seabios-hppa/src/hw/esp-scsi.c243
-rw-r--r--roms/seabios-hppa/src/hw/esp-scsi.h8
-rw-r--r--roms/seabios-hppa/src/hw/floppy.c741
-rw-r--r--roms/seabios-hppa/src/hw/lsi-scsi.c227
-rw-r--r--roms/seabios-hppa/src/hw/lsi-scsi.h8
-rw-r--r--roms/seabios-hppa/src/hw/megasas.c406
-rw-r--r--roms/seabios-hppa/src/hw/megasas.h8
-rw-r--r--roms/seabios-hppa/src/hw/mpt-scsi.c321
-rw-r--r--roms/seabios-hppa/src/hw/mpt-scsi.h8
-rw-r--r--roms/seabios-hppa/src/hw/nvme-int.h212
-rw-r--r--roms/seabios-hppa/src/hw/nvme.c786
-rw-r--r--roms/seabios-hppa/src/hw/nvme.h17
-rw-r--r--roms/seabios-hppa/src/hw/pci.c183
-rw-r--r--roms/seabios-hppa/src/hw/pci.h48
-rw-r--r--roms/seabios-hppa/src/hw/pci_ids.h2632
-rw-r--r--roms/seabios-hppa/src/hw/pci_regs.h556
-rw-r--r--roms/seabios-hppa/src/hw/pcidevice.c192
-rw-r--r--roms/seabios-hppa/src/hw/pcidevice.h76
-rw-r--r--roms/seabios-hppa/src/hw/pic.c115
-rw-r--r--roms/seabios-hppa/src/hw/pic.h60
-rw-r--r--roms/seabios-hppa/src/hw/ps2port.c547
-rw-r--r--roms/seabios-hppa/src/hw/ps2port.h67
-rw-r--r--roms/seabios-hppa/src/hw/pvscsi.c334
-rw-r--r--roms/seabios-hppa/src/hw/pvscsi.h8
-rw-r--r--roms/seabios-hppa/src/hw/ramdisk.c108
-rw-r--r--roms/seabios-hppa/src/hw/rtc.c100
-rw-r--r--roms/seabios-hppa/src/hw/rtc.h82
-rw-r--r--roms/seabios-hppa/src/hw/sdcard.c572
-rw-r--r--roms/seabios-hppa/src/hw/serialio.c129
-rw-r--r--roms/seabios-hppa/src/hw/serialio.h38
-rw-r--r--roms/seabios-hppa/src/hw/timer.c283
-rw-r--r--roms/seabios-hppa/src/hw/tpm_drivers.c637
-rw-r--r--roms/seabios-hppa/src/hw/tpm_drivers.h127
-rw-r--r--roms/seabios-hppa/src/hw/usb-ehci.c650
-rw-r--r--roms/seabios-hppa/src/hw/usb-ehci.h177
-rw-r--r--roms/seabios-hppa/src/hw/usb-hid.c453
-rw-r--r--roms/seabios-hppa/src/hw/usb-hid.h29
-rw-r--r--roms/seabios-hppa/src/hw/usb-hub.c205
-rw-r--r--roms/seabios-hppa/src/hw/usb-hub.h64
-rw-r--r--roms/seabios-hppa/src/hw/usb-msc.c222
-rw-r--r--roms/seabios-hppa/src/hw/usb-msc.h10
-rw-r--r--roms/seabios-hppa/src/hw/usb-ohci.c568
-rw-r--r--roms/seabios-hppa/src/hw/usb-ohci.h144
-rw-r--r--roms/seabios-hppa/src/hw/usb-uas.c289
-rw-r--r--roms/seabios-hppa/src/hw/usb-uas.h9
-rw-r--r--roms/seabios-hppa/src/hw/usb-uhci.c571
-rw-r--r--roms/seabios-hppa/src/hw/usb-uhci.h128
-rw-r--r--roms/seabios-hppa/src/hw/usb-xhci.c1206
-rw-r--r--roms/seabios-hppa/src/hw/usb-xhci.h133
-rw-r--r--roms/seabios-hppa/src/hw/usb.c510
-rw-r--r--roms/seabios-hppa/src/hw/usb.h255
-rw-r--r--roms/seabios-hppa/src/hw/virtio-blk.c293
-rw-r--r--roms/seabios-hppa/src/hw/virtio-blk.h44
-rw-r--r--roms/seabios-hppa/src/hw/virtio-mmio.c97
-rw-r--r--roms/seabios-hppa/src/hw/virtio-mmio.h77
-rw-r--r--roms/seabios-hppa/src/hw/virtio-pci.c545
-rw-r--r--roms/seabios-hppa/src/hw/virtio-pci.h152
-rw-r--r--roms/seabios-hppa/src/hw/virtio-ring.c147
-rw-r--r--roms/seabios-hppa/src/hw/virtio-ring.h121
-rw-r--r--roms/seabios-hppa/src/hw/virtio-scsi.c291
-rw-r--r--roms/seabios-hppa/src/hw/virtio-scsi.h48
-rw-r--r--roms/seabios-hppa/src/jpeg.c1055
-rw-r--r--roms/seabios-hppa/src/kbd.c599
-rw-r--r--roms/seabios-hppa/src/list.h91
-rw-r--r--roms/seabios-hppa/src/malloc.c561
-rw-r--r--roms/seabios-hppa/src/malloc.h74
-rw-r--r--roms/seabios-hppa/src/memmap.h21
-rw-r--r--roms/seabios-hppa/src/misc.c195
-rw-r--r--roms/seabios-hppa/src/mouse.c342
-rw-r--r--roms/seabios-hppa/src/optionroms.c499
-rw-r--r--roms/seabios-hppa/src/output.c602
-rw-r--r--roms/seabios-hppa/src/output.h68
-rw-r--r--roms/seabios-hppa/src/parisc/b160l.h630
-rw-r--r--roms/seabios-hppa/src/parisc/head.S319
-rw-r--r--roms/seabios-hppa/src/parisc/hppa.h375
-rw-r--r--roms/seabios-hppa/src/parisc/hppa_hardware.h49
-rw-r--r--roms/seabios-hppa/src/parisc/lasips2.c66
-rw-r--r--roms/seabios-hppa/src/parisc/lasips2.h17
-rw-r--r--roms/seabios-hppa/src/parisc/malloc.c91
-rw-r--r--roms/seabios-hppa/src/parisc/pafirmware.lds.S69
-rw-r--r--roms/seabios-hppa/src/parisc/parisc.c2002
-rw-r--r--roms/seabios-hppa/src/parisc/pdc.h694
-rw-r--r--roms/seabios-hppa/src/parisc/sti.c179
-rw-r--r--roms/seabios-hppa/src/parisc/sticore.h326
-rw-r--r--roms/seabios-hppa/src/parisc/stirom.c652
-rw-r--r--roms/seabios-hppa/src/parisc/timer.c103
-rw-r--r--roms/seabios-hppa/src/pcibios.c241
-rw-r--r--roms/seabios-hppa/src/pmm.c176
-rw-r--r--roms/seabios-hppa/src/pnpbios.c88
-rw-r--r--roms/seabios-hppa/src/post.c337
-rw-r--r--roms/seabios-hppa/src/resume.c157
-rw-r--r--roms/seabios-hppa/src/romfile.c148
-rw-r--r--roms/seabios-hppa/src/romfile.h21
-rw-r--r--roms/seabios-hppa/src/romlayout.S698
-rw-r--r--roms/seabios-hppa/src/sercon.c677
-rw-r--r--roms/seabios-hppa/src/serial.c319
-rw-r--r--roms/seabios-hppa/src/sha.h11
-rw-r--r--roms/seabios-hppa/src/sha1.c147
-rw-r--r--roms/seabios-hppa/src/sha256.c211
-rw-r--r--roms/seabios-hppa/src/sha512.c244
-rw-r--r--roms/seabios-hppa/src/stacks.c776
-rw-r--r--roms/seabios-hppa/src/stacks.h81
-rw-r--r--roms/seabios-hppa/src/std/LegacyBios.h985
-rw-r--r--roms/seabios-hppa/src/std/acpi.h334
-rw-r--r--roms/seabios-hppa/src/std/bda.h174
-rw-r--r--roms/seabios-hppa/src/std/disk.h175
-rw-r--r--roms/seabios-hppa/src/std/mptable.h77
-rw-r--r--roms/seabios-hppa/src/std/multiboot.h260
-rw-r--r--roms/seabios-hppa/src/std/optionrom.h59
-rw-r--r--roms/seabios-hppa/src/std/pirtable.h35
-rw-r--r--roms/seabios-hppa/src/std/pmm.h19
-rw-r--r--roms/seabios-hppa/src/std/pnpbios.h24
-rw-r--r--roms/seabios-hppa/src/std/smbios.h167
-rw-r--r--roms/seabios-hppa/src/std/tcg.h580
-rw-r--r--roms/seabios-hppa/src/std/vbe.h156
-rw-r--r--roms/seabios-hppa/src/std/vga.h63
-rw-r--r--roms/seabios-hppa/src/string.c276
-rw-r--r--roms/seabios-hppa/src/string.h31
-rw-r--r--roms/seabios-hppa/src/system.c357
-rw-r--r--roms/seabios-hppa/src/tcgbios.c2321
-rw-r--r--roms/seabios-hppa/src/tcgbios.h19
-rw-r--r--roms/seabios-hppa/src/types.h162
-rw-r--r--roms/seabios-hppa/src/util.h273
-rw-r--r--roms/seabios-hppa/src/version.c5
-rw-r--r--roms/seabios-hppa/src/vgahooks.c355
-rw-r--r--roms/seabios-hppa/src/x86.c23
-rw-r--r--roms/seabios-hppa/src/x86.h290
197 files changed, 57313 insertions, 0 deletions
diff --git a/roms/seabios-hppa/src/Kconfig b/roms/seabios-hppa/src/Kconfig
new file mode 100644
index 000000000..158ffb49c
--- /dev/null
+++ b/roms/seabios-hppa/src/Kconfig
@@ -0,0 +1,615 @@
+# Kconfig SeaBIOS configuration
+
+mainmenu "SeaBIOS Configuration"
+
+choice
+ prompt "Processor architecture"
+ default X86
+
+ config X86
+ bool "Intel/AMD x86"
+ help
+ Build PC BIOS.
+
+ config PARISC
+ bool "PA-RISC"
+ help
+ Build PA-RISC firmware for QEMU.
+endchoice
+
+menu "General Features"
+
+choice
+ prompt "Build Target"
+ default QEMU
+
+ config COREBOOT
+ bool "Build for coreboot" if X86
+ help
+ Configure as a coreboot payload.
+
+ config QEMU
+ bool "Build for QEMU/Xen/KVM/Bochs"
+ select QEMU_HARDWARE
+ help
+ Configure for an emulated machine (QEMU, Xen, KVM, or Bochs).
+
+ config CSM
+ bool "Build as Compatibility Support Module for EFI BIOS" if X86
+ help
+ Configure to be used by EFI firmware as Compatibility Support
+ module (CSM) to provide legacy BIOS services.
+
+endchoice
+
+ config QEMU_HARDWARE
+ bool "Support hardware found on emulators (QEMU/Xen/KVM/Bochs)" if !QEMU
+ default n
+ help
+ Support virtual hardware when the code detects it is
+ running on an emulator.
+
+ config XEN
+ depends on QEMU && !PARISC
+ bool "Support Xen HVM"
+ default y
+ help
+ Configure to be used by xen hvmloader, for a HVM guest.
+
+ config THREADS
+ bool "Parallelize hardware init"
+ depends on !PARISC
+ default y
+ help
+ Support running hardware initialization in parallel.
+
+ config RELOCATE_INIT
+ bool "Copy init code to high memory"
+ default y
+ depends on X86
+ help
+ Support relocating the one time initialization code to high memory.
+
+ config BOOTMENU
+ depends on BOOT
+ bool "Bootmenu"
+ default y
+ help
+ Support an interactive boot menu at end of post.
+ config BOOTSPLASH
+ depends on BOOTMENU && !PARISC
+ bool "Graphical boot splash screen"
+ default y
+ help
+ Support showing a graphical boot splash screen.
+ config BOOTORDER
+ depends on BOOT
+ bool "Boot ordering"
+ default y
+ help
+ Support controlling of the boot order via the fw_cfg/CBFS
+ "bootorder" file.
+ config HOST_BIOS_GEOMETRY
+ depends on BOOT
+ bool "Boot device bios geometry override"
+ default y
+ help
+ Support overriding bios (logical) geometry of boot devices via the
+ fw_cfg/CBFS "bios-geometry" file.
+
+ config COREBOOT_FLASH
+ depends on COREBOOT
+ bool "coreboot CBFS support"
+ default y
+ help
+ Support searching coreboot flash format.
+ config LZMA
+ depends on COREBOOT_FLASH
+ bool "CBFS lzma support"
+ default y
+ help
+ Support CBFS files compressed using the lzma decompression
+ algorithm.
+ config CBFS_LOCATION
+ depends on COREBOOT_FLASH
+ hex "CBFS memory end location"
+ default 0
+ help
+ Memory address of where the CBFS data ends. This should
+ be zero for normal builds. It may be a non-zero value if
+ the CBFS filesystem is at a non-standard location (eg,
+ 0xffe00000 if CBFS ends 2Meg below the end of flash).
+
+ config MULTIBOOT
+ depends on COREBOOT
+ bool "multiboot support"
+ default y
+ help
+ 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
+ depends on X86
+ help
+ Utilize an internal stack for all the legacy 16bit
+ interrupt entry points. This reduces the amount of space
+ on the caller's stack that SeaBIOS uses. This may
+ adversely impact any legacy operating systems that call
+ the BIOS in 16bit protected mode.
+
+ config MALLOC_UPPERMEMORY
+ bool "Allocate memory that needs to be in first Meg above 0xc0000"
+ default y
+ depends on X86
+ help
+ Use the "Upper Memory Block" area (0xc0000-0xf0000) for
+ internal "low memory" allocations. If this is not
+ selected, the memory is instead allocated from the
+ "9-segment" (0x90000-0xa0000).
+
+ config ROM_SIZE
+ int "ROM size (in KB)"
+ default 0
+ help
+ Set the ROM size. Say '0' here to make seabios figure the
+ needed size automatically.
+
+ Currently SeaBIOS will easily fit into 256 KB. To make it fit
+ it into 128 KB (which was big enouth for a long time) you'll
+ probably have to disable some featues such as xhci support.
+
+endmenu
+
+menu "Hardware support"
+ config ATA
+ depends on DRIVES
+ bool "ATA controllers"
+ default y
+ help
+ Support for IDE disk code.
+ config ATA_DMA
+ depends on ATA
+ bool "ATA DMA"
+ default n
+ help
+ Detect and try to use ATA bus mastering DMA controllers.
+ config ATA_PIO32
+ depends on ATA
+ bool "ATA 32bit PIO"
+ default n
+ help
+ Use 32bit PIO accesses on ATA (minor optimization on PCI transfers).
+ config AHCI
+ depends on DRIVES
+ bool "AHCI controllers"
+ default y
+ help
+ Support for AHCI disk code.
+ config SDCARD
+ depends on DRIVES && !PARISC
+ bool "SD controllers"
+ default y
+ help
+ Support for SD cards on PCI host controllers.
+ config VIRTIO_BLK
+ depends on DRIVES && QEMU_HARDWARE && !PARISC
+ bool "virtio-blk controllers"
+ default y
+ help
+ Support boot from virtio-blk storage.
+ config VIRTIO_SCSI
+ depends on DRIVES && QEMU_HARDWARE && !PARISC
+ bool "virtio-scsi controllers"
+ default y
+ help
+ Support boot from virtio-scsi storage.
+ config PVSCSI
+ depends on DRIVES && QEMU_HARDWARE && !PARISC
+ bool "PVSCSI controllers"
+ default y
+ help
+ Support boot from Paravirtualized SCSI storage. This kind of storage
+ is mainly supported by VMware ESX hypervisor. It is commonly used
+ to allow fast storage access by communicating directly with the
+ underlying hypervisor. Enabling this type of boot will allow
+ booting directly from images imported from an ESX platform,
+ without the need to use slower emulation of storage controllers
+ such as IDE.
+ config ESP_SCSI
+ depends on DRIVES && QEMU_HARDWARE
+ bool "AMD PCscsi controllers"
+ default y
+ help
+ Support boot from AMD PCscsi storage.
+ config LSI_SCSI
+ depends on DRIVES && QEMU_HARDWARE
+ bool "lsi53c895a scsi controllers"
+ default y
+ help
+ Support boot from qemu-emulated lsi53c895a scsi storage.
+ config MEGASAS
+ depends on DRIVES
+ bool "LSI MegaRAID SAS controllers"
+ default y
+ help
+ Support boot from LSI MegaRAID SAS scsi storage.
+ config MPT_SCSI
+ depends on DRIVES && QEMU_HARDWARE
+ bool "LSI MPT Fusion controllers"
+ default y
+ help
+ Support boot from LSI MPT Fusion scsi storage.
+ config FLOPPY
+ depends on DRIVES && HARDWARE_IRQ && !PARISC
+ bool "Floppy controller"
+ default y
+ help
+ Support floppy drive access.
+ config FLASH_FLOPPY
+ depends on DRIVES && !PARISC
+ bool "Floppy images from CBFS or fw_cfg"
+ default y
+ help
+ Support floppy images stored in coreboot flash or from
+ QEMU fw_cfg.
+ config NVME
+ depends on DRIVES && !PARISC
+ bool "NVMe controllers"
+ default y
+ help
+ Support for NVMe disk code.
+
+ config PS2PORT
+ depends on KEYBOARD || MOUSE
+ bool "PS/2 port"
+ default y
+ help
+ Support PS2 ports (keyboard and mouse).
+
+ config USB
+ bool "USB"
+ default y
+ help
+ Support USB devices.
+ config USB_UHCI
+ depends on USB
+ bool "USB UHCI controllers"
+ default y
+ help
+ Support USB UHCI controllers.
+ config USB_OHCI
+ depends on USB
+ bool "USB OHCI controllers"
+ default y
+ help
+ Support USB OHCI controllers.
+ config USB_EHCI
+ depends on USB
+ bool "USB EHCI controllers"
+ default y
+ help
+ Support USB EHCI controllers.
+ config USB_XHCI
+ depends on USB && !PARISC
+ bool "USB XHCI controllers"
+ default y
+ help
+ Support USB XHCI controllers.
+ config USB_MSC
+ depends on USB && DRIVES
+ bool "USB drives"
+ default y
+ help
+ Support USB BOT (bulk-only transport) disks.
+ config USB_UAS
+ depends on USB && DRIVES
+ bool "UAS drives"
+ default y
+ help
+ Support USB UAS (usb attached scsi) disks.
+ config USB_HUB
+ depends on USB
+ bool "USB hubs"
+ default y
+ help
+ Support USB hubs.
+ config USB_KEYBOARD
+ depends on USB && KEYBOARD
+ bool "USB keyboards"
+ default y
+ help
+ Support USB keyboards.
+ config USB_MOUSE
+ depends on USB && MOUSE
+ bool "USB mice"
+ default y
+ help
+ Support USB mice.
+
+ config SERIAL
+ bool "Serial port"
+ default y
+ help
+ Support serial ports. This also enables int 14 serial port calls.
+ config SERCON
+ bool "Serial console"
+ default y
+ help
+ Support redirecting vga output to the serial console.
+ config LPT
+ bool "Parallel port"
+ 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 && !PARISC
+ 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"
+ depends on X86
+ 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 && X86
+ bool "System Management Mode (SMM)"
+ default y
+ help
+ Support System Management Mode (on emulators).
+ config CALL32_SMM
+ bool
+ depends on USE_SMM
+ default y
+ config MTRR_INIT
+ depends on QEMU && X86
+ bool "Initialize MTRRs"
+ default y
+ help
+ Initialize the Memory Type Range Registers (on emulators).
+ config PMTIMER
+ bool "Support ACPI timer"
+ default y
+ depends on X86
+ help
+ 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"
+ config DRIVES
+ bool "Drive interface"
+ default y
+ help
+ Support int13 disk/floppy drive functions.
+
+ config CDROM_BOOT
+ depends on DRIVES
+ bool "DVD/CDROM booting"
+ default y
+ help
+ Support for booting from a CD. (El Torito spec support.)
+ config CDROM_EMU
+ depends on CDROM_BOOT
+ bool "DVD/CDROM boot drive emulation"
+ default y
+ help
+ Support bootable CDROMs that emulate a floppy/harddrive.
+
+ config PCIBIOS
+ bool "PCIBIOS interface"
+ default y
+ help
+ Support int 1a/b1 PCI BIOS calls.
+ config APMBIOS
+ bool "APM interface"
+ default y
+ help
+ Support int 15/53 APM BIOS calls.
+ config PNPBIOS
+ bool "PnP BIOS interface"
+ default y
+ help
+ Support PnP BIOS entry point.
+ config OPTIONROMS
+ depends on !PARISC
+ bool "Option ROMS"
+ default y
+ help
+ Support finding and running option roms during POST.
+ config PMM
+ depends on OPTIONROMS
+ bool "PMM interface"
+ default y
+ help
+ Support Post Memory Manager (PMM) entry point.
+ config BOOT
+ bool "Boot interface"
+ default y
+ help
+ Support int 19/18 system bootup support.
+ config KEYBOARD
+ bool "Keyboard interface"
+ default y
+ help
+ Support int 16 keyboard calls.
+ config KBD_CALL_INT15_4F
+ depends on KEYBOARD
+ bool "Keyboard hook interface"
+ default y
+ help
+ Support calling int155f on each keyboard event.
+ config MOUSE
+ bool "Mouse interface"
+ default y
+ help
+ Support for int15c2 mouse calls.
+
+ config S3_RESUME
+ bool "S3 resume"
+ default y
+ help
+ Support S3 resume handler.
+
+ config VGAHOOKS
+ bool "Hardware specific VGA helpers"
+ default y
+ help
+ Support int 155f BIOS callbacks specific to some Intel and
+ VIA on-board vga devices.
+
+ config DISABLE_A20
+ bool "Disable A20"
+ default n
+ help
+ Disable A20 on 16bit boot.
+
+ config WRITABLE_UPPERMEMORY
+ depends on QEMU
+ bool "Make unused UMB memory read/writeable."
+ default n
+ help
+ When selected, the "Upper Memory Block" area
+ (0x90000-0xa0000) that is not used for option roms will be
+ made writable. This allows the ram to be directly
+ 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"
+ depends on QEMU && X86
+ config PIRTABLE
+ bool "PIR table"
+ default y
+ help
+ Support generation of a PIR table in 0xf000 segment.
+ config MPTABLE
+ bool "MPTable"
+ default y
+ help
+ Support generation of MPTable.
+ config SMBIOS
+ bool "SMBIOS"
+ default y
+ help
+ Support generation of SM BIOS tables. This is also
+ sometimes called DMI.
+ config ACPI
+ bool "ACPI"
+ default y
+ help
+ Support generation of ACPI tables.
+ config ACPI_DSDT
+ bool "Include default ACPI DSDT"
+ default y
+ depends on ACPI
+ help
+ Include default DSDT ACPI table in BIOS.
+ Required for QEMU 1.3 and older.
+ This option can be disabled for QEMU 1.4 and newer
+ to save some space in the ROM file.
+ If unsure, say Y.
+ config FW_ROMFILE_LOAD
+ bool "Load BIOS tables from ROM files"
+ depends on QEMU_HARDWARE
+ default y
+ help
+ Support loading BIOS firmware tables from ROM files.
+ At the moment, only ACPI tables can be loaded in this way.
+ Required for QEMU 1.7 and newer.
+ This option can be disabled for QEMU 1.6 and older
+ to save some space in the ROM file.
+ If unsure, say Y.
+ config ACPI_PARSE
+ bool "Include ACPI DSDT parser."
+ default y
+ help
+ Support parsing ACPI DSDT for device probing.
+ Needed to find virtio-mmio devices.
+ If unsure, say Y.
+endmenu
+
+source vgasrc/Kconfig
+
+menu "Debugging"
+ config DEBUG_LEVEL
+ int "Debug level"
+ default 1
+ help
+ Control how verbose debug output is. The higher the
+ number, the more verbose SeaBIOS will be.
+
+ Set to zero to disable debugging.
+
+ config DEBUG_SERIAL
+ depends on DEBUG_LEVEL != 0
+ bool "Serial port debugging"
+ default n
+ help
+ Send debugging information to serial port.
+ config DEBUG_SERIAL_PORT
+ depends on DEBUG_SERIAL
+ hex "Serial port base address"
+ default 0x3f8
+ help
+ Base port for serial - generally 0x3f8, 0x2f8, 0x3e8, or 0x2e8.
+ config DEBUG_SERIAL_MMIO
+ depends on DEBUG_LEVEL != 0 && !DEBUG_SERIAL
+ bool "Serial port debugging via memory mapped IO"
+ default n
+ help
+ Send debugging information to serial port mapped in memory.
+ config DEBUG_SERIAL_MEM_ADDRESS
+ depends on DEBUG_SERIAL_MMIO
+ hex "Serial port memory mapped IO address"
+ help
+ On some chipsets the serial port is memory mapped, in those cases
+ provide the 32 bit address. E.g. 0xFEDC6000 for the AMD Kern
+ (a.k.a Hudson UART).
+
+ config DEBUG_IO
+ depends on QEMU_HARDWARE && DEBUG_LEVEL != 0
+ bool "Special IO port debugging"
+ default y
+ help
+ Some emulators or hypervisors provide with a way to output debug
+ information by outputing strings in a special port present in the
+ IO space.
+
+ config DEBUG_COREBOOT
+ depends on COREBOOT && DEBUG_LEVEL != 0
+ bool "coreboot cbmem debug logging"
+ default y
+ help
+ Send debugging information to the coreboot cbmem console buffer.
+ Needs CONFIG_CONSOLE_CBMEM in coreboot. You can read the log
+ after boot using 'cbmem -c'. Only 32bit code (basically every-
+ thing before booting the OS) writes to the log buffer.
+
+endmenu
diff --git a/roms/seabios-hppa/src/apm.c b/roms/seabios-hppa/src/apm.c
new file mode 100644
index 000000000..f7c2306c3
--- /dev/null
+++ b/roms/seabios-hppa/src/apm.c
@@ -0,0 +1,215 @@
+// Basic support for apmbios callbacks.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2005 Struan Bartlett
+// Copyright (C) 2004 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "bregs.h" // struct bregs
+#include "config.h" // CONFIG_*
+#include "output.h" // dprintf
+#include "stacks.h" // yield_toirq
+#include "util.h" // apm_shutdown
+#include "x86.h" // outb
+
+// APM installation check
+static void
+handle_155300(struct bregs *regs)
+{
+ regs->ah = 1; // APM major version
+ regs->al = 2; // APM minor version
+ regs->bh = 'P';
+ regs->bl = 'M';
+ // bit 0 : 16 bit interface supported
+ // bit 1 : 32 bit interface supported
+ regs->cx = 0x03;
+ set_success(regs);
+}
+
+// APM real mode interface connect
+static void
+handle_155301(struct bregs *regs)
+{
+ set_success(regs);
+}
+
+// APM 16 bit protected mode interface connect
+static void
+handle_155302(struct bregs *regs)
+{
+ extern void entry_apm16(void);
+ regs->bx = (u32)entry_apm16;
+ regs->ax = SEG_BIOS; // 16 bit code segment base
+ regs->si = 0xfff0; // 16 bit code segment size
+ regs->cx = SEG_BIOS; // data segment address
+ regs->di = 0xfff0; // data segment length
+ set_success(regs);
+}
+
+// APM 32 bit protected mode interface connect
+static void
+handle_155303(struct bregs *regs)
+{
+ extern void entry_apm32(void);
+ regs->ax = SEG_BIOS; // 32 bit code segment base
+ regs->ebx = (u32)entry_apm32;
+ regs->cx = SEG_BIOS; // 16 bit code segment base
+ // 32 bit code segment size (low 16 bits)
+ // 16 bit code segment size (high 16 bits)
+ regs->esi = 0xfff0fff0;
+ regs->dx = SEG_BIOS; // data segment address
+ regs->di = 0xfff0; // data segment length
+ set_success(regs);
+}
+
+// APM interface disconnect
+static void
+handle_155304(struct bregs *regs)
+{
+ set_success(regs);
+}
+
+// APM cpu idle
+static void
+handle_155305(struct bregs *regs)
+{
+ yield_toirq();
+ set_success(regs);
+}
+
+// APM cpu busy
+static void
+handle_155306(struct bregs *regs)
+{
+ set_success(regs);
+}
+
+void
+apm_shutdown(void)
+{
+ u16 pm1a_cnt = GET_GLOBAL(acpi_pm1a_cnt);
+ if (pm1a_cnt)
+ outw(0x2000, pm1a_cnt);
+
+ irq_disable();
+ for (;;)
+ hlt();
+}
+
+// APM Set Power State
+static void
+handle_155307(struct bregs *regs)
+{
+ if (regs->bx != 1) {
+ set_success(regs);
+ return;
+ }
+ switch (regs->cx) {
+ case 1:
+ dprintf(1, "APM standby request\n");
+ break;
+ case 2:
+ dprintf(1, "APM suspend request\n");
+ break;
+ case 3:
+ apm_shutdown();
+ break;
+ }
+ set_success(regs);
+}
+
+static void
+handle_155308(struct bregs *regs)
+{
+ set_success(regs);
+}
+
+// Get Power Status
+static void
+handle_15530a(struct bregs *regs)
+{
+ regs->bh = 0x01; // on line
+ regs->bl = 0xff; // unknown battery status
+ regs->ch = 0x80; // no system battery
+ regs->cl = 0xff; // unknown remaining time
+ regs->dx = 0xffff; // unknown remaining time
+ regs->si = 0x00; // zero battery
+ set_success(regs);
+}
+
+#define RET_ENOEVENT 0x80
+
+// Get PM Event
+static void
+handle_15530b(struct bregs *regs)
+{
+ set_code_invalid_silent(regs, RET_ENOEVENT);
+}
+
+// APM Driver Version
+static void
+handle_15530e(struct bregs *regs)
+{
+ regs->ah = 1;
+ regs->al = 2;
+ set_success(regs);
+}
+
+// APM Engage / Disengage
+static void
+handle_15530f(struct bregs *regs)
+{
+ set_success(regs);
+}
+
+// APM Get Capabilities
+static void
+handle_155310(struct bregs *regs)
+{
+ regs->bl = 0;
+ regs->cx = 0;
+ set_success(regs);
+}
+
+static void
+handle_1553XX(struct bregs *regs)
+{
+ set_unimplemented(regs);
+}
+
+void
+handle_1553(struct bregs *regs)
+{
+ if (! CONFIG_APMBIOS) {
+ set_code_invalid(regs, RET_EUNSUPPORTED);
+ return;
+ }
+
+ //debug_stub(regs);
+ switch (regs->al) {
+ case 0x00: handle_155300(regs); break;
+ case 0x01: handle_155301(regs); break;
+ case 0x02: handle_155302(regs); break;
+ case 0x03: handle_155303(regs); break;
+ case 0x04: handle_155304(regs); break;
+ case 0x05: handle_155305(regs); break;
+ case 0x06: handle_155306(regs); break;
+ case 0x07: handle_155307(regs); break;
+ case 0x08: handle_155308(regs); break;
+ case 0x0a: handle_15530a(regs); break;
+ case 0x0b: handle_15530b(regs); break;
+ case 0x0e: handle_15530e(regs); break;
+ case 0x0f: handle_15530f(regs); break;
+ case 0x10: handle_155310(regs); break;
+ default: handle_1553XX(regs); break;
+ }
+}
+
+void VISIBLE16 VISIBLE32SEG
+handle_apm(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_apm);
+ handle_1553(regs);
+}
diff --git a/roms/seabios-hppa/src/asm-offsets.c b/roms/seabios-hppa/src/asm-offsets.c
new file mode 100644
index 000000000..b98f3b5a8
--- /dev/null
+++ b/roms/seabios-hppa/src/asm-offsets.c
@@ -0,0 +1,23 @@
+// Generate assembler offsets.
+
+#include "gen-defs.h" // OFFSET
+#include "bregs.h" // struct bregs
+
+/* workaround for a warning with -Wmissing-prototypes */
+void foo(void) VISIBLE16;
+
+void foo(void)
+{
+ COMMENT("BREGS");
+ OFFSET(BREGS_es, bregs, es);
+ OFFSET(BREGS_ds, bregs, ds);
+ OFFSET(BREGS_eax, bregs, eax);
+ OFFSET(BREGS_ebx, bregs, ebx);
+ OFFSET(BREGS_ecx, bregs, ecx);
+ OFFSET(BREGS_edx, bregs, edx);
+ OFFSET(BREGS_ebp, bregs, ebp);
+ OFFSET(BREGS_esi, bregs, esi);
+ OFFSET(BREGS_edi, bregs, edi);
+ OFFSET(BREGS_flags, bregs, flags);
+ OFFSET(BREGS_code, bregs, code);
+}
diff --git a/roms/seabios-hppa/src/biosvar.h b/roms/seabios-hppa/src/biosvar.h
new file mode 100644
index 000000000..ab1d0fd4e
--- /dev/null
+++ b/roms/seabios-hppa/src/biosvar.h
@@ -0,0 +1,161 @@
+// Memory access to BIOS variables.
+//
+// Copyright (C) 2008-2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __BIOSVAR_H
+#define __BIOSVAR_H
+
+#include "autoconf.h" // CONFIG_*
+#include "config.h" // SEG_BDA
+#include "farptr.h" // GET_FARVAR
+#include "memmap.h" // SYMBOL
+#include "std/bda.h" // struct bios_data_area_s
+
+
+/****************************************************************
+ * Interrupt vector table
+ ****************************************************************/
+
+#if CONFIG_X86
+#define GET_IVT(vector) \
+ GET_FARVAR(SEG_IVT, ((struct rmode_IVT *)0)->ivec[vector])
+#define SET_IVT(vector, segoff) \
+ SET_FARVAR(SEG_IVT, ((struct rmode_IVT *)0)->ivec[vector], segoff)
+
+#define FUNC16(func) ({ \
+ ASSERT32FLAT(); \
+ extern void func (void); \
+ SEGOFF(SEG_BIOS, (u32)func - BUILD_BIOS_ADDR); \
+ })
+#elif CONFIG_PARISC
+extern struct segoff_s ivt_table[256];
+
+#define GET_IVT(vector) ivt_table[vector]
+#define SET_IVT(vector, segoff) ivt_table[vector] = (segoff)
+
+#define FUNC16(func) ({ SEGOFF(0, 0); })
+#endif
+
+
+/****************************************************************
+ * Bios Data Area (BDA)
+ ****************************************************************/
+
+static inline struct bios_data_area_s *
+get_bda_ptr(void)
+{
+#if CONFIG_X86
+ return MAKE_FLATPTR(SEG_BDA, 0);
+#elif CONFIG_PARISC
+ extern struct bios_data_area_s bios_data_area;
+ return &bios_data_area;
+#endif
+}
+
+// Accessor functions
+#if CONFIG_X86
+#define GET_BDA(var) \
+ GET_FARVAR(SEG_BDA, ((struct bios_data_area_s *)0)->var)
+#define SET_BDA(var, val) \
+ SET_FARVAR(SEG_BDA, ((struct bios_data_area_s *)0)->var, (val))
+#elif CONFIG_PARISC
+#define GET_BDA(var) get_bda_ptr()->var
+#define SET_BDA(var, val) get_bda_ptr()->var = (val)
+#endif
+
+// Helper function to set the bits of the equipment_list_flags variable.
+static inline void set_equipment_flags(u16 clear, u16 set) {
+ u16 eqf = GET_BDA(equipment_list_flags);
+ SET_BDA(equipment_list_flags, (eqf & ~clear) | set);
+}
+
+
+/****************************************************************
+ * Extended Bios Data Area (EBDA)
+ ****************************************************************/
+
+// The initial size and location of EBDA
+#define EBDA_SIZE_START \
+ DIV_ROUND_UP(sizeof(struct extended_bios_data_area_s), 1024)
+#define EBDA_SEGMENT_START \
+ FLATPTR_TO_SEG(BUILD_LOWRAM_END - EBDA_SIZE_START*1024)
+
+// Accessor functions
+static inline u16 get_ebda_seg(void) {
+ return GET_BDA(ebda_seg);
+}
+static inline struct extended_bios_data_area_s *
+get_ebda_ptr(void)
+{
+ ASSERT32FLAT();
+ return MAKE_FLATPTR(get_ebda_seg(), 0);
+}
+#define GET_EBDA(eseg, var) \
+ GET_FARVAR(eseg, ((struct extended_bios_data_area_s *)0)->var)
+#define SET_EBDA(eseg, var, val) \
+ SET_FARVAR(eseg, ((struct extended_bios_data_area_s *)0)->var, (val))
+
+
+/****************************************************************
+ * Global variables
+ ****************************************************************/
+
+#if MODE16 == 0 && MODESEGMENT == 1
+// In 32bit segmented mode %cs may not be readable and the code may be
+// relocated. The entry code sets up %gs with a readable segment and
+// the code offset can be determined by get_global_offset().
+#define GLOBAL_SEGREG GS
+static inline u32 __attribute_const get_global_offset(void) {
+ u32 ret;
+ asm(" calll 1f\n"
+ "1:popl %0\n"
+ " subl $1b, %0"
+ : "=r"(ret));
+ return ret;
+}
+#else
+#define GLOBAL_SEGREG CS
+static inline u32 __attribute_const get_global_offset(void) {
+ return 0;
+}
+#endif
+static inline u16 get_global_seg(void) {
+ return GET_SEG(GLOBAL_SEGREG);
+}
+#if CONFIG_X86
+#define GET_GLOBAL(var) \
+ GET_VAR(GLOBAL_SEGREG, *(typeof(&(var)))((void*)&(var) \
+ + get_global_offset()))
+#elif CONFIG_PARISC
+#define GET_GLOBAL(var) (var)
+#endif
+
+#if MODESEGMENT
+#define GLOBALFLAT2GLOBAL(var) ((typeof(var))((void*)(var) - BUILD_BIOS_ADDR))
+#else
+#define GLOBALFLAT2GLOBAL(var) (var)
+#endif
+// Access a "flat" pointer known to point to the f-segment.
+#define GET_GLOBALFLAT(var) GET_GLOBAL(*GLOBALFLAT2GLOBAL(&(var)))
+
+
+/****************************************************************
+ * "Low" memory variables
+ ****************************************************************/
+
+#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) - SYMBOL(zonelow_base)))
+#else
+#define GET_LOW(var) (var)
+#define SET_LOW(var, val) do { (var) = (val); } while (0)
+#define LOWFLAT2LOW(var) (var)
+#endif
+#define GET_LOWFLAT(var) GET_LOW(*LOWFLAT2LOW(&(var)))
+#define SET_LOWFLAT(var, val) SET_LOW(*LOWFLAT2LOW(&(var)), (val))
+
+#endif // __BIOSVAR_H
diff --git a/roms/seabios-hppa/src/block.c b/roms/seabios-hppa/src/block.c
new file mode 100644
index 000000000..1b8515481
--- /dev/null
+++ b/roms/seabios-hppa/src/block.c
@@ -0,0 +1,645 @@
+// Disk setup and access
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "block.h" // process_op
+#include "hw/ata.h" // process_ata_op
+#include "hw/ahci.h" // process_ahci_op
+#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/mpt-scsi.h" // mpt_scsi_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 "hw/nvme.h" // nvme_process_op
+#include "malloc.h" // malloc_low
+#include "output.h" // dprintf
+#include "stacks.h" // call32
+#include "std/disk.h" // struct dpte_s
+#include "string.h" // checksum
+#include "util.h" // process_floppy_op
+
+u8 FloppyCount VARFSEG;
+u8 CDCount;
+struct drive_s *IDMap[3][BUILD_MAX_EXTDRIVE] VARFSEG;
+u8 *bounce_buf_fl VARFSEG;
+
+struct drive_s *
+getDrive(u8 exttype, u8 extdriveoffset)
+{
+ if (extdriveoffset >= ARRAY_SIZE(IDMap[0]))
+ return NULL;
+ return GET_GLOBAL(IDMap[exttype][extdriveoffset]);
+}
+
+int getDriveId(u8 exttype, struct drive_s *drive)
+{
+ ASSERT32FLAT();
+ int i;
+ for (i = 0; i < ARRAY_SIZE(IDMap[0]); i++)
+ if (getDrive(exttype, i) == drive)
+ return i;
+ return -1;
+}
+
+int create_bounce_buf(void)
+{
+ if (bounce_buf_fl)
+ return 0;
+
+ u8 *buf = malloc_low(CDROM_SECTOR_SIZE);
+ if (!buf) {
+ warn_noalloc();
+ return -1;
+ }
+ bounce_buf_fl = buf;
+ return 0;
+}
+
+/****************************************************************
+ * Disk geometry translation
+ ****************************************************************/
+
+static int
+host_lchs_supplied(struct drive_s *drive)
+{
+ return (drive->lchs.head <= 255 &&
+ drive->lchs.sector > 0 && drive->lchs.sector <= 63);
+}
+
+static u8
+get_translation(struct drive_s *drive)
+{
+ if (host_lchs_supplied(drive))
+ return TRANSLATION_HOST;
+ u8 type = drive->type;
+ if (CONFIG_QEMU && type == DTYPE_ATA) {
+ // Emulators pass in the translation info via nvram.
+ u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + drive->cntl_id/4);
+ translation >>= 2 * (drive->cntl_id % 4);
+ translation &= 0x03;
+ return translation;
+ }
+
+ // Otherwise use a heuristic to determine translation type.
+ u16 heads = drive->pchs.head;
+ u16 cylinders = drive->pchs.cylinder;
+ u16 spt = drive->pchs.sector;
+ u64 sectors = drive->sectors;
+ u64 psectors = (u64)heads * cylinders * spt;
+ if (!heads || !cylinders || !spt || psectors > sectors)
+ // pchs doesn't look valid - use LBA.
+ return TRANSLATION_LBA;
+
+ if (cylinders <= 1024 && heads <= 16 && spt <= 63)
+ return TRANSLATION_NONE;
+ if (cylinders * heads <= 131072)
+ return TRANSLATION_LARGE;
+ return TRANSLATION_LBA;
+}
+
+static void
+setup_translation(struct drive_s *drive)
+{
+ u8 translation = get_translation(drive);
+ drive->translation = translation;
+
+ u16 heads = drive->pchs.head ;
+ u16 cylinders = drive->pchs.cylinder;
+ u16 spt = drive->pchs.sector;
+ u64 sectors = drive->sectors;
+ const char *desc = NULL;
+
+ switch (translation) {
+ default:
+ case TRANSLATION_NONE:
+ desc = "none";
+ break;
+ case TRANSLATION_LBA:
+ desc = "lba";
+ spt = 63;
+ if (sectors > 63*255*1024) {
+ heads = 255;
+ cylinders = 1024;
+ break;
+ }
+ u32 sect = (u32)sectors / 63;
+ heads = sect / 1024;
+ if (heads>128)
+ heads = 255;
+ else if (heads>64)
+ heads = 128;
+ else if (heads>32)
+ heads = 64;
+ else if (heads>16)
+ heads = 32;
+ else
+ heads = 16;
+ cylinders = sect / heads;
+ break;
+ case TRANSLATION_RECHS:
+ desc = "r-echs";
+ // Take care not to overflow
+ if (heads==16) {
+ if (cylinders>61439)
+ cylinders=61439;
+ heads=15;
+ cylinders = (u16)((u32)(cylinders)*16/15);
+ }
+ // then go through the large bitshift process
+ case TRANSLATION_LARGE:
+ if (translation == TRANSLATION_LARGE)
+ desc = "large";
+ while (cylinders > 1024) {
+ cylinders >>= 1;
+ heads <<= 1;
+
+ // If we max out the head count
+ if (heads > 127)
+ break;
+ }
+ break;
+ case TRANSLATION_HOST:
+ desc = "host-supplied";
+ cylinders = drive->lchs.cylinder;
+ heads = drive->lchs.head;
+ spt = drive->lchs.sector;
+ break;
+ }
+ // clip to 1024 cylinders in lchs
+ if (cylinders > 1024)
+ cylinders = 1024;
+ dprintf(1, "drive %p: PCHS=%u/%d/%d translation=%s LCHS=%d/%d/%d s=%u\n"
+ , drive
+ , drive->pchs.cylinder, drive->pchs.head, drive->pchs.sector
+ , desc
+ , cylinders, heads, spt
+ , (u32)sectors);
+
+ drive->lchs.head = heads;
+ drive->lchs.cylinder = cylinders;
+ drive->lchs.sector = spt;
+}
+
+
+/****************************************************************
+ * Drive mapping
+ ****************************************************************/
+
+// Fill in Fixed Disk Parameter Table (located in ebda).
+static void
+fill_fdpt(struct drive_s *drive, int hdid)
+{
+ if (hdid > 1)
+ return;
+
+ u16 nlc = drive->lchs.cylinder;
+ u16 nlh = drive->lchs.head;
+ u16 nls = drive->lchs.sector;
+
+ u16 npc = drive->pchs.cylinder;
+ u16 nph = drive->pchs.head;
+ u16 nps = drive->pchs.sector;
+
+ struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[hdid];
+ fdpt->precompensation = 0xffff;
+ fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3);
+ fdpt->landing_zone = npc;
+ fdpt->cylinders = nlc;
+ fdpt->heads = nlh;
+ fdpt->sectors = nls;
+
+ if (nlc != npc || nlh != nph || nls != nps) {
+ // Logical mapping present - use extended structure.
+
+ // complies with Phoenix style Translated Fixed Disk Parameter
+ // Table (FDPT)
+ fdpt->phys_cylinders = npc;
+ fdpt->phys_heads = nph;
+ fdpt->phys_sectors = nps;
+ fdpt->a0h_signature = 0xa0;
+
+ // Checksum structure.
+ fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
+ }
+
+ if (hdid == 0)
+ SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof(
+ struct extended_bios_data_area_s, fdpt[0])));
+ else
+ SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof(
+ struct extended_bios_data_area_s, fdpt[1])));
+}
+
+// Find spot to add a drive
+static void
+add_drive(struct drive_s **idmap, u8 *count, struct drive_s *drive)
+{
+ if (*count >= ARRAY_SIZE(IDMap[0])) {
+ warn_noalloc();
+ return;
+ }
+ idmap[*count] = drive;
+ *count = *count + 1;
+}
+
+// Map a hard drive
+void
+map_hd_drive(struct drive_s *drive)
+{
+ ASSERT32FLAT();
+ struct bios_data_area_s *bda = get_bda_ptr();
+ int hdid = bda->hdcount;
+ dprintf(3, "Mapping hd drive %p to %d\n", drive, hdid);
+ add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive);
+
+ // Setup disk geometry translation.
+ setup_translation(drive);
+
+ // Fill "fdpt" structure.
+ fill_fdpt(drive, hdid);
+}
+
+// Map a cd
+void
+map_cd_drive(struct drive_s *drive)
+{
+ ASSERT32FLAT();
+ dprintf(3, "Mapping cd drive %p\n", drive);
+ add_drive(IDMap[EXTTYPE_CD], &CDCount, drive);
+}
+
+// Map a floppy
+void
+map_floppy_drive(struct drive_s *drive)
+{
+ ASSERT32FLAT();
+ dprintf(3, "Mapping floppy drive %p\n", drive);
+ add_drive(IDMap[EXTTYPE_FLOPPY], &FloppyCount, drive);
+
+ // Update equipment word bits for floppy
+ if (FloppyCount == 1) {
+ // 1 drive, ready for boot
+ set_equipment_flags(0x41, 0x01);
+ SET_BDA(floppy_harddisk_info, 0x07);
+ } else if (FloppyCount >= 2) {
+ // 2 drives, ready for boot
+ set_equipment_flags(0x41, 0x41);
+ SET_BDA(floppy_harddisk_info, 0x77);
+ }
+}
+
+
+/****************************************************************
+ * 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(struct segoff_s edd, struct drive_s *drive_fl
+ , 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;
+
+ // Buffer is too small
+ if (size < 26)
+ return DISK_RET_EPARAM;
+
+ // EDD 1.x
+
+ u8 type = GET_FLATPTR(drive_fl->type);
+ u16 npc = GET_FLATPTR(drive_fl->pchs.cylinder);
+ u16 nph = GET_FLATPTR(drive_fl->pchs.head);
+ u16 nps = GET_FLATPTR(drive_fl->pchs.sector);
+ u64 lba = GET_FLATPTR(drive_fl->sectors);
+ u16 blksize = GET_FLATPTR(drive_fl->blksize);
+
+ dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n"
+ , size, type, npc, nph, nps, (u32)lba, blksize);
+
+ SET_FARVAR(seg, param_far->size, 26);
+ if (lba == (u64)-1) {
+ // 0x74 = removable, media change, lockable, max values
+ SET_FARVAR(seg, param_far->infos, 0x74);
+ SET_FARVAR(seg, param_far->cylinders, 0xffffffff);
+ SET_FARVAR(seg, param_far->heads, 0xffffffff);
+ SET_FARVAR(seg, param_far->spt, 0xffffffff);
+ } else {
+ if (lba > (u64)nps*nph*0x3fff) {
+ SET_FARVAR(seg, param_far->infos, 0x00); // geometry is invalid
+ SET_FARVAR(seg, param_far->cylinders, 0x3fff);
+ } else {
+ SET_FARVAR(seg, param_far->infos, 0x02); // geometry is valid
+ SET_FARVAR(seg, param_far->cylinders, (u32)npc);
+ }
+ SET_FARVAR(seg, param_far->heads, (u32)nph);
+ SET_FARVAR(seg, param_far->spt, (u32)nps);
+ }
+ SET_FARVAR(seg, param_far->sector_count, lba);
+ SET_FARVAR(seg, param_far->blksize, blksize);
+
+ if (size < 30 || !dpte_so)
+ return DISK_RET_SUCCESS;
+
+ // EDD 2.x
+
+ SET_FARVAR(seg, param_far->size, 30);
+ SET_FARVAR(seg, param_far->dpte.segoff, dpte_so);
+
+ if (size < 66 || !bus_iface)
+ return DISK_RET_SUCCESS;
+
+ // EDD 3.x
+ SET_FARVAR(seg, param_far->key, 0xbedd);
+ SET_FARVAR(seg, param_far->dpi_length, t13 ? 44 : 36);
+ SET_FARVAR(seg, param_far->reserved1, 0);
+ SET_FARVAR(seg, param_far->reserved2, 0);
+
+ 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);
+
+ SET_FARVAR(seg, param_far->t13.checksum
+ , -checksum_far(seg, (void*)param_far+30, 43));
+ } else {
+ SET_FARVAR(seg, param_far->phoenix.device_path, device_path);
+
+ SET_FARVAR(seg, param_far->phoenix.checksum
+ , -checksum_far(seg, (void*)param_far+30, 35));
+ }
+
+ 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(struct segoff_s edd, struct drive_s *drive_gf)
+{
+ if (!CONFIG_ATA)
+ return DISK_RET_EPARAM;
+
+ // Fill in dpte
+ struct atadrive_s *adrive_gf = container_of(
+ drive_gf, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ u8 slave = GET_GLOBALFLAT(adrive_gf->slave);
+ u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+ u8 irq = GET_GLOBALFLAT(chan_gf->irq);
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ int bdf = GET_GLOBALFLAT(chan_gf->pci_bdf);
+ u8 channel = GET_GLOBALFLAT(chan_gf->chanid);
+
+ u16 options = 0;
+ if (GET_GLOBALFLAT(drive_gf->type) == DTYPE_ATA) {
+ u8 translation = GET_GLOBALFLAT(drive_gf->translation);
+ if ((translation != TRANSLATION_NONE) &&
+ (translation != TRANSLATION_HOST)) {
+ options |= 1<<3; // CHS translation
+ if (translation == TRANSLATION_LBA)
+ options |= 1<<9;
+ if (translation == TRANSLATION_RECHS)
+ options |= 3<<9;
+ }
+ } else {
+ // ATAPI
+ options |= 1<<5; // removable device
+ options |= 1<<6; // atapi device
+ }
+ options |= 1<<4; // lba translation
+ if (CONFIG_ATA_PIO32)
+ options |= 1<<7;
+
+ SET_LOW(DefaultDPTE.iobase1, iobase1);
+ SET_LOW(DefaultDPTE.iobase2, iobase2 + ATA_CB_DC);
+ SET_LOW(DefaultDPTE.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
+ | ATA_CB_DH_LBA));
+ SET_LOW(DefaultDPTE.unused, 0xcb);
+ SET_LOW(DefaultDPTE.irq, irq);
+ SET_LOW(DefaultDPTE.blkcount, 1);
+ SET_LOW(DefaultDPTE.dma, 0);
+ SET_LOW(DefaultDPTE.pio, 0);
+ SET_LOW(DefaultDPTE.options, options);
+ SET_LOW(DefaultDPTE.reserved, 0);
+ SET_LOW(DefaultDPTE.revision, 0x11);
+
+ 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(
+ 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(struct segoff_s edd, struct drive_s *drive_fl)
+{
+ switch (GET_FLATPTR(drive_fl->type)) {
+ case DTYPE_ATA:
+ case DTYPE_ATA_ATAPI:
+ return fill_ata_edd(edd, drive_fl);
+ case DTYPE_VIRTIO_BLK:
+ case DTYPE_VIRTIO_SCSI:
+ return fill_generic_edd(
+ edd, drive_fl, 0xffffffff, EDD_PCI | EDD_SCSI
+ , edd_pci_path(GET_FLATPTR(drive_fl->cntl_id), 0), 0);
+ default:
+ return fill_generic_edd(edd, drive_fl, 0, 0, 0, 0);
+ }
+}
+
+
+/****************************************************************
+ * Disk driver dispatch
+ ****************************************************************/
+
+void
+block_setup(void)
+{
+ floppy_setup();
+ ata_setup();
+ ahci_setup();
+ sdcard_setup();
+ ramdisk_setup();
+ virtio_blk_setup();
+ virtio_scsi_setup();
+ lsi_scsi_setup();
+ esp_scsi_setup();
+ megasas_setup();
+ pvscsi_setup();
+ mpt_scsi_setup();
+ nvme_setup();
+}
+
+// Fallback handler for command requests not implemented by drivers
+int
+default_process_op(struct disk_op_s *op)
+{
+ switch (op->command) {
+ case CMD_FORMAT:
+ 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 DISK_RET_EPARAM;
+ }
+}
+
+// Command dispatch for disk drivers that run in both 16bit and 32bit mode
+static int
+process_op_both(struct disk_op_s *op)
+{
+ switch (GET_FLATPTR(op->drive_fl->type)) {
+#if CONFIG_PARISC
+ case DTYPE_ATA:
+ return ata_process_op(op);
+#endif
+ case DTYPE_ATA_ATAPI:
+ return ata_atapi_process_op(op);
+ case DTYPE_USB:
+ return usb_process_op(op);
+ case DTYPE_UAS:
+ 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:
+ return megasas_process_op(op);
+ case DTYPE_MPT_SCSI:
+ return mpt_scsi_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_fl->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:
+ return uas_process_op(op);
+ case DTYPE_VIRTIO_SCSI:
+ return virtio_scsi_process_op(op);
+ case DTYPE_PVSCSI:
+ return pvscsi_process_op(op);
+ case DTYPE_NVME:
+ return nvme_process_op(op);
+ default:
+ 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_FLATPTR(op->drive_fl->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)
+{
+ dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n"
+ , op->drive_fl, (u32)op->lba, op->buf_fl
+ , op->count, op->command);
+
+ int ret, origcount = op->count;
+ /* Only x86 arch has problems with large reads/writes greater than 64kb */
+ if (CONFIG_X86 &&
+ (origcount * GET_FLATPTR(op->drive_fl->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;
+ return ret;
+}
diff --git a/roms/seabios-hppa/src/block.h b/roms/seabios-hppa/src/block.h
new file mode 100644
index 000000000..5cd2e5db0
--- /dev/null
+++ b/roms/seabios-hppa/src/block.h
@@ -0,0 +1,124 @@
+#ifndef __BLOCK_H
+#define __BLOCK_H
+
+#include "types.h" // u32
+
+
+/****************************************************************
+ * Disk command request
+ ****************************************************************/
+
+struct disk_op_s {
+ void *buf_fl;
+ struct drive_s *drive_fl;
+ u8 command;
+ u16 count;
+ union {
+ // Commands: READ, WRITE, VERIFY, SEEK, FORMAT
+ u64 lba;
+ // Commands: SCSI
+ struct {
+ u16 blocksize;
+ void *cdbcmd;
+ };
+ };
+};
+
+#define CMD_RESET 0x00
+#define CMD_READ 0x02
+#define CMD_WRITE 0x03
+#define CMD_VERIFY 0x04
+#define CMD_FORMAT 0x05
+#define CMD_SEEK 0x07
+#define CMD_ISREADY 0x10
+#define CMD_SCSI 0x20
+
+
+/****************************************************************
+ * Global storage
+ ****************************************************************/
+
+struct chs_s {
+ u16 head;
+ u16 cylinder;
+ u16 sector;
+ u16 pad;
+};
+
+struct drive_s {
+ u8 type; // Driver type (DTYPE_*)
+ u8 floppy_type; // Type of floppy (only for floppy drives).
+ struct chs_s lchs; // Logical CHS
+ u64 sectors; // Total sectors count
+ u32 cntl_id; // Unique id for a given driver type.
+ u8 removable; // Is media removable (currently unused)
+
+ // Info for EDD calls
+ u8 translation; // type of translation
+ u16 blksize; // block size
+ struct chs_s pchs; // Physical CHS
+
+ u8 target, lun; // SCSI target and LUN
+};
+
+#define DISK_SECTOR_SIZE 512
+#define CDROM_SECTOR_SIZE 2048
+
+#define DTYPE_NONE 0x00
+#define DTYPE_FLOPPY 0x10
+#define DTYPE_ATA 0x20
+#define DTYPE_ATA_ATAPI 0x21
+#define DTYPE_RAMDISK 0x30
+#define DTYPE_CDEMU 0x40
+#define DTYPE_AHCI 0x50
+#define DTYPE_AHCI_ATAPI 0x51
+#define DTYPE_VIRTIO_SCSI 0x60
+#define DTYPE_VIRTIO_BLK 0x61
+#define DTYPE_USB 0x70
+#define DTYPE_USB_32 0x71
+#define DTYPE_UAS 0x72
+#define DTYPE_UAS_32 0x73
+#define DTYPE_LSI_SCSI 0x80
+#define DTYPE_ESP_SCSI 0x81
+#define DTYPE_MEGASAS 0x82
+#define DTYPE_PVSCSI 0x83
+#define DTYPE_MPT_SCSI 0x84
+#define DTYPE_SDCARD 0x90
+#define DTYPE_NVME 0x91
+
+#define MAXDESCSIZE 80
+
+#define TRANSLATION_NONE 0
+#define TRANSLATION_LBA 1
+#define TRANSLATION_LARGE 2
+#define TRANSLATION_RECHS 3
+#define TRANSLATION_HOST 4
+
+#define EXTTYPE_FLOPPY 0
+#define EXTTYPE_HD 1
+#define EXTTYPE_CD 2
+
+#define EXTSTART_HD 0x80
+#define EXTSTART_CD 0xE0
+
+
+/****************************************************************
+ * Function defs
+ ****************************************************************/
+
+// block.c
+extern u8 FloppyCount, CDCount;
+extern u8 *bounce_buf_fl;
+struct drive_s *getDrive(u8 exttype, u8 extdriveoffset);
+int getDriveId(u8 exttype, struct drive_s *drive);
+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(struct segoff_s edd, struct drive_s *drive_fl);
+void block_setup(void);
+int default_process_op(struct disk_op_s *op);
+int process_op(struct disk_op_s *op);
+int create_bounce_buf(void);
+
+#endif // block.h
diff --git a/roms/seabios-hppa/src/bmp.c b/roms/seabios-hppa/src/bmp.c
new file mode 100644
index 000000000..fecc29530
--- /dev/null
+++ b/roms/seabios-hppa/src/bmp.c
@@ -0,0 +1,116 @@
+/*
+* Basic BMP data process and Raw picture data handle functions.
+* Could be used to adjust pixel data format, get information, etc.
+*
+* Copyright (C) 2011 Wayne Xia <xiawenc@cn.ibm.com>
+*
+* This work is licensed under the terms of the GNU LGPLv3.
+*/
+#include "malloc.h" // malloc_tmphigh
+#include "string.h" // memcpy
+#include "util.h" // struct bmp_decdata
+
+struct bmp_decdata {
+ struct tagRGBQUAD *quadp;
+ unsigned char *datap;
+ int width;
+ int height;
+ int bpp;
+};
+
+#define bmp_load4byte(addr) (*(u32 *)(addr))
+#define bmp_load2byte(addr) (*(u16 *)(addr))
+
+typedef struct tagBITMAPFILEHEADER {
+ u8 bfType[2];
+ u8 bfSize[4];
+ u8 bfReserved1[2];
+ u8 bfReserved2[2];
+ u8 bfOffBits[4];
+} BITMAPFILEHEADER, tagBITMAPFILEHEADER;
+
+typedef struct tagBITMAPINFOHEADER {
+ u8 biSize[4];
+ u8 biWidth[4];
+ u8 biHeight[4];
+ u8 biPlanes[2];
+ u8 biBitCount[2];
+ u8 biCompression[4];
+ u8 biSizeImage[4];
+ u8 biXPelsPerMeter[4];
+ u8 biYPelsPerMeter[4];
+ u8 biClrUsed[4];
+ u8 biClrImportant[4];
+} BITMAPINFOHEADER, tagBITMAPINFOHEADER;
+
+typedef struct tagRGBQUAD {
+ u8 rgbBlue;
+ u8 rgbGreen;
+ u8 rgbRed;
+ u8 rgbReserved;
+} RGBQUAD, tagRGBQUAD;
+
+/* flat picture data adjusting function
+* description:
+* switch the vertical line sequence
+* arrange horizontal pixel data, add extra space in the dest buffer
+* for every line
+*/
+static void raw_data_format_adjust(u8 *src, u8 *dest, int width,
+ int height, int bytes_per_line_src, int bytes_per_line_dest)
+{
+ int i;
+ for (i = 0 ; i < height ; i++) {
+ memcpy(dest + i * bytes_per_line_dest,
+ src + (height - 1 - i) * bytes_per_line_src, bytes_per_line_src);
+ }
+}
+
+/* allocate decdata struct */
+struct bmp_decdata *bmp_alloc(void)
+{
+ struct bmp_decdata *bmp = malloc_tmphigh(sizeof(*bmp));
+ return bmp;
+}
+
+/* extract information from bmp file data */
+int bmp_decode(struct bmp_decdata *bmp, unsigned char *data, int data_size)
+{
+ if (data_size < 54)
+ return 1;
+
+ u16 bmp_filehead = bmp_load2byte(data + 0);
+ if (bmp_filehead != 0x4d42)
+ return 2;
+ u32 bmp_recordsize = bmp_load4byte(data + 2);
+ if (bmp_recordsize != data_size)
+ return 3;
+ u32 bmp_dataoffset = bmp_load4byte(data + 10);
+ bmp->datap = (unsigned char *)data + bmp_dataoffset;
+ bmp->width = bmp_load4byte(data + 18);
+ bmp->height = bmp_load4byte(data + 22);
+ bmp->bpp = bmp_load2byte(data + 28);
+ return 0;
+}
+
+/* get bmp properties */
+void bmp_get_info(struct bmp_decdata *bmp, int *width, int *height, int *bpp)
+{
+ *width = bmp->width;
+ *height = bmp->height;
+ *bpp = bmp->bpp;
+}
+
+/* flush flat picture data to *pc */
+int bmp_show(struct bmp_decdata *bmp, unsigned char *pic, int width,
+ int height, int depth, int bytes_per_line_dest)
+{
+ if (bmp->datap == pic)
+ return 0;
+ if ((depth == bmp->bpp) && (bmp->bpp%8 == 0)) {
+ raw_data_format_adjust(bmp->datap, pic, width, height,
+ (bmp->bpp/8)*width, bytes_per_line_dest);
+ return 0;
+ }
+ return 1;
+}
diff --git a/roms/seabios-hppa/src/boot.c b/roms/seabios-hppa/src/boot.c
new file mode 100644
index 000000000..31f63ea86
--- /dev/null
+++ b/roms/seabios-hppa/src/boot.c
@@ -0,0 +1,1104 @@
+// Code to load disk image and start system boot.
+//
+// Copyright (C) 2008-2013 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "block.h" // struct drive_s
+#include "bregs.h" // struct bregs
+#include "config.h" // CONFIG_*
+#include "fw/paravirt.h" // qemu_cfg_show_boot_menu
+#include "hw/pci.h" // pci_bdf_to_*
+#include "hw/pcidevice.h" // struct pci_device
+#include "hw/rtc.h" // rtc_read
+#include "hw/usb.h" // struct usbdevice_s
+#include "list.h" // hlist_node
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "romfile.h" // romfile_loadint
+#include "std/disk.h" // struct mbr_s
+#include "string.h" // memset
+#include "util.h" // irqtimer_calc
+#include "tcgbios.h" // tpm_*
+
+/****************************************************************
+ * Helper search functions
+ ****************************************************************/
+
+// See if 'str' starts with 'glob' - if glob contains an '*' character
+// it will match any number of characters in str that aren't a '/' or
+// the next glob character.
+static char *
+glob_prefix(const char *glob, const char *str)
+{
+ for (;;) {
+ if (!*glob && (!*str || *str == '/'))
+ return (char*)str;
+ if (*glob == '*') {
+ if (!*str || *str == '/' || *str == glob[1])
+ glob++;
+ else
+ str++;
+ continue;
+ }
+ if (*glob != *str)
+ return NULL;
+ glob++;
+ str++;
+ }
+}
+
+#if CONFIG_PARISC
+#define FW_PCI_DOMAIN "/dino-pcihost"
+#else
+#define FW_PCI_DOMAIN "/pci@i0cf8"
+#endif
+
+static char *
+build_pci_path(char *buf, int max, const char *devname, struct pci_device *pci)
+{
+ // Build the string path of a bdf - for example: /pci@i0cf8/isa@1,2
+ char *p = buf;
+ if (pci->parent) {
+ p = build_pci_path(p, max, "pci-bridge", pci->parent);
+ } else {
+ 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);
+ p += snprintf(p, buf+max-p, "/%s@%x", devname, dev);
+ if (fn)
+ p += snprintf(p, buf+max-p, ",%x", fn);
+ return p;
+}
+
+static char *
+build_scsi_path(char *buf, int max,
+ struct pci_device *pci, int target, int lun)
+{
+ // Build the string path of a scsi drive - for example:
+ // /pci@i0cf8/scsi@5/channel@0/disk@1,0
+ char *p;
+ p = build_pci_path(buf, max, "*", pci);
+ p += snprintf(p, buf+max-p, "/*@0/*@%x,%x", target, lun);
+ return p;
+}
+
+static char *
+build_ata_path(char *buf, int max,
+ struct pci_device *pci, int chanid, int slave)
+{
+ // Build the string path of an ata drive - for example:
+ // /pci@i0cf8/ide@1,1/drive@1/disk@0
+ char *p;
+ p = build_pci_path(buf, max, "*", pci);
+ p += snprintf(p, buf+max-p, "/drive@%x/disk@%x", chanid, slave);
+ return p;
+}
+
+
+/****************************************************************
+ * Boot device logical geometry
+ ****************************************************************/
+
+typedef struct BootDeviceLCHS {
+ char *name;
+ u32 lcyls;
+ u32 lheads;
+ u32 lsecs;
+} BootDeviceLCHS;
+
+static BootDeviceLCHS *BiosGeometry VARVERIFY32INIT;
+static int BiosGeometryCount;
+
+static char *
+parse_u32(char *cur, u32 *n)
+{
+ u32 m = 0;
+ if (cur) {
+ while ('0' <= *cur && *cur <= '9') {
+ m = 10 * m + (*cur - '0');
+ cur++;
+ }
+ if (*cur != '\0')
+ cur++;
+ }
+ *n = m;
+ return cur;
+}
+
+static void
+loadBiosGeometry(void)
+{
+ if (!CONFIG_HOST_BIOS_GEOMETRY)
+ return;
+ char *f = romfile_loadfile("bios-geometry", NULL);
+ if (!f)
+ return;
+
+ int i = 0;
+ BiosGeometryCount = 1;
+ while (f[i]) {
+ if (f[i] == '\n')
+ BiosGeometryCount++;
+ i++;
+ }
+ BiosGeometry = malloc_tmphigh(BiosGeometryCount * sizeof(BootDeviceLCHS));
+ if (!BiosGeometry) {
+ warn_noalloc();
+ free(f);
+ BiosGeometryCount = 0;
+ return;
+ }
+
+ dprintf(1, "bios geometry:\n");
+ i = 0;
+ do {
+ BootDeviceLCHS *d = &BiosGeometry[i];
+ d->name = f;
+ f = strchr(f, '\n');
+ if (f)
+ *(f++) = '\0';
+ char *chs_values = strchr(d->name, ' ');
+ if (chs_values)
+ *(chs_values++) = '\0';
+ chs_values = parse_u32(chs_values, &d->lcyls);
+ chs_values = parse_u32(chs_values, &d->lheads);
+ chs_values = parse_u32(chs_values, &d->lsecs);
+ dprintf(1, "%s: (%u, %u, %u)\n",
+ d->name, d->lcyls, d->lheads, d->lsecs);
+ i++;
+ } while (f);
+}
+
+// Search the bios-geometry list for the given glob pattern.
+static BootDeviceLCHS *
+boot_lchs_find(const char *glob)
+{
+ dprintf(1, "Searching bios-geometry for: %s\n", glob);
+ int i;
+ for (i = 0; i < BiosGeometryCount; i++)
+ if (glob_prefix(glob, BiosGeometry[i].name))
+ return &BiosGeometry[i];
+ return NULL;
+}
+
+int boot_lchs_find_pci_device(struct pci_device *pci, struct chs_s *chs)
+{
+ if (!CONFIG_HOST_BIOS_GEOMETRY)
+ return -1;
+ char desc[256];
+ build_pci_path(desc, sizeof(desc), "*", pci);
+ BootDeviceLCHS *b = boot_lchs_find(desc);
+ if (!b)
+ return -1;
+ chs->cylinder = (u16)b->lcyls;
+ chs->head = (u16)b->lheads;
+ chs->sector = (u16)b->lsecs;
+ return 0;
+}
+
+int boot_lchs_find_scsi_device(struct pci_device *pci, int target, int lun,
+ struct chs_s *chs)
+{
+ if (!CONFIG_HOST_BIOS_GEOMETRY)
+ return -1;
+ if (!pci)
+ // support only pci machine for now
+ return -1;
+ // Find scsi drive - for example: /pci@i0cf8/scsi@5/channel@0/disk@1,0
+ char desc[256];
+ build_scsi_path(desc, sizeof(desc), pci, target, lun);
+ BootDeviceLCHS *b = boot_lchs_find(desc);
+ if (!b)
+ return -1;
+ chs->cylinder = (u16)b->lcyls;
+ chs->head = (u16)b->lheads;
+ chs->sector = (u16)b->lsecs;
+ return 0;
+}
+
+int boot_lchs_find_ata_device(struct pci_device *pci, int chanid, int slave,
+ struct chs_s *chs)
+{
+ if (!CONFIG_HOST_BIOS_GEOMETRY)
+ return -1;
+ if (!pci)
+ // support only pci machine for now
+ return -1;
+ // Find ata drive - for example: /pci@i0cf8/ide@1,1/drive@1/disk@0
+ char desc[256];
+ build_ata_path(desc, sizeof(desc), pci, chanid, slave);
+ BootDeviceLCHS *b = boot_lchs_find(desc);
+ if (!b)
+ return -1;
+ chs->cylinder = (u16)b->lcyls;
+ chs->head = (u16)b->lheads;
+ chs->sector = (u16)b->lsecs;
+ return 0;
+}
+
+
+/****************************************************************
+ * Boot priority ordering
+ ****************************************************************/
+
+static char **Bootorder VARVERIFY32INIT;
+static int BootorderCount;
+
+static void
+loadBootOrder(void)
+{
+ if (!CONFIG_BOOTORDER)
+ return;
+
+ char *f = romfile_loadfile("bootorder", NULL);
+ if (!f)
+ return;
+
+ int i = 0;
+ BootorderCount = 1;
+ while (f[i]) {
+ if (f[i] == '\n')
+ BootorderCount++;
+ i++;
+ }
+ Bootorder = malloc_tmphigh(BootorderCount*sizeof(char*));
+ if (!Bootorder) {
+ warn_noalloc();
+ free(f);
+ BootorderCount = 0;
+ return;
+ }
+
+ dprintf(1, "boot order:\n");
+ i = 0;
+ do {
+ Bootorder[i] = f;
+ f = strchr(f, '\n');
+ if (f)
+ *(f++) = '\0';
+ Bootorder[i] = nullTrailingSpace(Bootorder[i]);
+ dprintf(1, "%d: %s\n", i+1, Bootorder[i]);
+ i++;
+ } while (f);
+}
+
+// Search the bootorder list for the given glob pattern.
+static int
+find_prio(const char *glob)
+{
+ dprintf(1, "Searching bootorder for: %s\n", glob);
+ int i;
+ for (i = 0; i < BootorderCount; i++)
+ if (glob_prefix(glob, Bootorder[i]))
+ return i+1;
+ return -1;
+}
+
+u8 is_bootprio_strict(void)
+{
+ static int prio_halt = -2;
+
+ if (prio_halt == -2)
+ prio_halt = find_prio("HALT");
+ return prio_halt >= 0;
+}
+
+int bootprio_find_pci_device(struct pci_device *pci)
+{
+ if (CONFIG_CSM)
+ return csm_bootprio_pci(pci);
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ // Find pci device - for example: /pci@i0cf8/ethernet@5
+ char desc[256];
+ build_pci_path(desc, sizeof(desc), "*", pci);
+ return find_prio(desc);
+}
+
+int bootprio_find_mmio_device(void *mmio)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ char desc[256];
+ snprintf(desc, sizeof(desc), "/virtio-mmio@%016x/*", (u32)mmio);
+ return find_prio(desc);
+}
+
+int bootprio_find_scsi_device(struct pci_device *pci, int target, int lun)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ if (!pci)
+ // support only pci machine for now
+ return -1;
+ char desc[256];
+ build_scsi_path(desc, sizeof(desc), pci, target, lun);
+ return find_prio(desc);
+}
+
+int bootprio_find_scsi_mmio_device(void *mmio, int target, int lun)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ char desc[256];
+ snprintf(desc, sizeof(desc), "/virtio-mmio@%016x/*@0/*@%x,%x",
+ (u32)mmio, target, lun);
+ return find_prio(desc);
+}
+
+int bootprio_find_ata_device(struct pci_device *pci, int chanid, int slave)
+{
+ if (CONFIG_CSM)
+ return csm_bootprio_ata(pci, chanid, slave);
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ if (!pci)
+ // support only pci machine for now
+ return -1;
+ char desc[256];
+ build_ata_path(desc, sizeof(desc), pci, chanid, slave);
+ return find_prio(desc);
+}
+
+int bootprio_find_fdc_device(struct pci_device *pci, int port, int fdid)
+{
+ if (CONFIG_CSM)
+ return csm_bootprio_fdc(pci, port, fdid);
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ if (!pci)
+ // support only pci machine for now
+ return -1;
+ // Find floppy - for example: /pci@i0cf8/isa@1/fdc@03f1/floppy@0
+ char desc[256], *p;
+ p = build_pci_path(desc, sizeof(desc), "isa", pci);
+ snprintf(p, desc+sizeof(desc)-p, "/fdc@%04x/floppy@%x", port, fdid);
+ return find_prio(desc);
+}
+
+int bootprio_find_pci_rom(struct pci_device *pci, int instance)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ // Find pci rom - for example: /pci@i0cf8/scsi@3:rom2
+ char desc[256], *p;
+ p = build_pci_path(desc, sizeof(desc), "*", pci);
+ if (instance)
+ snprintf(p, desc+sizeof(desc)-p, ":rom%x", instance);
+ return find_prio(desc);
+}
+
+int bootprio_find_named_rom(const char *name, int instance)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ // Find named rom - for example: /rom@genroms/linuxboot.bin
+ char desc[256], *p;
+ p = desc + snprintf(desc, sizeof(desc), "/rom@%s", name);
+ if (instance)
+ snprintf(p, desc+sizeof(desc)-p, ":rom%x", instance);
+ return find_prio(desc);
+}
+
+static int usb_portmap(struct usbdevice_s *usbdev)
+{
+ if (usbdev->hub->op->portmap)
+ return usbdev->hub->op->portmap(usbdev->hub, usbdev->port);
+ return usbdev->port + 1;
+}
+
+static char *
+build_usb_path(char *buf, int max, struct usbhub_s *hub)
+{
+ if (!hub->usbdev)
+ // Root hub - nothing to add.
+ return buf;
+ char *p = build_usb_path(buf, max, hub->usbdev->hub);
+ p += snprintf(p, buf+max-p, "/hub@%x", usb_portmap(hub->usbdev));
+ return p;
+}
+
+int bootprio_find_usb(struct usbdevice_s *usbdev, int lun)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ // Find usb - examples:
+ // pci: /pci@i0cf8/usb@1,2/storage@1/channel@0/disk@0,0
+ // mmio: /sysbus-xhci@00000000fe900000/storage@1/channel@0/disk@0,0
+ char desc[256], *p;
+
+ if (usbdev->hub->cntl->pci)
+ p = build_pci_path(desc, sizeof(desc), "usb", usbdev->hub->cntl->pci);
+ else if (usbdev->hub->cntl->mmio)
+ p = desc + snprintf(desc, sizeof(desc), "/*@%016x"
+ , (u32)usbdev->hub->cntl->mmio);
+ else
+ return -1;
+
+ p = build_usb_path(p, desc+sizeof(desc)-p, usbdev->hub);
+ snprintf(p, desc+sizeof(desc)-p, "/storage@%x/*@0/*@0,%x"
+ , usb_portmap(usbdev), lun);
+ int ret = find_prio(desc);
+ if (ret >= 0)
+ return ret;
+ // Try usb-host/redir - for example: /pci@i0cf8/usb@1,2/usb-host@1
+ snprintf(p, desc+sizeof(desc)-p, "/usb-*@%x", usb_portmap(usbdev));
+ return find_prio(desc);
+}
+
+
+/****************************************************************
+ * Boot setup
+ ****************************************************************/
+
+static int BootRetryTime;
+static int CheckFloppySig = 1;
+
+#define DEFAULT_PRIO 9999
+
+static int DefaultFloppyPrio = 101;
+static int DefaultCDPrio = 102;
+static int DefaultHDPrio = 103;
+static int DefaultBEVPrio = 104;
+
+void
+boot_init(void)
+{
+ if (! CONFIG_BOOT)
+ return;
+
+ if (CONFIG_QEMU) {
+ // On emulators, get boot order from nvram.
+ if (rtc_read(CMOS_BIOS_BOOTFLAG1) & 1)
+ CheckFloppySig = 0;
+ u32 bootorder = (rtc_read(CMOS_BIOS_BOOTFLAG2)
+ | ((rtc_read(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4));
+ DefaultFloppyPrio = DefaultCDPrio = DefaultHDPrio
+ = DefaultBEVPrio = DEFAULT_PRIO;
+ int i;
+ for (i=101; i<104; i++) {
+ u32 val = bootorder & 0x0f;
+ bootorder >>= 4;
+ switch (val) {
+ case 1: DefaultFloppyPrio = i; break;
+ case 2: DefaultHDPrio = i; break;
+ case 3: DefaultCDPrio = i; break;
+ case 4: DefaultBEVPrio = i; break;
+ }
+ }
+ }
+
+ BootRetryTime = romfile_loadint("etc/boot-fail-wait", 60*1000);
+
+ loadBootOrder();
+ loadBiosGeometry();
+}
+
+
+/****************************************************************
+ * BootList handling
+ ****************************************************************/
+
+struct bootentry_s {
+ int type;
+ union {
+ u32 data;
+ struct segoff_s vector;
+ struct drive_s *drive;
+ };
+ int priority;
+ const char *description;
+ struct hlist_node node;
+};
+static struct hlist_head BootList VARVERIFY32INIT;
+
+#define IPL_TYPE_FLOPPY 0x01
+#define IPL_TYPE_HARDDISK 0x02
+#define IPL_TYPE_CDROM 0x03
+#define IPL_TYPE_CBFS 0x20
+#define IPL_TYPE_BEV 0x80
+#define IPL_TYPE_BCV 0x81
+#define IPL_TYPE_HALT 0xf0
+
+static void
+bootentry_add(int type, int prio, u32 data, const char *desc)
+{
+ if (! CONFIG_BOOT)
+ return;
+ struct bootentry_s *be = malloc_tmp(sizeof(*be));
+ if (!be) {
+ warn_noalloc();
+ return;
+ }
+ be->type = type;
+ be->priority = prio;
+ be->data = data;
+ be->description = desc ?: "?";
+ dprintf(3, "Registering bootable: %s (type:%d prio:%d data:%x)\n"
+ , be->description, type, prio, data);
+
+ // Add entry in sorted order.
+ struct hlist_node **pprev;
+ struct bootentry_s *pos;
+ hlist_for_each_entry_pprev(pos, pprev, &BootList, node) {
+ if (be->priority < pos->priority)
+ break;
+ if (be->priority > pos->priority)
+ continue;
+ if (be->type < pos->type)
+ break;
+ if (be->type > pos->type)
+ continue;
+ if (be->type <= IPL_TYPE_CDROM
+ && (be->drive->type < pos->drive->type
+ || (be->drive->type == pos->drive->type
+ && be->drive->cntl_id < pos->drive->cntl_id)))
+ break;
+ }
+ hlist_add(&be->node, pprev);
+}
+
+// Return the given priority if it's set - defaultprio otherwise.
+static inline int defPrio(int priority, int defaultprio) {
+ return (priority < 0) ? defaultprio : priority;
+}
+
+// Add a BEV vector for a given pnp compatible option rom.
+void
+boot_add_bev(u16 seg, u16 bev, u16 desc, int prio)
+{
+ bootentry_add(IPL_TYPE_BEV, defPrio(prio, DefaultBEVPrio)
+ , SEGOFF(seg, bev).segoff
+ , desc ? MAKE_FLATPTR(seg, desc) : "Unknown");
+ DefaultBEVPrio = DEFAULT_PRIO;
+}
+
+// Add a bcv entry for an expansion card harddrive or legacy option rom
+void
+boot_add_bcv(u16 seg, u16 ip, u16 desc, int prio)
+{
+ bootentry_add(IPL_TYPE_BCV, defPrio(prio, DefaultHDPrio)
+ , SEGOFF(seg, ip).segoff
+ , desc ? MAKE_FLATPTR(seg, desc) : "Legacy option rom");
+}
+
+void
+boot_add_floppy(struct drive_s *drive, const char *desc, int prio)
+{
+ bootentry_add(IPL_TYPE_FLOPPY, defPrio(prio, DefaultFloppyPrio)
+ , (u32)drive, desc);
+}
+
+void
+boot_add_hd(struct drive_s *drive, const char *desc, int prio)
+{
+ bootentry_add(IPL_TYPE_HARDDISK, defPrio(prio, DefaultHDPrio)
+ , (u32)drive, desc);
+}
+
+void
+boot_add_cd(struct drive_s *drive, const char *desc, int prio)
+{
+ if (GET_GLOBAL(PlatformRunningOn) & PF_QEMU) {
+ // We want short boot times. But on physical hardware even
+ // the test unit ready can take several seconds. So do media
+ // access on qemu only, where we know it will be fast.
+ char *extra = cdrom_media_info(drive);
+ if (extra) {
+ desc = znprintf(MAXDESCSIZE, "%s (%s)", desc, extra);
+ free(extra);
+ }
+ }
+ bootentry_add(IPL_TYPE_CDROM, defPrio(prio, DefaultCDPrio)
+ , (u32)drive, desc);
+}
+
+// Add a CBFS payload entry
+void
+boot_add_cbfs(void *data, const char *desc, int prio)
+{
+ bootentry_add(IPL_TYPE_CBFS, defPrio(prio, DEFAULT_PRIO), (u32)data, desc);
+}
+
+
+/****************************************************************
+ * Keyboard calls
+ ****************************************************************/
+
+// See if a keystroke is pending in the keyboard buffer.
+static int
+check_for_keystroke(void)
+{
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF|F_ZF;
+ br.ah = 1;
+ call16_int(0x16, &br);
+ return !(br.flags & F_ZF);
+}
+
+// Return a keystroke - waiting forever if necessary.
+static int
+get_raw_keystroke(void)
+{
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ call16_int(0x16, &br);
+ return br.ax;
+}
+
+// Read a keystroke - waiting up to 'msec' milliseconds.
+// returns both scancode and ascii code.
+int
+get_keystroke_full(int msec)
+{
+ u32 end = irqtimer_calc(msec);
+ for (;;) {
+ if (check_for_keystroke())
+ return get_raw_keystroke();
+ if (irqtimer_check(end))
+ return -1;
+ yield_toirq();
+ }
+}
+
+// Read a keystroke - waiting up to 'msec' milliseconds.
+// returns scancode only.
+int
+get_keystroke(int msec)
+{
+ int keystroke = get_keystroke_full(msec);
+
+ if (keystroke < 0)
+ return keystroke;
+ return keystroke >> 8;
+}
+
+/****************************************************************
+ * Boot menu and BCV execution
+ ****************************************************************/
+
+#define DEFAULT_BOOTMENU_WAIT 2500
+
+static const char menuchars[] = {
+ '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+ 's', /* skip t (tpm menu) */
+ 'u', 'v', 'w', 'x', 'y', 'z'
+};
+
+// Show IPL option menu.
+void
+interactive_bootmenu(void)
+{
+ if (! CONFIG_BOOTMENU)
+ return;
+ int show_boot_menu = romfile_loadint("etc/show-boot-menu", 1);
+ if (!show_boot_menu)
+ return;
+
+ // skip menu if only one boot device and no TPM
+ if (show_boot_menu == 2 && !tpm_can_show_menu()
+ && !hlist_empty(&BootList) && !BootList.first->next) {
+ dprintf(1, "Only one boot device present. Skip boot menu.\n");
+ printf("\n");
+ return;
+ }
+
+ while (get_keystroke(0) >= 0)
+ ;
+
+ char *bootmsg = romfile_loadfile("etc/boot-menu-message", NULL);
+ 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);
+ enable_bootsplash();
+ int scan_code = get_keystroke(menutime);
+ disable_bootsplash();
+ if (scan_code != menukey)
+ return;
+
+ while (get_keystroke(0) >= 0)
+ ;
+
+ printf("Select boot device:\n\n");
+ wait_threads();
+
+ // Show menu items
+ int maxmenu = 0;
+ struct bootentry_s *pos, *boot = NULL;
+ hlist_for_each_entry(pos, &BootList, node) {
+ char desc[77];
+ if (maxmenu >= ARRAY_SIZE(menuchars)) {
+ break;
+ }
+ printf("%c. %s\n", menuchars[maxmenu]
+ , strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
+ maxmenu++;
+ }
+ if (tpm_can_show_menu()) {
+ printf("\nt. TPM Configuration\n");
+ }
+
+ // 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 (;;) {
+ int keystroke = get_keystroke_full(1000);
+ if (keystroke == 0x011b && !irqtimer_check(esc_accepted_time))
+ continue;
+ if (keystroke < 0) // timeout
+ continue;
+
+ scan_code = keystroke >> 8;
+ int key_ascii = keystroke & 0xff;
+ if (tpm_can_show_menu() && key_ascii == 't') {
+ printf("\n");
+ tpm_menu();
+ }
+ if (scan_code == 1) {
+ // ESC
+ printf("\n");
+ return;
+ }
+
+ maxmenu = 0;
+ hlist_for_each_entry(pos, &BootList, node) {
+ if (maxmenu >= ARRAY_SIZE(menuchars))
+ break;
+ if (key_ascii == menuchars[maxmenu]) {
+ boot = pos;
+ break;
+ }
+ maxmenu++;
+ }
+ if (boot)
+ break;
+ }
+ printf("\n");
+
+ // Find entry and make top priority.
+ hlist_del(&boot->node);
+ boot->priority = 0;
+ hlist_add_head(&boot->node, &BootList);
+}
+
+#if CONFIG_PARISC
+void find_initial_parisc_boot_drives(struct drive_s **harddisc,
+ struct drive_s **cdrom)
+{
+ struct bootentry_s *pos;
+ hlist_for_each_entry(pos, &BootList, node) {
+ if ((pos->type == IPL_TYPE_CDROM) && (*cdrom == NULL))
+ *cdrom = pos->drive;
+ if ((pos->type == IPL_TYPE_HARDDISK) && (*harddisc == NULL))
+ *harddisc = pos->drive;
+ }
+}
+
+struct drive_s *select_parisc_boot_drive(char bootdrive)
+{
+ printf("Available boot devices:\n");
+
+ // Show menu items
+ int maxmenu = 0;
+ struct bootentry_s *pos;
+ hlist_for_each_entry(pos, &BootList, node) {
+ char desc[77];
+ maxmenu++;
+ printf("%d. %s\n", maxmenu
+ , strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
+ }
+
+ /* try each boot device */
+ hlist_for_each_entry(pos, &BootList, node) {
+ if (((bootdrive == 'd') && (pos->type == IPL_TYPE_CDROM)) ||
+ ((bootdrive == 'c') && (pos->type == IPL_TYPE_HARDDISK))) {
+ printf("\nBooting from %s\n",pos->description);
+ return pos->drive;
+ }
+ /* -boot order=g-m: machine implementation dependent drives */
+ if ((bootdrive >= 'g') && (bootdrive <= 'm')) {
+ int scsi_index = (int)bootdrive - 'g';
+ if (pos->drive->target == scsi_index) {
+ printf("\nBooting from SCSI target %d: %s\n",
+ scsi_index, pos->description);
+ return pos->drive;
+ }
+ }
+ }
+ /* if none found, choose first bootable device */
+ hlist_for_each_entry(pos, &BootList, node) {
+ if ((pos->type == IPL_TYPE_CDROM) ||
+ (pos->type == IPL_TYPE_HARDDISK)) {
+ printf("\nAuto-Booting from %s\n",pos->description);
+ return pos->drive;
+ }
+ }
+ return NULL;
+}
+#endif
+
+
+// BEV (Boot Execution Vector) list
+struct bev_s {
+ int type;
+ u32 vector;
+};
+static struct bev_s BEV[20];
+static int BEVCount;
+static int HaveHDBoot, HaveFDBoot;
+
+static void
+add_bev(int type, u32 vector)
+{
+ if (type == IPL_TYPE_HARDDISK && HaveHDBoot++)
+ return;
+ if (type == IPL_TYPE_FLOPPY && HaveFDBoot++)
+ return;
+ if (BEVCount >= ARRAY_SIZE(BEV))
+ return;
+ struct bev_s *bev = &BEV[BEVCount++];
+ bev->type = type;
+ bev->vector = vector;
+}
+
+// Prepare for boot - show menu and run bcvs.
+void
+bcv_prepboot(void)
+{
+ if (! CONFIG_BOOT)
+ return;
+
+ int haltprio = find_prio("HALT");
+ if (haltprio >= 0)
+ bootentry_add(IPL_TYPE_HALT, haltprio, 0, "HALT");
+
+ // Map drives and populate BEV list
+ struct bootentry_s *pos;
+ hlist_for_each_entry(pos, &BootList, node) {
+ switch (pos->type) {
+ case IPL_TYPE_BCV:
+ call_bcv(pos->vector.seg, pos->vector.offset);
+ add_bev(IPL_TYPE_HARDDISK, 0);
+ break;
+ case IPL_TYPE_FLOPPY:
+ map_floppy_drive(pos->drive);
+ add_bev(IPL_TYPE_FLOPPY, 0);
+ break;
+ case IPL_TYPE_HARDDISK:
+ map_hd_drive(pos->drive);
+ add_bev(IPL_TYPE_HARDDISK, 0);
+ break;
+ case IPL_TYPE_CDROM:
+ map_cd_drive(pos->drive);
+ // NO BREAK
+ default:
+ add_bev(pos->type, pos->data);
+ break;
+ }
+ }
+
+ // If nothing added a floppy/hd boot - add it manually.
+ add_bev(IPL_TYPE_FLOPPY, 0);
+ add_bev(IPL_TYPE_HARDDISK, 0);
+}
+
+
+/****************************************************************
+ * Boot code (int 18/19)
+ ****************************************************************/
+
+// Jump to a bootup entry point.
+static void
+call_boot_entry(struct segoff_s bootsegip, u8 bootdrv)
+{
+ dprintf(1, "Booting from %04x:%04x\n", bootsegip.seg, bootsegip.offset);
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ br.code = bootsegip;
+ // Set the magic number in ax and the boot drive in dl.
+ br.dl = bootdrv;
+ br.ax = 0xaa55;
+ farcall16(&br);
+}
+
+// Boot from a disk (either floppy or harddrive)
+static void
+boot_disk(u8 bootdrv, int checksig)
+{
+ u16 bootseg = 0x07c0;
+
+ // Read sector
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ br.dl = bootdrv;
+ br.es = bootseg;
+ br.ah = 2;
+ br.al = 1;
+ br.cl = 1;
+ call16_int(0x13, &br);
+
+ if (br.flags & F_CF) {
+ printf("Boot failed: could not read the boot disk\n\n");
+ return;
+ }
+
+ if (checksig) {
+ struct mbr_s *mbr = (void*)0;
+ if (GET_FARVAR(bootseg, mbr->signature) != MBR_SIGNATURE) {
+ printf("Boot failed: not a bootable disk\n\n");
+ return;
+ }
+ }
+
+ tpm_add_bcv(bootdrv, MAKE_FLATPTR(bootseg, 0), 512);
+
+ /* Canonicalize bootseg:bootip */
+ u16 bootip = (bootseg & 0x0fff) << 4;
+ bootseg &= 0xf000;
+
+ call_boot_entry(SEGOFF(bootseg, bootip), bootdrv);
+}
+
+// Boot from a CD-ROM
+static void
+boot_cdrom(struct drive_s *drive)
+{
+ if (! CONFIG_CDROM_BOOT)
+ return;
+ printf("Booting from DVD/CD...\n");
+
+ int status = cdrom_boot(drive);
+ if (status) {
+ printf("Boot failed: Could not read from CDROM (code %04x)\n", status);
+ return;
+ }
+
+ 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;
+
+ call_boot_entry(SEGOFF(bootseg, bootip), bootdrv);
+}
+
+// Boot from a CBFS payload
+static void
+boot_cbfs(struct cbfs_file *file)
+{
+ if (!CONFIG_COREBOOT_FLASH)
+ return;
+ printf("Booting from CBFS...\n");
+ cbfs_run_payload(file);
+}
+
+// Boot from a BEV entry on an optionrom.
+static void
+boot_rom(u32 vector)
+{
+ printf("Booting from ROM...\n");
+ struct segoff_s so;
+ so.segoff = vector;
+ call_boot_entry(so, 0);
+}
+
+// Unable to find bootable device - warn user and eventually retry.
+static void
+boot_fail(void)
+{
+ if (BootRetryTime == (u32)-1)
+ printf("No bootable device.\n");
+ else
+ printf("No bootable device. Retrying in %d seconds.\n"
+ , BootRetryTime/1000);
+ // Wait for 'BootRetryTime' milliseconds and then reboot.
+ u32 end = irqtimer_calc(BootRetryTime);
+ for (;;) {
+ if (BootRetryTime != (u32)-1 && irqtimer_check(end))
+ break;
+ yield_toirq();
+ }
+ printf("Rebooting.\n");
+ reset();
+}
+
+// Determine next boot method and attempt a boot using it.
+static void
+do_boot(int seq_nr)
+{
+ if (! CONFIG_BOOT)
+ panic("Boot support not compiled in.\n");
+
+ if (seq_nr >= BEVCount)
+ boot_fail();
+
+ // Boot the given BEV type.
+ struct bev_s *ie = &BEV[seq_nr];
+ switch (ie->type) {
+ case IPL_TYPE_FLOPPY:
+ printf("Booting from Floppy...\n");
+ boot_disk(0x00, CheckFloppySig);
+ break;
+ case IPL_TYPE_HARDDISK:
+ printf("Booting from Hard Disk...\n");
+ boot_disk(0x80, 1);
+ break;
+ case IPL_TYPE_CDROM:
+ boot_cdrom((void*)ie->vector);
+ break;
+ case IPL_TYPE_CBFS:
+ boot_cbfs((void*)ie->vector);
+ break;
+ case IPL_TYPE_BEV:
+ boot_rom(ie->vector);
+ break;
+ case IPL_TYPE_HALT:
+ boot_fail();
+ break;
+ }
+
+ // Boot failed: invoke the boot recovery function
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ call16_int(0x18, &br);
+}
+
+int BootSequence VARLOW = -1;
+
+// Boot Failure recovery: try the next device.
+void VISIBLE32FLAT
+handle_18(void)
+{
+ debug_enter(NULL, DEBUG_HDL_18);
+ int seq = BootSequence + 1;
+ BootSequence = seq;
+ do_boot(seq);
+}
+
+// INT 19h Boot Load Service Entry Point
+void VISIBLE32FLAT
+handle_19(void)
+{
+ debug_enter(NULL, DEBUG_HDL_19);
+ BootSequence = 0;
+ do_boot(0);
+}
diff --git a/roms/seabios-hppa/src/bootsplash.c b/roms/seabios-hppa/src/bootsplash.c
new file mode 100644
index 000000000..538b316d5
--- /dev/null
+++ b/roms/seabios-hppa/src/bootsplash.c
@@ -0,0 +1,255 @@
+// Initialize the VGA console and possibly show a boot splash image.
+//
+// Copyright (C) 2009-2010 coresystems GmbH
+// Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "bregs.h" // struct bregs
+#include "config.h" // CONFIG_*
+#include "farptr.h" // FLATPTR_TO_SEG
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "romfile.h" // romfile_loadfile
+#include "stacks.h" // call16_int
+#include "std/vbe.h" // struct vbe_info
+#include "string.h" // memset
+#include "util.h" // enable_bootsplash
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Call int10 vga handler.
+static void
+call16_int10(struct bregs *br)
+{
+ br->flags = F_IF;
+ start_preempt();
+ call16_int(0x10, br);
+ finish_preempt();
+}
+
+
+/****************************************************************
+ * VGA text / graphics console
+ ****************************************************************/
+
+void
+enable_vga_console(void)
+{
+ dprintf(1, "Turning on vga text mode console\n");
+ struct bregs br;
+
+ /* Enable VGA text mode */
+ memset(&br, 0, sizeof(br));
+ br.ax = 0x0003;
+ call16_int10(&br);
+
+ // Write to screen.
+ printf("SeaBIOS (version %s)\n", VERSION);
+ display_uuid();
+}
+
+static int
+find_videomode(struct vbe_info *vesa_info, struct vbe_mode_info *mode_info
+ , int width, int height, int bpp_req)
+{
+ dprintf(3, "Finding vesa mode with dimensions %d/%d\n", width, height);
+ u16 *videomodes = SEGOFF_TO_FLATPTR(vesa_info->video_mode);
+ for (;; videomodes++) {
+ u16 videomode = *videomodes;
+ if (videomode == 0xffff) {
+ dprintf(1, "Unable to find vesa video mode dimensions %d/%d\n"
+ , width, height);
+ return -1;
+ }
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.ax = 0x4f01;
+ br.cx = videomode;
+ br.di = FLATPTR_TO_OFFSET(mode_info);
+ br.es = FLATPTR_TO_SEG(mode_info);
+ call16_int10(&br);
+ if (br.ax != 0x4f) {
+ dprintf(1, "get_mode failed.\n");
+ continue;
+ }
+ if (mode_info->xres != width
+ || mode_info->yres != height)
+ continue;
+ u8 depth = mode_info->bits_per_pixel;
+ if (bpp_req == 0) {
+ if ((depth != 16 && depth != 24 && depth != 32)
+ || mode_info->green_size == 5)
+ continue;
+ } else {
+ if (depth != bpp_req)
+ continue;
+ }
+ return videomode;
+ }
+}
+
+static int BootsplashActive;
+
+void
+enable_bootsplash(void)
+{
+ if (!CONFIG_BOOTSPLASH)
+ return;
+ /* splash picture can be bmp or jpeg file */
+ dprintf(3, "Checking for bootsplash\n");
+ u8 type = 0; /* 0 means jpg, 1 means bmp, default is 0=jpg */
+ int filesize;
+ u8 *filedata = romfile_loadfile("bootsplash.jpg", &filesize);
+ if (!filedata) {
+ filedata = romfile_loadfile("bootsplash.bmp", &filesize);
+ if (!filedata)
+ return;
+ type = 1;
+ }
+ dprintf(3, "start showing bootsplash\n");
+
+ u8 *picture = NULL; /* data buff used to be flushed to the video buf */
+ struct jpeg_decdata *jpeg = NULL;
+ struct bmp_decdata *bmp = NULL;
+ struct vbe_info *vesa_info = malloc_tmplow(sizeof(*vesa_info));
+ struct vbe_mode_info *mode_info = malloc_tmplow(sizeof(*mode_info));
+ if (!vesa_info || !mode_info) {
+ warn_noalloc();
+ goto done;
+ }
+
+ /* Check whether we have a VESA 2.0 compliant BIOS */
+ memset(vesa_info, 0, sizeof(struct vbe_info));
+ vesa_info->signature = VBE2_SIGNATURE;
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.ax = 0x4f00;
+ br.di = FLATPTR_TO_OFFSET(vesa_info);
+ br.es = FLATPTR_TO_SEG(vesa_info);
+ call16_int10(&br);
+ if (vesa_info->signature != VESA_SIGNATURE) {
+ dprintf(1,"No VBE2 found.\n");
+ goto done;
+ }
+
+ /* Print some debugging information about our card. */
+ char *vendor = SEGOFF_TO_FLATPTR(vesa_info->oem_vendor_string);
+ char *product = SEGOFF_TO_FLATPTR(vesa_info->oem_product_string);
+ dprintf(3, "VESA %d.%d\nVENDOR: %s\nPRODUCT: %s\n",
+ vesa_info->version>>8, vesa_info->version&0xff,
+ vendor, product);
+
+ int ret, width, height;
+ int bpp_require = 0;
+ if (type == 0) {
+ jpeg = jpeg_alloc();
+ if (!jpeg) {
+ warn_noalloc();
+ goto done;
+ }
+ /* Parse jpeg and get image size. */
+ dprintf(5, "Decoding bootsplash.jpg\n");
+ ret = jpeg_decode(jpeg, filedata);
+ if (ret) {
+ dprintf(1, "jpeg_decode failed with return code %d...\n", ret);
+ goto done;
+ }
+ jpeg_get_size(jpeg, &width, &height);
+ } else {
+ bmp = bmp_alloc();
+ if (!bmp) {
+ warn_noalloc();
+ goto done;
+ }
+ /* Parse bmp and get image size. */
+ dprintf(5, "Decoding bootsplash.bmp\n");
+ ret = bmp_decode(bmp, filedata, filesize);
+ if (ret) {
+ dprintf(1, "bmp_decode failed with return code %d...\n", ret);
+ goto done;
+ }
+ bmp_get_info(bmp, &width, &height, &bpp_require);
+ }
+
+ // jpeg would use 16 or 24 bpp video mode, BMP uses 16/24/32 bpp mode.
+
+ // Try to find a graphics mode with the corresponding dimensions.
+ int videomode = find_videomode(vesa_info, mode_info, width, height,
+ bpp_require);
+ if (videomode < 0) {
+ dprintf(1, "failed to find a videomode with %dx%d %dbpp (0=any).\n",
+ width, height, bpp_require);
+ goto done;
+ }
+ void *framebuffer = (void *)mode_info->phys_base;
+ int depth = mode_info->bits_per_pixel;
+ dprintf(3, "mode: %04x\n", videomode);
+ dprintf(3, "framebuffer: %p\n", framebuffer);
+ dprintf(3, "bytes per scanline: %d\n", mode_info->bytes_per_scanline);
+ dprintf(3, "bits per pixel: %d\n", depth);
+
+ // Allocate space for image and decompress it.
+ int imagesize = height * mode_info->bytes_per_scanline;
+ picture = malloc_tmphigh(imagesize);
+ if (!picture) {
+ warn_noalloc();
+ goto done;
+ }
+
+ if (type == 0) {
+ dprintf(5, "Decompressing bootsplash.jpg\n");
+ ret = jpeg_show(jpeg, picture, width, height, depth,
+ mode_info->bytes_per_scanline);
+ if (ret) {
+ dprintf(1, "jpeg_show failed with return code %d...\n", ret);
+ goto done;
+ }
+ } else {
+ dprintf(5, "Decompressing bootsplash.bmp\n");
+ ret = bmp_show(bmp, picture, width, height, depth,
+ mode_info->bytes_per_scanline);
+ if (ret) {
+ dprintf(1, "bmp_show failed with return code %d...\n", ret);
+ goto done;
+ }
+ }
+
+ /* Switch to graphics mode */
+ dprintf(5, "Switching to graphics mode\n");
+ memset(&br, 0, sizeof(br));
+ br.ax = 0x4f02;
+ br.bx = videomode | VBE_MODE_LINEAR_FRAME_BUFFER;
+ call16_int10(&br);
+ if (br.ax != 0x4f) {
+ dprintf(1, "set_mode failed.\n");
+ goto done;
+ }
+
+ /* Show the picture */
+ dprintf(5, "Showing bootsplash picture\n");
+ iomemcpy(framebuffer, picture, imagesize);
+ dprintf(5, "Bootsplash copy complete\n");
+ BootsplashActive = 1;
+
+done:
+ free(filedata);
+ free(picture);
+ free(vesa_info);
+ free(mode_info);
+ free(jpeg);
+ free(bmp);
+ return;
+}
+
+void
+disable_bootsplash(void)
+{
+ if (!CONFIG_BOOTSPLASH || !BootsplashActive)
+ return;
+ BootsplashActive = 0;
+ enable_vga_console();
+}
diff --git a/roms/seabios-hppa/src/bregs.h b/roms/seabios-hppa/src/bregs.h
new file mode 100644
index 000000000..d40526345
--- /dev/null
+++ b/roms/seabios-hppa/src/bregs.h
@@ -0,0 +1,80 @@
+// Structure layout of cpu registers that the bios uses.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#ifndef __BREGS_H
+#define __BREGS_H
+
+#include "types.h" // u16
+#include "x86.h" // F_CF
+
+
+/****************************************************************
+ * Registers saved/restored in romlayout.S
+ ****************************************************************/
+
+#define UREG(ER, R, RH, RL) union { u32 ER; struct { u16 R; u16 R ## _hi; }; struct { u8 RL; u8 RH; u8 R ## _hilo; u8 R ## _hihi; }; }
+
+// Layout of registers passed in to irq handlers. Note that this
+// layout corresponds to code in romlayout.S - don't change it here
+// without also updating the assembler code.
+struct bregs {
+ u16 ds;
+ u16 es;
+ UREG(edi, di, di8u, di8l);
+ UREG(esi, si, si8u, si8l);
+ UREG(ebp, bp, bp8u, bp8l);
+ UREG(ebx, bx, bh, bl);
+ UREG(edx, dx, dh, dl);
+ UREG(ecx, cx, ch, cl);
+ UREG(eax, ax, ah, al);
+ struct segoff_s code;
+ u16 flags;
+} PACKED;
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+static inline void
+set_cf(struct bregs *regs, int cond)
+{
+ if (cond)
+ regs->flags |= F_CF;
+ else
+ regs->flags &= ~F_CF;
+}
+
+// Frequently used return codes
+#define RET_EUNSUPPORTED 0x86
+
+static inline void
+set_success(struct bregs *regs)
+{
+ set_cf(regs, 0);
+}
+
+static inline void
+set_code_success(struct bregs *regs)
+{
+ regs->ah = 0;
+ set_cf(regs, 0);
+}
+
+static inline void
+set_invalid_silent(struct bregs *regs)
+{
+ set_cf(regs, 1);
+}
+
+static inline void
+set_code_invalid_silent(struct bregs *regs, u8 code)
+{
+ regs->ah = code;
+ set_cf(regs, 1);
+}
+
+#endif // bregs.h
diff --git a/roms/seabios-hppa/src/byteorder.h b/roms/seabios-hppa/src/byteorder.h
new file mode 100644
index 000000000..f0dffa3ff
--- /dev/null
+++ b/roms/seabios-hppa/src/byteorder.h
@@ -0,0 +1,145 @@
+#ifndef __BYTEORDER_H
+#define __BYTEORDER_H
+
+#include "autoconf.h"
+#include "types.h" // u32
+
+#if CONFIG_X86
+#define TARGET_LITTLE_ENDIAN
+#elif CONFIG_PARISC
+#define TARGET_BIG_ENDIAN
+#else
+#error "unknown endianess"
+#endif
+
+static inline u16 __swab16_constant(u16 val) {
+ return (val<<8) | (val>>8);
+}
+static inline u32 __swab32_constant(u32 val) {
+ return (val<<24) | ((val&0xff00)<<8) | ((val&0xff0000)>>8) | (val>>24);
+}
+static inline u64 __swab64_constant(u64 val) {
+ return ((u64)__swab32_constant(val) << 32) | __swab32_constant(val>>32);
+}
+static inline u32 __swab32(u32 val) {
+#if CONFIG_X86
+ asm("bswapl %0" : "+r"(val));
+#elif CONFIG_PARISC
+ unsigned int temp;
+ asm("shd %0, %0, 16, %1\n\t" /* shift abcdabcd -> cdab */
+ "dep %1, 15, 8, %1\n\t" /* deposit cdab -> cbab */
+ "shd %0, %1, 8, %0" /* shift abcdcbab -> dcba */
+ : "=r" (val), "=&r" (temp)
+ : "0" (val));
+#else
+ #error "unknown arch"
+#endif
+ return val;
+}
+static inline u64 __swab64(u64 val) {
+ union u64_u32_u i, o;
+ i.val = val;
+ o.lo = __swab32(i.hi);
+ o.hi = __swab32(i.lo);
+ return o.val;
+}
+
+#define swab16(x) __swab16_constant(x)
+#define swab32(x) (__builtin_constant_p((u32)(x)) \
+ ? __swab32_constant(x) : __swab32(x))
+#define swab64(x) (__builtin_constant_p((u64)(x)) \
+ ? __swab64_constant(x) : __swab64(x))
+
+#if defined(TARGET_BIG_ENDIAN)
+static inline u16 cpu_to_le16(u16 x) {
+ return swab16(x);
+}
+static inline u32 cpu_to_le32(u32 x) {
+ return swab32(x);
+}
+static inline u64 cpu_to_le64(u64 x) {
+ return swab64(x);
+}
+static inline u16 le16_to_cpu(u16 x) {
+ return swab16(x);
+}
+static inline u32 le32_to_cpu(u32 x) {
+ return swab32(x);
+}
+static inline u64 le64_to_cpu(u64 x) {
+ return swab64(x);
+}
+
+static inline u16 cpu_to_be16(u16 x) {
+ return x;
+}
+static inline u32 cpu_to_be32(u32 x) {
+ return x;
+}
+static inline u64 cpu_to_be64(u64 x) {
+ return x;
+}
+static inline u16 be16_to_cpu(u16 x) {
+ return x;
+}
+static inline u32 be32_to_cpu(u32 x) {
+ return x;
+}
+static inline u64 be64_to_cpu(u64 x) {
+ return x;
+}
+
+static inline void convert_to_le32(u32 *script, unsigned long bytes)
+{
+ while (bytes > 0) {
+ *script = cpu_to_le32(*script);
+ script++;
+ bytes -= sizeof(u32);
+ }
+}
+
+#else /* defined(TARGET_LITTLE_ENDIAN) */
+static inline u16 cpu_to_le16(u16 x) {
+ return x;
+}
+static inline u32 cpu_to_le32(u32 x) {
+ return x;
+}
+static inline u64 cpu_to_le64(u64 x) {
+ return x;
+}
+static inline u16 le16_to_cpu(u16 x) {
+ return x;
+}
+static inline u32 le32_to_cpu(u32 x) {
+ return x;
+}
+static inline u64 le64_to_cpu(u64 x) {
+ return x;
+}
+
+static inline u16 cpu_to_be16(u16 x) {
+ return swab16(x);
+}
+static inline u32 cpu_to_be32(u32 x) {
+ return swab32(x);
+}
+static inline u64 cpu_to_be64(u64 x) {
+ return swab64(x);
+}
+static inline u16 be16_to_cpu(u16 x) {
+ return swab16(x);
+}
+static inline u32 be32_to_cpu(u32 x) {
+ return swab32(x);
+}
+static inline u64 be64_to_cpu(u64 x) {
+ return swab64(x);
+}
+
+static inline void convert_to_le32(u32 *script, unsigned long bytes)
+{
+}
+#endif
+
+#endif // byteorder.h
diff --git a/roms/seabios-hppa/src/cdrom.c b/roms/seabios-hppa/src/cdrom.c
new file mode 100644
index 000000000..a77671a47
--- /dev/null
+++ b/roms/seabios-hppa/src/cdrom.c
@@ -0,0 +1,322 @@
+// Support for booting from cdroms (the "El Torito" spec).
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "block.h" // struct drive_s
+#include "bregs.h" // struct bregs
+#include "hw/ata.h" // ATA_CMD_REQUEST_SENSE
+#include "hw/blockcmd.h" // CDB_CMD_REQUEST_SENSE
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // cdrom_prepboot
+#include "tcgbios.h" // tpm_*
+
+
+/****************************************************************
+ * CD emulation
+ ****************************************************************/
+
+struct eltorito_s CDEmu VARLOW = { .size=sizeof(CDEmu) };
+struct drive_s *emulated_drive_gf VARLOW;
+struct drive_s *cdemu_drive_gf VARFSEG;
+
+static int
+cdemu_read(struct disk_op_s *op)
+{
+ struct drive_s *drive_gf = GET_LOW(emulated_drive_gf);
+ struct disk_op_s dop;
+ dop.drive_fl = drive_gf;
+ dop.command = op->command;
+ dop.lba = GET_LOW(CDEmu.ilba) + op->lba / 4;
+
+ int count = op->count;
+ op->count = 0;
+ u8 *cdbuf_fl = GET_GLOBAL(bounce_buf_fl);
+
+ if (op->lba & 3) {
+ // Partial read of first block.
+ dop.count = 1;
+ dop.buf_fl = cdbuf_fl;
+ int ret = process_op(&dop);
+ if (ret)
+ return ret;
+ u8 thiscount = 4 - (op->lba & 3);
+ if (thiscount > count)
+ thiscount = count;
+ count -= thiscount;
+ memcpy_fl(op->buf_fl, cdbuf_fl + (op->lba & 3) * 512, thiscount * 512);
+ op->buf_fl += thiscount * 512;
+ op->count += thiscount;
+ dop.lba++;
+ }
+
+ if (count > 3) {
+ // Read n number of regular blocks.
+ dop.count = count / 4;
+ dop.buf_fl = op->buf_fl;
+ int ret = process_op(&dop);
+ op->count += dop.count * 4;
+ if (ret)
+ return ret;
+ u8 thiscount = count & ~3;
+ count &= 3;
+ op->buf_fl += thiscount * 512;
+ dop.lba += thiscount / 4;
+ }
+
+ if (count) {
+ // Partial read on last block.
+ dop.count = 1;
+ dop.buf_fl = cdbuf_fl;
+ int ret = process_op(&dop);
+ if (ret)
+ return ret;
+ u8 thiscount = count;
+ memcpy_fl(op->buf_fl, cdbuf_fl, thiscount * 512);
+ op->count += thiscount;
+ }
+
+ return DISK_RET_SUCCESS;
+}
+
+int
+cdemu_process_op(struct disk_op_s *op)
+{
+ if (!CONFIG_CDROM_EMU)
+ return 0;
+
+ switch (op->command) {
+ case CMD_READ:
+ return cdemu_read(op);
+ case CMD_WRITE:
+ case CMD_FORMAT:
+ return DISK_RET_EWRITEPROTECT;
+ default:
+ return default_process_op(op);
+ }
+}
+
+void
+cdrom_prepboot(void)
+{
+ if (!CONFIG_CDROM_EMU)
+ return;
+ if (!CDCount)
+ return;
+ if (create_bounce_buf() < 0)
+ return;
+
+ struct drive_s *drive = malloc_fseg(sizeof(*drive));
+ if (!drive) {
+ warn_noalloc();
+ return;
+ }
+ cdemu_drive_gf = drive;
+ memset(drive, 0, sizeof(*drive));
+ drive->type = DTYPE_CDEMU;
+ drive->blksize = DISK_SECTOR_SIZE;
+ drive->sectors = (u64)-1;
+}
+
+
+/****************************************************************
+ * CD booting
+ ****************************************************************/
+
+int
+cdrom_boot(struct drive_s *drive)
+{
+ ASSERT32FLAT();
+ struct disk_op_s dop;
+ int cdid = getDriveId(EXTTYPE_CD, drive);
+ memset(&dop, 0, sizeof(dop));
+ dop.drive_fl = drive;
+ if (!dop.drive_fl || cdid < 0)
+ return 1;
+
+ int ret = scsi_is_ready(&dop);
+ if (ret)
+ dprintf(5, "scsi_is_ready returned %d\n", ret);
+
+ // Read the Boot Record Volume Descriptor
+ u8 buffer[CDROM_SECTOR_SIZE];
+ dop.command = CMD_READ;
+ dop.lba = 0x11;
+ dop.count = 1;
+ dop.buf_fl = buffer;
+ ret = process_op(&dop);
+ if (ret)
+ return 3;
+
+ // Validity checks
+ if (buffer[0])
+ return 4;
+ if (strcmp((char*)&buffer[1], "CD001\001EL TORITO SPECIFICATION") != 0)
+ return 5;
+
+ // ok, now we calculate the Boot catalog address
+ u32 lba = *(u32*)&buffer[0x47];
+
+ // And we read the Boot Catalog
+ dop.lba = lba;
+ dop.count = 1;
+ ret = process_op(&dop);
+ if (ret)
+ return 7;
+
+ // Validation entry
+ if (buffer[0x00] != 0x01)
+ return 8; // Header
+ if (buffer[0x01] != 0x00)
+ return 9; // Platform
+ if (buffer[0x1E] != 0x55)
+ return 10; // key 1
+ if (buffer[0x1F] != 0xAA)
+ return 10; // key 2
+
+ // Initial/Default Entry
+ 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];
+
+ u16 boot_segment = *(u16*)&buffer[0x22];
+ if (!boot_segment)
+ boot_segment = 0x07C0;
+ CDEmu.load_segment = boot_segment;
+ CDEmu.buffer_segment = 0x0000;
+
+ u16 nbsectors = *(u16*)&buffer[0x26];
+ CDEmu.sector_count = nbsectors;
+
+ lba = *(u32*)&buffer[0x28];
+ CDEmu.ilba = lba;
+
+ CDEmu.controller_index = drive->cntl_id / 2;
+ CDEmu.device_spec = drive->cntl_id % 2;
+
+ // And we read the image in memory
+ nbsectors = DIV_ROUND_UP(nbsectors, 4);
+ dop.lba = lba;
+ dop.buf_fl = MAKE_FLATPTR(boot_segment, 0);
+ while (nbsectors) {
+ int count = nbsectors;
+ if (count > 64*1024/CDROM_SECTOR_SIZE)
+ count = 64*1024/CDROM_SECTOR_SIZE;
+ dop.count = count;
+ ret = process_op(&dop);
+ if (ret)
+ return 12;
+ nbsectors -= count;
+ dop.lba += count;
+ dop.buf_fl += count*CDROM_SECTOR_SIZE;
+ }
+
+ if (media == 0) {
+ // No emulation requested - return success.
+ CDEmu.emulated_drive = EXTSTART_CD + cdid;
+ return 0;
+ }
+
+ // Emulation of a floppy/harddisk requested
+ if (! CONFIG_CDROM_EMU || !cdemu_drive_gf)
+ return 13;
+
+ // Set emulated drive id and increase bios installed hardware
+ // number of devices
+ if (media < 4) {
+ // Floppy emulation
+ CDEmu.emulated_drive = 0x00;
+ // XXX - get and set actual floppy count.
+ set_equipment_flags(0x41, 0x41);
+
+ switch (media) {
+ case 0x01: // 1.2M floppy
+ CDEmu.chs.sptcyl = 15;
+ CDEmu.chs.cyllow = 79;
+ CDEmu.chs.heads = 1;
+ break;
+ case 0x02: // 1.44M floppy
+ CDEmu.chs.sptcyl = 18;
+ CDEmu.chs.cyllow = 79;
+ CDEmu.chs.heads = 1;
+ break;
+ case 0x03: // 2.88M floppy
+ CDEmu.chs.sptcyl = 36;
+ CDEmu.chs.cyllow = 79;
+ CDEmu.chs.heads = 1;
+ break;
+ }
+ } else {
+ // Harddrive emulation
+ CDEmu.emulated_drive = 0x80;
+ SET_BDA(hdcount, GET_BDA(hdcount) + 1);
+
+ // Peak at partition table to get chs.
+ struct mbr_s *mbr = MAKE_FLATPTR(boot_segment, 0);
+ CDEmu.chs = mbr->partitions[0].last;
+ }
+
+ // everything is ok, so from now on, the emulation is active
+ CDEmu.media = media;
+ dprintf(6, "cdemu media=%d\n", media);
+
+ return 0;
+}
+
+// check if media is present and the drive is bootable.
+// in case it is return the volume label.
+char*
+cdrom_media_info(struct drive_s *drive)
+{
+ ASSERT32FLAT();
+
+ struct disk_op_s dop;
+ memset(&dop, 0, sizeof(dop));
+ dop.drive_fl = drive;
+
+ int ret = scsi_is_ready(&dop);
+ if (ret)
+ return NULL;
+
+ // Read the Boot Record Volume Descriptor
+ u8 buffer[CDROM_SECTOR_SIZE];
+ dop.command = CMD_READ;
+ dop.lba = 0x11;
+ dop.count = 1;
+ dop.buf_fl = buffer;
+ ret = process_op(&dop);
+ if (ret)
+ return NULL;
+
+ // Is it bootable?
+ if (buffer[0])
+ return NULL;
+ if (strcmp((char*)&buffer[1], "CD001\001EL TORITO SPECIFICATION") != 0)
+ return NULL;
+
+ // Read the Primary Volume Descriptor
+ dop.command = CMD_READ;
+ dop.lba = 0x10;
+ dop.count = 1;
+ dop.buf_fl = buffer;
+ ret = process_op(&dop);
+ if (ret)
+ return NULL;
+
+ // Read volume id, trim trailing spaces
+ char *volume = znprintf(30, "%s", buffer + 40);
+ nullTrailingSpace(volume);
+ return volume;
+}
diff --git a/roms/seabios-hppa/src/clock.c b/roms/seabios-hppa/src/clock.c
new file mode 100644
index 000000000..e44e11206
--- /dev/null
+++ b/roms/seabios-hppa/src/clock.c
@@ -0,0 +1,506 @@
+// 16bit code to handle system clocks.
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#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
+#include "stacks.h" // yield
+#include "string.h" // memset
+#include "util.h" // clock_setup
+
+
+/****************************************************************
+ * Init
+ ****************************************************************/
+
+static u32
+bcd2bin(u8 val)
+{
+ return (val & 0xf) + ((val >> 4) * 10);
+}
+
+u8 Century VARLOW;
+
+void
+clock_setup(void)
+{
+ dprintf(3, "init timer\n");
+ pit_setup();
+
+ rtc_setup();
+ rtc_updating();
+ u32 seconds = bcd2bin(rtc_read(CMOS_RTC_SECONDS));
+ u32 minutes = bcd2bin(rtc_read(CMOS_RTC_MINUTES));
+ u32 hours = bcd2bin(rtc_read(CMOS_RTC_HOURS));
+ u32 ticks = ticks_from_ms(((hours * 60 + minutes) * 60 + seconds) * 1000);
+ SET_BDA(timer_counter, ticks % TICKS_PER_DAY);
+
+ // Setup Century storage
+ if (CONFIG_QEMU) {
+ Century = rtc_read(CMOS_CENTURY);
+ } else {
+ // Infer current century from the year.
+ u8 year = rtc_read(CMOS_RTC_YEAR);
+ if (year > 0x80)
+ Century = 0x19;
+ else
+ Century = 0x20;
+ }
+
+ enable_hwirq(0, FUNC16(entry_08));
+ if (CONFIG_RTC_TIMER)
+ enable_hwirq(8, FUNC16(entry_70));
+}
+
+
+/****************************************************************
+ * Standard clock functions
+ ****************************************************************/
+
+// get current clock count
+static void
+handle_1a00(struct bregs *regs)
+{
+ yield();
+ u32 ticks = GET_BDA(timer_counter);
+ regs->cx = ticks >> 16;
+ regs->dx = ticks;
+ regs->al = GET_BDA(timer_rollover);
+ SET_BDA(timer_rollover, 0); // reset flag
+ set_success(regs);
+}
+
+// Set Current Clock Count
+static void
+handle_1a01(struct bregs *regs)
+{
+ u32 ticks = (regs->cx << 16) | regs->dx;
+ SET_BDA(timer_counter, ticks);
+ SET_BDA(timer_rollover, 0); // reset flag
+ // XXX - should use set_code_success()?
+ regs->ah = 0;
+ set_success(regs);
+}
+
+// Read CMOS Time
+static void
+handle_1a02(struct bregs *regs)
+{
+ if (rtc_updating()) {
+ set_invalid(regs);
+ return;
+ }
+
+ regs->dh = rtc_read(CMOS_RTC_SECONDS);
+ regs->cl = rtc_read(CMOS_RTC_MINUTES);
+ regs->ch = rtc_read(CMOS_RTC_HOURS);
+ regs->dl = rtc_read(CMOS_STATUS_B) & RTC_B_DSE;
+ regs->ah = 0;
+ regs->al = regs->ch;
+ set_success(regs);
+}
+
+// Set CMOS Time
+static void
+handle_1a03(struct bregs *regs)
+{
+ // Using a debugger, I notice the following masking/setting
+ // of bits in Status Register B, by setting Reg B to
+ // a few values and getting its value after INT 1A was called.
+ //
+ // try#1 try#2 try#3
+ // before 1111 1101 0111 1101 0000 0000
+ // after 0110 0010 0110 0010 0000 0010
+ //
+ // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+ // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
+ if (rtc_updating()) {
+ rtc_setup();
+ // fall through as if an update were not in progress
+ }
+ rtc_write(CMOS_RTC_SECONDS, regs->dh);
+ rtc_write(CMOS_RTC_MINUTES, regs->cl);
+ rtc_write(CMOS_RTC_HOURS, regs->ch);
+ // Set Daylight Savings time enabled bit to requested value
+ u8 val8 = ((rtc_read(CMOS_STATUS_B) & (RTC_B_PIE|RTC_B_AIE))
+ | RTC_B_24HR | (regs->dl & RTC_B_DSE));
+ rtc_write(CMOS_STATUS_B, val8);
+ regs->ah = 0;
+ regs->al = val8; // val last written to Reg B
+ set_success(regs);
+}
+
+// Read CMOS Date
+static void
+handle_1a04(struct bregs *regs)
+{
+ regs->ah = 0;
+ if (rtc_updating()) {
+ set_invalid(regs);
+ return;
+ }
+ regs->cl = rtc_read(CMOS_RTC_YEAR);
+ regs->dh = rtc_read(CMOS_RTC_MONTH);
+ regs->dl = rtc_read(CMOS_RTC_DAY_MONTH);
+ regs->ch = GET_LOW(Century);
+ regs->al = regs->ch;
+ set_success(regs);
+}
+
+// Set CMOS Date
+static void
+handle_1a05(struct bregs *regs)
+{
+ // Using a debugger, I notice the following masking/setting
+ // of bits in Status Register B, by setting Reg B to
+ // a few values and getting its value after INT 1A was called.
+ //
+ // try#1 try#2 try#3 try#4
+ // before 1111 1101 0111 1101 0000 0010 0000 0000
+ // after 0110 1101 0111 1101 0000 0010 0000 0000
+ //
+ // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+ // My assumption: RegB = (RegB & 01111111b)
+ if (rtc_updating()) {
+ rtc_setup();
+ set_invalid(regs);
+ return;
+ }
+ rtc_write(CMOS_RTC_YEAR, regs->cl);
+ rtc_write(CMOS_RTC_MONTH, regs->dh);
+ rtc_write(CMOS_RTC_DAY_MONTH, regs->dl);
+ SET_LOW(Century, regs->ch);
+ // clear halt-clock bit
+ u8 val8 = rtc_read(CMOS_STATUS_B) & ~RTC_B_SET;
+ rtc_write(CMOS_STATUS_B, val8);
+ regs->ah = 0;
+ regs->al = val8; // AL = val last written to Reg B
+ set_success(regs);
+}
+
+// Set Alarm Time in CMOS
+static void
+handle_1a06(struct bregs *regs)
+{
+ // Using a debugger, I notice the following masking/setting
+ // of bits in Status Register B, by setting Reg B to
+ // a few values and getting its value after INT 1A was called.
+ //
+ // try#1 try#2 try#3
+ // before 1101 1111 0101 1111 0000 0000
+ // after 0110 1111 0111 1111 0010 0000
+ //
+ // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+ // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
+ u8 val8 = rtc_read(CMOS_STATUS_B); // Get Status Reg B
+ regs->ax = 0;
+ if (val8 & RTC_B_AIE) {
+ // Alarm interrupt enabled already
+ set_invalid(regs);
+ return;
+ }
+ if (rtc_updating()) {
+ rtc_setup();
+ // fall through as if an update were not in progress
+ }
+ rtc_write(CMOS_RTC_SECONDS_ALARM, regs->dh);
+ rtc_write(CMOS_RTC_MINUTES_ALARM, regs->cl);
+ rtc_write(CMOS_RTC_HOURS_ALARM, regs->ch);
+ // enable Status Reg B alarm bit, clear halt clock bit
+ rtc_write(CMOS_STATUS_B, (val8 & ~RTC_B_SET) | RTC_B_AIE);
+ set_success(regs);
+}
+
+// Turn off Alarm
+static void
+handle_1a07(struct bregs *regs)
+{
+ // Using a debugger, I notice the following masking/setting
+ // of bits in Status Register B, by setting Reg B to
+ // a few values and getting its value after INT 1A was called.
+ //
+ // try#1 try#2 try#3 try#4
+ // before 1111 1101 0111 1101 0010 0000 0010 0010
+ // after 0100 0101 0101 0101 0000 0000 0000 0010
+ //
+ // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+ // My assumption: RegB = (RegB & 01010111b)
+ u8 val8 = rtc_read(CMOS_STATUS_B); // Get Status Reg B
+ // clear clock-halt bit, disable alarm bit
+ rtc_write(CMOS_STATUS_B, val8 & ~(RTC_B_SET|RTC_B_AIE));
+ regs->ah = 0;
+ regs->al = val8; // val last written to Reg B
+ 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)
+{
+ set_unimplemented(regs);
+}
+
+// INT 1Ah Time-of-day Service Entry Point
+void VISIBLE16
+handle_1a(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_1a);
+ switch (regs->ah) {
+ case 0x00: handle_1a00(regs); break;
+ case 0x01: handle_1a01(regs); break;
+ case 0x02: handle_1a02(regs); break;
+ case 0x03: handle_1a03(regs); break;
+ case 0x04: handle_1a04(regs); break;
+ 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;
+ }
+}
+
+// Update main tick counter
+static void
+clock_update(void)
+{
+ u32 counter = GET_BDA(timer_counter);
+ counter++;
+ // compare to one days worth of timer ticks at 18.2 hz
+ if (counter >= TICKS_PER_DAY) {
+ // there has been a midnight rollover at this point
+ counter = 0;
+ SET_BDA(timer_rollover, GET_BDA(timer_rollover) + 1);
+ }
+ SET_BDA(timer_counter, counter);
+
+ // Check for internal events.
+ floppy_tick();
+ usb_check_event();
+ ps2_check_event();
+ sercon_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;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ call16_int(0x1c, &br);
+
+ 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
+ ****************************************************************/
+
+// Calculate the timer value at 'count' number of full timer ticks in
+// the future.
+u32
+irqtimer_calc_ticks(u32 count)
+{
+ return (GET_BDA(timer_counter) + count + 1) % TICKS_PER_DAY;
+}
+
+// Return the timer value that is 'msecs' time in the future.
+u32
+irqtimer_calc(u32 msecs)
+{
+ if (!msecs)
+ return GET_BDA(timer_counter);
+ return irqtimer_calc_ticks(ticks_from_ms(msecs));
+}
+
+// Check if the given timer value has passed.
+int
+irqtimer_check(u32 end)
+{
+ return (((GET_BDA(timer_counter) + TICKS_PER_DAY - end) % TICKS_PER_DAY)
+ < (TICKS_PER_DAY/2));
+}
+
+
+/****************************************************************
+ * Periodic timer
+ ****************************************************************/
+
+static int
+set_usertimer(u32 usecs, u16 seg, u16 offset)
+{
+ if (GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING)
+ return -1;
+
+ // Interval not already set.
+ SET_BDA(rtc_wait_flag, RWS_WAIT_PENDING); // Set status byte.
+ SET_BDA(user_wait_complete_flag, SEGOFF(seg, offset));
+ SET_BDA(user_wait_timeout, usecs);
+ rtc_use();
+ return 0;
+}
+
+static void
+clear_usertimer(void)
+{
+ if (!(GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING))
+ return;
+ // Turn off status byte.
+ SET_BDA(rtc_wait_flag, 0);
+ rtc_release();
+}
+
+#define RET_ECLOCKINUSE 0x83
+
+// Wait for CX:DX microseconds
+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;
+ int ret = set_usertimer(count, GET_SEG(SS), (u32)&statusflag);
+ if (ret) {
+ set_code_invalid(regs, RET_ECLOCKINUSE);
+ return;
+ }
+ while (!statusflag)
+ yield_toirq();
+ set_success(regs);
+}
+
+// Set Interval requested.
+static void
+handle_158300(struct bregs *regs)
+{
+ int ret = set_usertimer((regs->cx << 16) | regs->dx, regs->es, regs->bx);
+ if (ret)
+ // Interval already set.
+ set_code_invalid(regs, RET_EUNSUPPORTED);
+ else
+ set_success(regs);
+}
+
+// Clear interval requested
+static void
+handle_158301(struct bregs *regs)
+{
+ clear_usertimer();
+ set_success(regs);
+}
+
+static void
+handle_1583XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EUNSUPPORTED);
+ regs->al--;
+}
+
+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;
+ default: handle_1583XX(regs); break;
+ }
+}
+
+#define USEC_PER_RTC DIV_ROUND_CLOSEST(1000000, 1024)
+
+// int70h: IRQ8 - CMOS RTC
+void VISIBLE16
+handle_70(void)
+{
+ if (!CONFIG_RTC_TIMER)
+ return;
+ debug_isr(DEBUG_ISR_70);
+
+ // Check which modes are enabled and have occurred.
+ u8 registerB = rtc_read(CMOS_STATUS_B);
+ u8 registerC = rtc_read(CMOS_STATUS_C);
+
+ if (!(registerB & (RTC_B_PIE|RTC_B_AIE)))
+ goto done;
+ if (registerC & RTC_B_AIE) {
+ // Handle Alarm Interrupt.
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ call16_int(0x4a, &br);
+ }
+ if (!(registerC & RTC_B_PIE))
+ goto done;
+
+ // Handle Periodic Interrupt.
+
+ check_preempt();
+
+ if (!GET_BDA(rtc_wait_flag))
+ goto done;
+
+ // Wait Interval (Int 15, AH=83) active.
+ u32 time = GET_BDA(user_wait_timeout); // Time left in microseconds.
+ if (time < USEC_PER_RTC) {
+ // Done waiting - write to specified flag byte.
+ struct segoff_s segoff = GET_BDA(user_wait_complete_flag);
+ u16 ptr_seg = segoff.seg;
+ u8 *ptr_far = (u8*)(segoff.offset+0);
+ u8 oldval = GET_FARVAR(ptr_seg, *ptr_far);
+ SET_FARVAR(ptr_seg, *ptr_far, oldval | 0x80);
+
+ clear_usertimer();
+ } else {
+ // Continue waiting.
+ time -= USEC_PER_RTC;
+ SET_BDA(user_wait_timeout, time);
+ }
+
+done:
+ pic_eoi2();
+}
diff --git a/roms/seabios-hppa/src/code16gcc.s b/roms/seabios-hppa/src/code16gcc.s
new file mode 100644
index 000000000..8f7121b87
--- /dev/null
+++ b/roms/seabios-hppa/src/code16gcc.s
@@ -0,0 +1 @@
+.code16gcc
diff --git a/roms/seabios-hppa/src/config.h b/roms/seabios-hppa/src/config.h
new file mode 100644
index 000000000..93c8dbc2d
--- /dev/null
+++ b/roms/seabios-hppa/src/config.h
@@ -0,0 +1,108 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include "autoconf.h"
+
+// Configuration definitions.
+
+//#define BUILD_APPNAME "QEMU"
+//#define BUILD_CPUNAME8 "QEMUCPU "
+//#define BUILD_APPNAME6 "QEMU "
+//#define BUILD_APPNAME4 "QEMU"
+#define BUILD_APPNAME "Bochs"
+#define BUILD_CPUNAME8 "BOCHSCPU"
+#define BUILD_APPNAME6 "BOCHS "
+#define BUILD_APPNAME4 "BXPC"
+
+// Maximum number of map entries in the e820 map
+#define BUILD_MAX_E820 32
+// Space to reserve in high-memory for tables
+#define BUILD_MAX_HIGHTABLE (256*1024)
+// Largest supported externaly facing drive id
+#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
+#define BUILD_BIOS_REVISION 0x01
+
+// Various memory addresses used by the code.
+#define BUILD_STACK_ADDR 0x7000
+#define BUILD_S3RESUME_STACK_ADDR 0x1000
+#define BUILD_AP_BOOT_ADDR 0x10000
+#define BUILD_EBDA_MINIMUM 0x90000
+#define BUILD_LOWRAM_END 0xa0000
+#define BUILD_ROM_START 0xc0000
+#define BUILD_BIOS_ADDR 0xf0000
+#define BUILD_BIOS_SIZE 0x10000
+#define BUILD_EXTRA_STACK_SIZE 0x800
+#define BUILD_SMM_INIT_ADDR 0x30000
+#define BUILD_SMM_ADDR 0xa0000
+
+#define BUILD_PCIMEM_START 0xe0000000
+#define BUILD_PCIMEM_END 0xfec00000 /* IOAPIC is mapped at */
+#define BUILD_PCIMEM64_START 0x8000000000ULL
+#define BUILD_PCIMEM64_END 0x10000000000ULL
+
+#define BUILD_IOAPIC_ADDR 0xfec00000
+#define BUILD_IOAPIC_ID 0
+#define BUILD_HPET_ADDRESS 0xfed00000
+#define BUILD_APIC_ADDR 0xfee00000
+
+// PCI IRQS
+#define BUILD_PCI_IRQS ((1<<5) | (1<<9) | (1<<10) | (1<<11))
+
+// Important real-mode segments
+#define SEG_IVT 0x0000
+#define SEG_BDA 0x0040
+#define SEG_BIOS 0xf000
+
+// Segment definitions in protected mode (see rombios32_gdt in misc.c)
+#define SEG32_MODE32_CS (1 << 3)
+#define SEG32_MODE32_DS (2 << 3)
+#define SEG32_MODE16_CS (3 << 3)
+#define SEG32_MODE16_DS (4 << 3)
+#define SEG32_MODE16BIG_CS (5 << 3)
+#define SEG32_MODE16BIG_DS (6 << 3)
+
+// Debugging levels. If non-zero and CONFIG_DEBUG_LEVEL is greater
+// than the specified value, then the corresponding irq handler will
+// report every enter event.
+#define DEBUG_ISR_02 1
+#define DEBUG_HDL_05 1
+#define DEBUG_ISR_08 20
+#define DEBUG_ISR_09 9
+#define DEBUG_ISR_0e 9
+#define DEBUG_HDL_11 2
+#define DEBUG_HDL_12 2
+#define DEBUG_HDL_13 10
+#define DEBUG_HDL_14 2
+#define DEBUG_HDL_15 9
+#define DEBUG_HDL_16 9
+#define DEBUG_HDL_17 2
+#define DEBUG_HDL_18 1
+#define DEBUG_HDL_19 1
+#define DEBUG_HDL_1a 9
+#define DEBUG_HDL_40 1
+#define DEBUG_ISR_70 9
+#define DEBUG_ISR_74 9
+#define DEBUG_ISR_75 1
+#define DEBUG_ISR_76 10
+#define DEBUG_ISR_hwpic1 5
+#define DEBUG_ISR_hwpic2 5
+#define DEBUG_HDL_smi 9
+#define DEBUG_HDL_smp 1
+#define DEBUG_HDL_pnp 1
+#define DEBUG_HDL_pmm 1
+#define DEBUG_HDL_pcibios 9
+#define DEBUG_HDL_apm 9
+
+#define DEBUG_unimplemented 2
+#define DEBUG_invalid 3
+#define DEBUG_thread 2
+#define DEBUG_tcg 20
+
+#endif // config.h
diff --git a/roms/seabios-hppa/src/cp437.c b/roms/seabios-hppa/src/cp437.c
new file mode 100644
index 000000000..719872f57
--- /dev/null
+++ b/roms/seabios-hppa/src/cp437.c
@@ -0,0 +1,277 @@
+/*
+ * code page 437 to unicode map
+ *
+ * This file may be distributed under the terms of the GNU LGPLv3 license.
+ */
+
+#include "types.h"
+#include "biosvar.h"
+#include "cp437.h"
+
+static VAR16 u16 cp437_to_unicode_map[256] = {
+
+ /* https://en.wikipedia.org/wiki/Code_page_437 */
+ [ 0x00 ] = 0x0000,
+ [ 0x01 ] = 0x263A,
+ [ 0x02 ] = 0x263B,
+ [ 0x03 ] = 0x2665,
+ [ 0x04 ] = 0x2666,
+ [ 0x05 ] = 0x2663,
+ [ 0x06 ] = 0x2660,
+ [ 0x07 ] = 0x2022,
+ [ 0x08 ] = 0x25D8,
+ [ 0x09 ] = 0x25CB,
+ [ 0x0a ] = 0x25D9,
+ [ 0x0b ] = 0x2642,
+ [ 0x0c ] = 0x2640,
+ [ 0x0d ] = 0x266A,
+ [ 0x0e ] = 0x266B,
+ [ 0x0f ] = 0x263C,
+ [ 0x10 ] = 0x25BA,
+ [ 0x11 ] = 0x25C4,
+ [ 0x12 ] = 0x2195,
+ [ 0x13 ] = 0x203C,
+ [ 0x14 ] = 0x00B6,
+ [ 0x15 ] = 0x00A7,
+ [ 0x16 ] = 0x25AC,
+ [ 0x17 ] = 0x21A8,
+ [ 0x18 ] = 0x2191,
+ [ 0x19 ] = 0x2193,
+ [ 0x1a ] = 0x2192,
+ [ 0x1b ] = 0x2190,
+ [ 0x1c ] = 0x221F,
+ [ 0x1d ] = 0x2194,
+ [ 0x1e ] = 0x25B2,
+ [ 0x1f ] = 0x25BC,
+ [ 0x7f ] = 0x2302,
+
+ /* http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP437.TXT */
+ [ 0x20 ] = 0x0020, // SPACE
+ [ 0x21 ] = 0x0021, // EXCLAMATION MARK
+ [ 0x22 ] = 0x0022, // QUOTATION MARK
+ [ 0x23 ] = 0x0023, // NUMBER SIGN
+ [ 0x24 ] = 0x0024, // DOLLAR SIGN
+ [ 0x25 ] = 0x0025, // PERCENT SIGN
+ [ 0x26 ] = 0x0026, // AMPERSAND
+ [ 0x27 ] = 0x0027, // APOSTROPHE
+ [ 0x28 ] = 0x0028, // LEFT PARENTHESIS
+ [ 0x29 ] = 0x0029, // RIGHT PARENTHESIS
+ [ 0x2a ] = 0x002a, // ASTERISK
+ [ 0x2b ] = 0x002b, // PLUS SIGN
+ [ 0x2c ] = 0x002c, // COMMA
+ [ 0x2d ] = 0x002d, // HYPHEN-MINUS
+ [ 0x2e ] = 0x002e, // FULL STOP
+ [ 0x2f ] = 0x002f, // SOLIDUS
+ [ 0x30 ] = 0x0030, // DIGIT ZERO
+ [ 0x31 ] = 0x0031, // DIGIT ONE
+ [ 0x32 ] = 0x0032, // DIGIT TWO
+ [ 0x33 ] = 0x0033, // DIGIT THREE
+ [ 0x34 ] = 0x0034, // DIGIT FOUR
+ [ 0x35 ] = 0x0035, // DIGIT FIVE
+ [ 0x36 ] = 0x0036, // DIGIT SIX
+ [ 0x37 ] = 0x0037, // DIGIT SEVEN
+ [ 0x38 ] = 0x0038, // DIGIT EIGHT
+ [ 0x39 ] = 0x0039, // DIGIT NINE
+ [ 0x3a ] = 0x003a, // COLON
+ [ 0x3b ] = 0x003b, // SEMICOLON
+ [ 0x3c ] = 0x003c, // LESS-THAN SIGN
+ [ 0x3d ] = 0x003d, // EQUALS SIGN
+ [ 0x3e ] = 0x003e, // GREATER-THAN SIGN
+ [ 0x3f ] = 0x003f, // QUESTION MARK
+ [ 0x40 ] = 0x0040, // COMMERCIAL AT
+ [ 0x41 ] = 0x0041, // LATIN CAPITAL LETTER A
+ [ 0x42 ] = 0x0042, // LATIN CAPITAL LETTER B
+ [ 0x43 ] = 0x0043, // LATIN CAPITAL LETTER C
+ [ 0x44 ] = 0x0044, // LATIN CAPITAL LETTER D
+ [ 0x45 ] = 0x0045, // LATIN CAPITAL LETTER E
+ [ 0x46 ] = 0x0046, // LATIN CAPITAL LETTER F
+ [ 0x47 ] = 0x0047, // LATIN CAPITAL LETTER G
+ [ 0x48 ] = 0x0048, // LATIN CAPITAL LETTER H
+ [ 0x49 ] = 0x0049, // LATIN CAPITAL LETTER I
+ [ 0x4a ] = 0x004a, // LATIN CAPITAL LETTER J
+ [ 0x4b ] = 0x004b, // LATIN CAPITAL LETTER K
+ [ 0x4c ] = 0x004c, // LATIN CAPITAL LETTER L
+ [ 0x4d ] = 0x004d, // LATIN CAPITAL LETTER M
+ [ 0x4e ] = 0x004e, // LATIN CAPITAL LETTER N
+ [ 0x4f ] = 0x004f, // LATIN CAPITAL LETTER O
+ [ 0x50 ] = 0x0050, // LATIN CAPITAL LETTER P
+ [ 0x51 ] = 0x0051, // LATIN CAPITAL LETTER Q
+ [ 0x52 ] = 0x0052, // LATIN CAPITAL LETTER R
+ [ 0x53 ] = 0x0053, // LATIN CAPITAL LETTER S
+ [ 0x54 ] = 0x0054, // LATIN CAPITAL LETTER T
+ [ 0x55 ] = 0x0055, // LATIN CAPITAL LETTER U
+ [ 0x56 ] = 0x0056, // LATIN CAPITAL LETTER V
+ [ 0x57 ] = 0x0057, // LATIN CAPITAL LETTER W
+ [ 0x58 ] = 0x0058, // LATIN CAPITAL LETTER X
+ [ 0x59 ] = 0x0059, // LATIN CAPITAL LETTER Y
+ [ 0x5a ] = 0x005a, // LATIN CAPITAL LETTER Z
+ [ 0x5b ] = 0x005b, // LEFT SQUARE BRACKET
+ [ 0x5c ] = 0x005c, // REVERSE SOLIDUS
+ [ 0x5d ] = 0x005d, // RIGHT SQUARE BRACKET
+ [ 0x5e ] = 0x005e, // CIRCUMFLEX ACCENT
+ [ 0x5f ] = 0x005f, // LOW LINE
+ [ 0x60 ] = 0x0060, // GRAVE ACCENT
+ [ 0x61 ] = 0x0061, // LATIN SMALL LETTER A
+ [ 0x62 ] = 0x0062, // LATIN SMALL LETTER B
+ [ 0x63 ] = 0x0063, // LATIN SMALL LETTER C
+ [ 0x64 ] = 0x0064, // LATIN SMALL LETTER D
+ [ 0x65 ] = 0x0065, // LATIN SMALL LETTER E
+ [ 0x66 ] = 0x0066, // LATIN SMALL LETTER F
+ [ 0x67 ] = 0x0067, // LATIN SMALL LETTER G
+ [ 0x68 ] = 0x0068, // LATIN SMALL LETTER H
+ [ 0x69 ] = 0x0069, // LATIN SMALL LETTER I
+ [ 0x6a ] = 0x006a, // LATIN SMALL LETTER J
+ [ 0x6b ] = 0x006b, // LATIN SMALL LETTER K
+ [ 0x6c ] = 0x006c, // LATIN SMALL LETTER L
+ [ 0x6d ] = 0x006d, // LATIN SMALL LETTER M
+ [ 0x6e ] = 0x006e, // LATIN SMALL LETTER N
+ [ 0x6f ] = 0x006f, // LATIN SMALL LETTER O
+ [ 0x70 ] = 0x0070, // LATIN SMALL LETTER P
+ [ 0x71 ] = 0x0071, // LATIN SMALL LETTER Q
+ [ 0x72 ] = 0x0072, // LATIN SMALL LETTER R
+ [ 0x73 ] = 0x0073, // LATIN SMALL LETTER S
+ [ 0x74 ] = 0x0074, // LATIN SMALL LETTER T
+ [ 0x75 ] = 0x0075, // LATIN SMALL LETTER U
+ [ 0x76 ] = 0x0076, // LATIN SMALL LETTER V
+ [ 0x77 ] = 0x0077, // LATIN SMALL LETTER W
+ [ 0x78 ] = 0x0078, // LATIN SMALL LETTER X
+ [ 0x79 ] = 0x0079, // LATIN SMALL LETTER Y
+ [ 0x7a ] = 0x007a, // LATIN SMALL LETTER Z
+ [ 0x7b ] = 0x007b, // LEFT CURLY BRACKET
+ [ 0x7c ] = 0x007c, // VERTICAL LINE
+ [ 0x7d ] = 0x007d, // RIGHT CURLY BRACKET
+ [ 0x7e ] = 0x007e, // TILDE
+ [ 0x80 ] = 0x00c7, // LATIN CAPITAL LETTER C WITH CEDILLA
+ [ 0x81 ] = 0x00fc, // LATIN SMALL LETTER U WITH DIAERESIS
+ [ 0x82 ] = 0x00e9, // LATIN SMALL LETTER E WITH ACUTE
+ [ 0x83 ] = 0x00e2, // LATIN SMALL LETTER A WITH CIRCUMFLEX
+ [ 0x84 ] = 0x00e4, // LATIN SMALL LETTER A WITH DIAERESIS
+ [ 0x85 ] = 0x00e0, // LATIN SMALL LETTER A WITH GRAVE
+ [ 0x86 ] = 0x00e5, // LATIN SMALL LETTER A WITH RING ABOVE
+ [ 0x87 ] = 0x00e7, // LATIN SMALL LETTER C WITH CEDILLA
+ [ 0x88 ] = 0x00ea, // LATIN SMALL LETTER E WITH CIRCUMFLEX
+ [ 0x89 ] = 0x00eb, // LATIN SMALL LETTER E WITH DIAERESIS
+ [ 0x8a ] = 0x00e8, // LATIN SMALL LETTER E WITH GRAVE
+ [ 0x8b ] = 0x00ef, // LATIN SMALL LETTER I WITH DIAERESIS
+ [ 0x8c ] = 0x00ee, // LATIN SMALL LETTER I WITH CIRCUMFLEX
+ [ 0x8d ] = 0x00ec, // LATIN SMALL LETTER I WITH GRAVE
+ [ 0x8e ] = 0x00c4, // LATIN CAPITAL LETTER A WITH DIAERESIS
+ [ 0x8f ] = 0x00c5, // LATIN CAPITAL LETTER A WITH RING ABOVE
+ [ 0x90 ] = 0x00c9, // LATIN CAPITAL LETTER E WITH ACUTE
+ [ 0x91 ] = 0x00e6, // LATIN SMALL LIGATURE AE
+ [ 0x92 ] = 0x00c6, // LATIN CAPITAL LIGATURE AE
+ [ 0x93 ] = 0x00f4, // LATIN SMALL LETTER O WITH CIRCUMFLEX
+ [ 0x94 ] = 0x00f6, // LATIN SMALL LETTER O WITH DIAERESIS
+ [ 0x95 ] = 0x00f2, // LATIN SMALL LETTER O WITH GRAVE
+ [ 0x96 ] = 0x00fb, // LATIN SMALL LETTER U WITH CIRCUMFLEX
+ [ 0x97 ] = 0x00f9, // LATIN SMALL LETTER U WITH GRAVE
+ [ 0x98 ] = 0x00ff, // LATIN SMALL LETTER Y WITH DIAERESIS
+ [ 0x99 ] = 0x00d6, // LATIN CAPITAL LETTER O WITH DIAERESIS
+ [ 0x9a ] = 0x00dc, // LATIN CAPITAL LETTER U WITH DIAERESIS
+ [ 0x9b ] = 0x00a2, // CENT SIGN
+ [ 0x9c ] = 0x00a3, // POUND SIGN
+ [ 0x9d ] = 0x00a5, // YEN SIGN
+ [ 0x9e ] = 0x20a7, // PESETA SIGN
+ [ 0x9f ] = 0x0192, // LATIN SMALL LETTER F WITH HOOK
+ [ 0xa0 ] = 0x00e1, // LATIN SMALL LETTER A WITH ACUTE
+ [ 0xa1 ] = 0x00ed, // LATIN SMALL LETTER I WITH ACUTE
+ [ 0xa2 ] = 0x00f3, // LATIN SMALL LETTER O WITH ACUTE
+ [ 0xa3 ] = 0x00fa, // LATIN SMALL LETTER U WITH ACUTE
+ [ 0xa4 ] = 0x00f1, // LATIN SMALL LETTER N WITH TILDE
+ [ 0xa5 ] = 0x00d1, // LATIN CAPITAL LETTER N WITH TILDE
+ [ 0xa6 ] = 0x00aa, // FEMININE ORDINAL INDICATOR
+ [ 0xa7 ] = 0x00ba, // MASCULINE ORDINAL INDICATOR
+ [ 0xa8 ] = 0x00bf, // INVERTED QUESTION MARK
+ [ 0xa9 ] = 0x2310, // REVERSED NOT SIGN
+ [ 0xaa ] = 0x00ac, // NOT SIGN
+ [ 0xab ] = 0x00bd, // VULGAR FRACTION ONE HALF
+ [ 0xac ] = 0x00bc, // VULGAR FRACTION ONE QUARTER
+ [ 0xad ] = 0x00a1, // INVERTED EXCLAMATION MARK
+ [ 0xae ] = 0x00ab, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ [ 0xaf ] = 0x00bb, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ [ 0xb0 ] = 0x2591, // LIGHT SHADE
+ [ 0xb1 ] = 0x2592, // MEDIUM SHADE
+ [ 0xb2 ] = 0x2593, // DARK SHADE
+ [ 0xb3 ] = 0x2502, // BOX DRAWINGS LIGHT VERTICAL
+ [ 0xb4 ] = 0x2524, // BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ [ 0xb5 ] = 0x2561, // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ [ 0xb6 ] = 0x2562, // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ [ 0xb7 ] = 0x2556, // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ [ 0xb8 ] = 0x2555, // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ [ 0xb9 ] = 0x2563, // BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ [ 0xba ] = 0x2551, // BOX DRAWINGS DOUBLE VERTICAL
+ [ 0xbb ] = 0x2557, // BOX DRAWINGS DOUBLE DOWN AND LEFT
+ [ 0xbc ] = 0x255d, // BOX DRAWINGS DOUBLE UP AND LEFT
+ [ 0xbd ] = 0x255c, // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ [ 0xbe ] = 0x255b, // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ [ 0xbf ] = 0x2510, // BOX DRAWINGS LIGHT DOWN AND LEFT
+ [ 0xc0 ] = 0x2514, // BOX DRAWINGS LIGHT UP AND RIGHT
+ [ 0xc1 ] = 0x2534, // BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ [ 0xc2 ] = 0x252c, // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ [ 0xc3 ] = 0x251c, // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ [ 0xc4 ] = 0x2500, // BOX DRAWINGS LIGHT HORIZONTAL
+ [ 0xc5 ] = 0x253c, // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ [ 0xc6 ] = 0x255e, // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ [ 0xc7 ] = 0x255f, // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ [ 0xc8 ] = 0x255a, // BOX DRAWINGS DOUBLE UP AND RIGHT
+ [ 0xc9 ] = 0x2554, // BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ [ 0xca ] = 0x2569, // BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ [ 0xcb ] = 0x2566, // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ [ 0xcc ] = 0x2560, // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+ [ 0xcd ] = 0x2550, // BOX DRAWINGS DOUBLE HORIZONTAL
+ [ 0xce ] = 0x256c, // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ [ 0xcf ] = 0x2567, // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ [ 0xd0 ] = 0x2568, // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ [ 0xd1 ] = 0x2564, // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ [ 0xd2 ] = 0x2565, // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ [ 0xd3 ] = 0x2559, // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ [ 0xd4 ] = 0x2558, // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ [ 0xd5 ] = 0x2552, // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ [ 0xd6 ] = 0x2553, // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ [ 0xd7 ] = 0x256b, // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ [ 0xd8 ] = 0x256a, // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ [ 0xd9 ] = 0x2518, // BOX DRAWINGS LIGHT UP AND LEFT
+ [ 0xda ] = 0x250c, // BOX DRAWINGS LIGHT DOWN AND RIGHT
+ [ 0xdb ] = 0x2588, // FULL BLOCK
+ [ 0xdc ] = 0x2584, // LOWER HALF BLOCK
+ [ 0xdd ] = 0x258c, // LEFT HALF BLOCK
+ [ 0xde ] = 0x2590, // RIGHT HALF BLOCK
+ [ 0xdf ] = 0x2580, // UPPER HALF BLOCK
+ [ 0xe0 ] = 0x03b1, // GREEK SMALL LETTER ALPHA
+ [ 0xe1 ] = 0x00df, // LATIN SMALL LETTER SHARP S
+ [ 0xe2 ] = 0x0393, // GREEK CAPITAL LETTER GAMMA
+ [ 0xe3 ] = 0x03c0, // GREEK SMALL LETTER PI
+ [ 0xe4 ] = 0x03a3, // GREEK CAPITAL LETTER SIGMA
+ [ 0xe5 ] = 0x03c3, // GREEK SMALL LETTER SIGMA
+ [ 0xe6 ] = 0x00b5, // MICRO SIGN
+ [ 0xe7 ] = 0x03c4, // GREEK SMALL LETTER TAU
+ [ 0xe8 ] = 0x03a6, // GREEK CAPITAL LETTER PHI
+ [ 0xe9 ] = 0x0398, // GREEK CAPITAL LETTER THETA
+ [ 0xea ] = 0x03a9, // GREEK CAPITAL LETTER OMEGA
+ [ 0xeb ] = 0x03b4, // GREEK SMALL LETTER DELTA
+ [ 0xec ] = 0x221e, // INFINITY
+ [ 0xed ] = 0x03c6, // GREEK SMALL LETTER PHI
+ [ 0xee ] = 0x03b5, // GREEK SMALL LETTER EPSILON
+ [ 0xef ] = 0x2229, // INTERSECTION
+ [ 0xf0 ] = 0x2261, // IDENTICAL TO
+ [ 0xf1 ] = 0x00b1, // PLUS-MINUS SIGN
+ [ 0xf2 ] = 0x2265, // GREATER-THAN OR EQUAL TO
+ [ 0xf3 ] = 0x2264, // LESS-THAN OR EQUAL TO
+ [ 0xf4 ] = 0x2320, // TOP HALF INTEGRAL
+ [ 0xf5 ] = 0x2321, // BOTTOM HALF INTEGRAL
+ [ 0xf6 ] = 0x00f7, // DIVISION SIGN
+ [ 0xf7 ] = 0x2248, // ALMOST EQUAL TO
+ [ 0xf8 ] = 0x00b0, // DEGREE SIGN
+ [ 0xf9 ] = 0x2219, // BULLET OPERATOR
+ [ 0xfa ] = 0x00b7, // MIDDLE DOT
+ [ 0xfb ] = 0x221a, // SQUARE ROOT
+ [ 0xfc ] = 0x207f, // SUPERSCRIPT LATIN SMALL LETTER N
+ [ 0xfd ] = 0x00b2, // SUPERSCRIPT TWO
+ [ 0xfe ] = 0x25a0, // BLACK SQUARE
+ [ 0xff ] = 0x00a0, // NO-BREAK SPACE
+};
+
+u16 cp437_to_unicode(u8 cp437)
+{
+ return GET_GLOBAL(cp437_to_unicode_map[cp437]);
+}
diff --git a/roms/seabios-hppa/src/cp437.h b/roms/seabios-hppa/src/cp437.h
new file mode 100644
index 000000000..7bd1ef152
--- /dev/null
+++ b/roms/seabios-hppa/src/cp437.h
@@ -0,0 +1 @@
+u16 cp437_to_unicode(u8 cp437);
diff --git a/roms/seabios-hppa/src/disk.c b/roms/seabios-hppa/src/disk.c
new file mode 100644
index 000000000..0328fbd1a
--- /dev/null
+++ b/roms/seabios-hppa/src/disk.c
@@ -0,0 +1,779 @@
+// 16bit code to access hard drives.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // SET_BDA
+#include "bregs.h" // struct bregs
+#include "config.h" // CONFIG_*
+#include "hw/ata.h" // ATA_CB_DC
+#include "hw/pic.h" // pic_eoi2
+#include "output.h" // debug_enter
+#include "stacks.h" // call16_int
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // CDRom_locks
+
+
+/****************************************************************
+ * Return status functions
+ ****************************************************************/
+
+static void
+__disk_ret(struct bregs *regs, u32 linecode, const char *fname)
+{
+ u8 code = linecode;
+ if (regs->dl < EXTSTART_HD)
+ SET_BDA(floppy_last_status, code);
+ else
+ SET_BDA(disk_last_status, code);
+ if (code)
+ __set_code_invalid(regs, linecode, fname);
+ else
+ set_code_success(regs);
+}
+
+static void
+__disk_ret_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
+{
+ u8 code = linecode;
+ if (regs->dl < EXTSTART_HD)
+ SET_BDA(floppy_last_status, code);
+ else
+ SET_BDA(disk_last_status, code);
+ __set_code_unimplemented(regs, linecode, fname);
+}
+
+static void
+__disk_stub(struct bregs *regs, int lineno, const char *fname)
+{
+ __warn_unimplemented(regs, lineno, fname);
+ __disk_ret(regs, DISK_RET_SUCCESS | (lineno << 8), fname);
+}
+
+#define disk_ret(regs, code) \
+ __disk_ret((regs), (code) | (__LINE__ << 8), __func__)
+#define disk_ret_unimplemented(regs, code) \
+ __disk_ret_unimplemented((regs), (code) | (__LINE__ << 8), __func__)
+#define DISK_STUB(regs) \
+ __disk_stub((regs), __LINE__, __func__)
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Get the cylinders/heads/sectors for the given drive.
+static struct chs_s
+getLCHS(struct drive_s *drive_fl)
+{
+ struct chs_s res = { };
+ if (CONFIG_CDROM_EMU && drive_fl == GET_GLOBAL(cdemu_drive_gf)) {
+ // Emulated drive - get info from CDEmu. (It's not possible to
+ // populate the geometry directly in the driveid because the
+ // geometry is only known after the bios segment is made
+ // read-only).
+ u8 sptcyl = GET_LOW(CDEmu.chs.sptcyl);
+ res.cylinder = GET_LOW(CDEmu.chs.cyllow) + ((sptcyl << 2) & 0x300) + 1;
+ res.head = GET_LOW(CDEmu.chs.heads) + 1;
+ res.sector = sptcyl & 0x3f;
+ return res;
+ }
+ res.cylinder = GET_FLATPTR(drive_fl->lchs.cylinder);
+ res.head = GET_FLATPTR(drive_fl->lchs.head);
+ res.sector = GET_FLATPTR(drive_fl->lchs.sector);
+ return res;
+}
+
+// Execute a "disk_op_s" request after jumping to the extra stack.
+static int
+__send_disk_op(struct disk_op_s *op_far, u16 op_seg)
+{
+ struct disk_op_s dop;
+ memcpy_far(GET_SEG(SS), &dop, op_seg, op_far, sizeof(dop));
+
+ int status = process_op(&dop);
+
+ // Update count with total sectors transferred.
+ SET_FARVAR(op_seg, op_far->count, dop.count);
+
+ return status;
+}
+
+// Execute a "disk_op_s" request (using the extra 16bit stack).
+static int
+send_disk_op(struct disk_op_s *op)
+{
+ ASSERT16();
+ if (! CONFIG_DRIVES)
+ return -1;
+ if (!CONFIG_ENTRY_EXTRASTACK)
+ // Jump on to extra stack
+ return stack_hop(__send_disk_op, op, GET_SEG(SS));
+ return process_op(op);
+}
+
+// Perform read/write/verify using old-style chs accesses
+static void noinline
+basic_access(struct bregs *regs, struct drive_s *drive_fl, u16 command)
+{
+ struct disk_op_s dop;
+ dop.drive_fl = drive_fl;
+ dop.command = command;
+
+ u8 count = regs->al;
+ u16 cylinder = regs->ch | ((((u16)regs->cl) << 2) & 0x300);
+ u16 sector = regs->cl & 0x3f;
+ u16 head = regs->dh;
+
+ if (count > 128 || count == 0 || sector == 0) {
+ warn_invalid(regs);
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+ dop.count = count;
+
+ struct chs_s chs = getLCHS(drive_fl);
+ u16 nlc=chs.cylinder, nlh=chs.head, nls=chs.sector;
+
+ // sanity check on cyl heads, sec
+ if (cylinder >= nlc || head >= nlh || sector > nls) {
+ warn_invalid(regs);
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ // translate lchs to lba
+ dop.lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nls)
+ + (u32)sector - 1);
+
+ dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
+
+ int status = send_disk_op(&dop);
+
+ regs->al = dop.count;
+
+ disk_ret(regs, status);
+}
+
+// Perform read/write/verify using new-style "int13ext" accesses.
+static void noinline
+extended_access(struct bregs *regs, struct drive_s *drive_fl, u16 command)
+{
+ struct disk_op_s dop;
+ struct int13ext_s *param_far = (struct int13ext_s*)(regs->si+0);
+ // Get lba and check.
+ dop.lba = GET_FARVAR(regs->ds, param_far->lba);
+ dop.command = command;
+ dop.drive_fl = drive_fl;
+ if (dop.lba >= GET_FLATPTR(drive_fl->sectors)) {
+ warn_invalid(regs);
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ dop.buf_fl = SEGOFF_TO_FLATPTR(GET_FARVAR(regs->ds, param_far->data));
+ dop.count = GET_FARVAR(regs->ds, param_far->count);
+ if (! dop.count) {
+ // Nothing to do.
+ disk_ret(regs, DISK_RET_SUCCESS);
+ return;
+ }
+
+ int status = send_disk_op(&dop);
+
+ SET_FARVAR(regs->ds, param_far->count, dop.count);
+
+ disk_ret(regs, status);
+}
+
+
+/****************************************************************
+ * Hard Drive functions
+ ****************************************************************/
+
+// disk controller reset
+static void
+disk_1300(struct bregs *regs, struct drive_s *drive_fl)
+{
+ struct disk_op_s dop;
+ dop.drive_fl = drive_fl;
+ dop.command = CMD_RESET;
+ dop.count = 0;
+ int status = send_disk_op(&dop);
+ disk_ret(regs, status);
+}
+
+// read disk status
+static void
+disk_1301(struct bregs *regs, struct drive_s *drive_fl)
+{
+ u8 v;
+ if (regs->dl < EXTSTART_HD)
+ // Floppy
+ v = GET_BDA(floppy_last_status);
+ else
+ v = GET_BDA(disk_last_status);
+ regs->ah = v;
+ set_cf(regs, v);
+ // XXX - clear disk_last_status?
+}
+
+// read disk sectors
+static void
+disk_1302(struct bregs *regs, struct drive_s *drive_fl)
+{
+ basic_access(regs, drive_fl, CMD_READ);
+}
+
+// write disk sectors
+static void
+disk_1303(struct bregs *regs, struct drive_s *drive_fl)
+{
+ basic_access(regs, drive_fl, CMD_WRITE);
+}
+
+// verify disk sectors
+static void
+disk_1304(struct bregs *regs, struct drive_s *drive_fl)
+{
+ basic_access(regs, drive_fl, CMD_VERIFY);
+}
+
+// format disk track
+static void noinline
+disk_1305(struct bregs *regs, struct drive_s *drive_fl)
+{
+ debug_stub(regs);
+
+ struct chs_s chs = getLCHS(drive_fl);
+ u16 nlc=chs.cylinder, nlh=chs.head, nls=chs.sector;
+
+ u8 count = regs->al;
+ u8 cylinder = regs->ch;
+ u8 head = regs->dh;
+
+ if (cylinder >= nlc || head >= nlh || count == 0 || count > nls) {
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ struct disk_op_s dop;
+ dop.drive_fl = drive_fl;
+ dop.command = CMD_FORMAT;
+ dop.lba = (((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nls;
+ dop.count = count;
+ dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
+ int status = send_disk_op(&dop);
+ disk_ret(regs, status);
+}
+
+// read disk drive parameters
+static void noinline
+disk_1308(struct bregs *regs, struct drive_s *drive_fl)
+{
+ // Get logical geometry from table
+ struct chs_s chs = getLCHS(drive_fl);
+ u16 nlc=chs.cylinder, nlh=chs.head, nls=chs.sector;
+ nlc--;
+ nlh--;
+ u8 count;
+ if (regs->dl < EXTSTART_HD) {
+ // Floppy
+ count = GET_GLOBAL(FloppyCount);
+
+ if (CONFIG_CDROM_EMU && drive_fl == GET_GLOBAL(cdemu_drive_gf))
+ regs->bx = GET_LOW(CDEmu.media) * 2;
+ else
+ regs->bx = GET_FLATPTR(drive_fl->floppy_type);
+
+ // set es & di to point to 11 byte diskette param table in ROM
+ regs->es = SEG_BIOS;
+ regs->di = (u32)&diskette_param_table2;
+ } else if (regs->dl < EXTSTART_CD) {
+ // Hard drive
+ count = GET_BDA(hdcount);
+ nlc--; // last sector reserved
+ } else {
+ // Not supported on CDROM
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ if (CONFIG_CDROM_EMU && GET_LOW(CDEmu.media)) {
+ u8 emudrive = GET_LOW(CDEmu.emulated_drive);
+ if (((emudrive ^ regs->dl) & 0x80) == 0)
+ // Note extra drive due to emulation.
+ count++;
+ if (regs->dl < EXTSTART_HD && count > 2)
+ // Max of two floppy drives.
+ count = 2;
+ }
+
+ regs->al = 0;
+ regs->ch = nlc & 0xff;
+ regs->cl = ((nlc >> 2) & 0xc0) | (nls & 0x3f);
+ regs->dh = nlh;
+
+ disk_ret(regs, DISK_RET_SUCCESS);
+ regs->dl = count;
+}
+
+// initialize drive parameters
+static void
+disk_1309(struct bregs *regs, struct drive_s *drive_fl)
+{
+ DISK_STUB(regs);
+}
+
+// seek to specified cylinder
+static void
+disk_130c(struct bregs *regs, struct drive_s *drive_fl)
+{
+ DISK_STUB(regs);
+}
+
+// alternate disk reset
+static void
+disk_130d(struct bregs *regs, struct drive_s *drive_fl)
+{
+ DISK_STUB(regs);
+}
+
+// check drive ready
+static void
+disk_1310(struct bregs *regs, struct drive_s *drive_fl)
+{
+ // should look at 40:8E also???
+
+ struct disk_op_s dop;
+ dop.drive_fl = drive_fl;
+ dop.command = CMD_ISREADY;
+ dop.count = 0;
+ int status = send_disk_op(&dop);
+ disk_ret(regs, status);
+}
+
+// recalibrate
+static void
+disk_1311(struct bregs *regs, struct drive_s *drive_fl)
+{
+ DISK_STUB(regs);
+}
+
+// controller internal diagnostic
+static void
+disk_1314(struct bregs *regs, struct drive_s *drive_fl)
+{
+ DISK_STUB(regs);
+}
+
+// read disk drive size
+static void noinline
+disk_1315(struct bregs *regs, struct drive_s *drive_fl)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+ if (regs->dl < EXTSTART_HD || regs->dl >= EXTSTART_CD) {
+ // Floppy or cdrom
+ regs->ah = 1;
+ return;
+ }
+ // Hard drive
+
+ // Get logical geometry from table
+ struct chs_s chs = getLCHS(drive_fl);
+ u16 nlc=chs.cylinder, nlh=chs.head, nls=chs.sector;
+
+ // Compute sector count seen by int13
+ u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nls;
+ regs->cx = lba >> 16;
+ regs->dx = lba & 0xffff;
+ regs->ah = 3; // hard disk accessible
+}
+
+static void
+disk_1316(struct bregs *regs, struct drive_s *drive_fl)
+{
+ if (regs->dl >= EXTSTART_HD) {
+ // Hard drive
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+ disk_ret(regs, DISK_RET_ECHANGED);
+}
+
+// IBM/MS installation check
+static void
+disk_1341(struct bregs *regs, struct drive_s *drive_fl)
+{
+ regs->bx = 0xaa55; // install check
+ regs->cx = 0x0007; // ext disk access and edd, removable supported
+ disk_ret(regs, DISK_RET_SUCCESS);
+ regs->ah = 0x30; // EDD 3.0
+}
+
+// IBM/MS extended read
+static void
+disk_1342(struct bregs *regs, struct drive_s *drive_fl)
+{
+ extended_access(regs, drive_fl, CMD_READ);
+}
+
+// IBM/MS extended write
+static void
+disk_1343(struct bregs *regs, struct drive_s *drive_fl)
+{
+ extended_access(regs, drive_fl, CMD_WRITE);
+}
+
+// IBM/MS verify
+static void
+disk_1344(struct bregs *regs, struct drive_s *drive_fl)
+{
+ extended_access(regs, drive_fl, 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_fl)
+{
+ int cdid = regs->dl - EXTSTART_CD;
+ u8 locks = GET_LOW(CDRom_locks[cdid]);
+ if (locks == 0xff) {
+ regs->al = 1;
+ disk_ret(regs, DISK_RET_ETOOMANYLOCKS);
+ return;
+ }
+ SET_LOW(CDRom_locks[cdid], locks + 1);
+ regs->al = 1;
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+// unlock
+static void
+disk_134501(struct bregs *regs, struct drive_s *drive_fl)
+{
+ int cdid = regs->dl - EXTSTART_CD;
+ u8 locks = GET_LOW(CDRom_locks[cdid]);
+ if (locks == 0x00) {
+ regs->al = 0;
+ disk_ret(regs, DISK_RET_ENOTLOCKED);
+ return;
+ }
+ locks--;
+ SET_LOW(CDRom_locks[cdid], locks);
+ regs->al = (locks ? 1 : 0);
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+// status
+static void
+disk_134502(struct bregs *regs, struct drive_s *drive_fl)
+{
+ int cdid = regs->dl - EXTSTART_CD;
+ u8 locks = GET_LOW(CDRom_locks[cdid]);
+ regs->al = (locks ? 1 : 0);
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_1345XX(struct bregs *regs, struct drive_s *drive_fl)
+{
+ disk_ret_unimplemented(regs, DISK_RET_EPARAM);
+}
+
+// IBM/MS lock/unlock drive
+static void
+disk_1345(struct bregs *regs, struct drive_s *drive_fl)
+{
+ if (regs->dl < EXTSTART_CD) {
+ // Always success for HD
+ disk_ret(regs, DISK_RET_SUCCESS);
+ return;
+ }
+
+ switch (regs->al) {
+ case 0x00: disk_134500(regs, drive_fl); break;
+ case 0x01: disk_134501(regs, drive_fl); break;
+ case 0x02: disk_134502(regs, drive_fl); break;
+ default: disk_1345XX(regs, drive_fl); break;
+ }
+}
+
+// IBM/MS eject media
+static void noinline
+disk_1346(struct bregs *regs, struct drive_s *drive_fl)
+{
+ if (regs->dl < EXTSTART_CD) {
+ // Volume Not Removable
+ disk_ret(regs, DISK_RET_ENOTREMOVABLE);
+ return;
+ }
+
+ int cdid = regs->dl - EXTSTART_CD;
+ u8 locks = GET_LOW(CDRom_locks[cdid]);
+ if (locks != 0) {
+ disk_ret(regs, DISK_RET_ELOCKED);
+ return;
+ }
+
+ // FIXME should handle 0x31 no media in device
+ // FIXME should handle 0xb5 valid request failed
+
+ // Call removable media eject
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.ah = 0x52;
+ br.dl = regs->dl;
+ call16_int(0x15, &br);
+
+ if (br.ah || br.flags & F_CF) {
+ disk_ret(regs, DISK_RET_ELOCKED);
+ return;
+ }
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+// IBM/MS extended seek
+static void
+disk_1347(struct bregs *regs, struct drive_s *drive_fl)
+{
+ extended_access(regs, drive_fl, CMD_SEEK);
+}
+
+// IBM/MS get drive parameters
+static void
+disk_1348(struct bregs *regs, struct drive_s *drive_fl)
+{
+ int ret = fill_edd(SEGOFF(regs->ds, regs->si), drive_fl);
+ disk_ret(regs, ret);
+}
+
+// IBM/MS extended media change
+static void
+disk_1349(struct bregs *regs, struct drive_s *drive_fl)
+{
+ if (regs->dl < EXTSTART_CD) {
+ // Always success for HD
+ disk_ret(regs, DISK_RET_SUCCESS);
+ return;
+ }
+ set_invalid(regs);
+ // always send changed ??
+ regs->ah = DISK_RET_ECHANGED;
+}
+
+static void
+disk_134e01(struct bregs *regs, struct drive_s *drive_fl)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e03(struct bregs *regs, struct drive_s *drive_fl)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e04(struct bregs *regs, struct drive_s *drive_fl)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e06(struct bregs *regs, struct drive_s *drive_fl)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134eXX(struct bregs *regs, struct drive_s *drive_fl)
+{
+ disk_ret(regs, DISK_RET_EPARAM);
+}
+
+// IBM/MS set hardware configuration
+static void
+disk_134e(struct bregs *regs, struct drive_s *drive_fl)
+{
+ switch (regs->al) {
+ case 0x01: disk_134e01(regs, drive_fl); break;
+ case 0x03: disk_134e03(regs, drive_fl); break;
+ case 0x04: disk_134e04(regs, drive_fl); break;
+ case 0x06: disk_134e06(regs, drive_fl); break;
+ default: disk_134eXX(regs, drive_fl); break;
+ }
+}
+
+static void
+disk_13XX(struct bregs *regs, struct drive_s *drive_fl)
+{
+ disk_ret_unimplemented(regs, DISK_RET_EPARAM);
+}
+
+static void
+disk_13(struct bregs *regs, struct drive_s *drive_fl)
+{
+ //debug_stub(regs);
+
+ // clear completion flag
+ SET_BDA(disk_interrupt_flag, 0);
+
+ switch (regs->ah) {
+ case 0x00: disk_1300(regs, drive_fl); break;
+ case 0x01: disk_1301(regs, drive_fl); break;
+ case 0x02: disk_1302(regs, drive_fl); break;
+ case 0x03: disk_1303(regs, drive_fl); break;
+ case 0x04: disk_1304(regs, drive_fl); break;
+ case 0x05: disk_1305(regs, drive_fl); break;
+ case 0x08: disk_1308(regs, drive_fl); break;
+ case 0x09: disk_1309(regs, drive_fl); break;
+ case 0x0c: disk_130c(regs, drive_fl); break;
+ case 0x0d: disk_130d(regs, drive_fl); break;
+ case 0x10: disk_1310(regs, drive_fl); break;
+ case 0x11: disk_1311(regs, drive_fl); break;
+ case 0x14: disk_1314(regs, drive_fl); break;
+ case 0x15: disk_1315(regs, drive_fl); break;
+ case 0x16: disk_1316(regs, drive_fl); break;
+ case 0x41: disk_1341(regs, drive_fl); break;
+ case 0x42: disk_1342(regs, drive_fl); break;
+ case 0x43: disk_1343(regs, drive_fl); break;
+ case 0x44: disk_1344(regs, drive_fl); break;
+ case 0x45: disk_1345(regs, drive_fl); break;
+ case 0x46: disk_1346(regs, drive_fl); break;
+ case 0x47: disk_1347(regs, drive_fl); break;
+ case 0x48: disk_1348(regs, drive_fl); break;
+ case 0x49: disk_1349(regs, drive_fl); break;
+ case 0x4e: disk_134e(regs, drive_fl); break;
+ default: disk_13XX(regs, drive_fl); break;
+ }
+}
+
+static void
+floppy_13(struct bregs *regs, struct drive_s *drive_fl)
+{
+ // Only limited commands are supported on floppies.
+ switch (regs->ah) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x08:
+ case 0x15:
+ case 0x16:
+ disk_13(regs, drive_fl);
+ break;
+ default: disk_13XX(regs, drive_fl); break;
+ }
+}
+
+// ElTorito - Terminate disk emu
+static void
+cdemu_134b(struct bregs *regs)
+{
+ memcpy_far(regs->ds, (void*)(regs->si+0), SEG_LOW, &CDEmu, sizeof(CDEmu));
+
+ // If we have to terminate emulation
+ if (regs->al == 0x00) {
+ // FIXME ElTorito Various. Should be handled accordingly to spec
+ SET_LOW(CDEmu.media, 0x00); // bye bye
+
+ // XXX - update floppy/hd count.
+ }
+
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+
+/****************************************************************
+ * Entry points
+ ****************************************************************/
+
+static void
+handle_legacy_disk(struct bregs *regs, u8 extdrive)
+{
+ if (! CONFIG_DRIVES) {
+ // XXX - support handle_1301 anyway?
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ if (extdrive < EXTSTART_HD) {
+ struct drive_s *drive_fl = getDrive(EXTTYPE_FLOPPY, extdrive);
+ if (!drive_fl)
+ goto fail;
+ floppy_13(regs, drive_fl);
+ return;
+ }
+
+ struct drive_s *drive_fl;
+ if (extdrive >= EXTSTART_CD)
+ drive_fl = getDrive(EXTTYPE_CD, extdrive - EXTSTART_CD);
+ else
+ drive_fl = getDrive(EXTTYPE_HD, extdrive - EXTSTART_HD);
+ if (!drive_fl)
+ goto fail;
+ disk_13(regs, drive_fl);
+ return;
+
+fail:
+ // XXX - support 1301/1308/1315 anyway?
+ disk_ret(regs, DISK_RET_EPARAM);
+}
+
+void VISIBLE16
+handle_40(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_40);
+ handle_legacy_disk(regs, regs->dl);
+}
+
+// INT 13h Fixed Disk Services Entry Point
+void VISIBLE16
+handle_13(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_13);
+ u8 extdrive = regs->dl;
+
+ if (CONFIG_CDROM_EMU) {
+ if (regs->ah == 0x4b) {
+ cdemu_134b(regs);
+ return;
+ }
+ if (GET_LOW(CDEmu.media)) {
+ u8 emudrive = GET_LOW(CDEmu.emulated_drive);
+ if (extdrive == emudrive) {
+ // Access to an emulated drive.
+ struct drive_s *cdemu_gf = GET_GLOBAL(cdemu_drive_gf);
+ if (regs->ah > 0x16) {
+ // Only old-style commands supported.
+ disk_13XX(regs, cdemu_gf);
+ return;
+ }
+ disk_13(regs, cdemu_gf);
+ return;
+ }
+ if (extdrive < EXTSTART_CD && ((emudrive ^ extdrive) & 0x80) == 0)
+ // Adjust id to make room for emulated drive.
+ extdrive--;
+ }
+ }
+ handle_legacy_disk(regs, extdrive);
+}
+
+// record completion in BIOS task complete flag
+void VISIBLE16
+handle_76(void)
+{
+ debug_isr(DEBUG_ISR_76);
+ SET_BDA(disk_interrupt_flag, 0xff);
+ pic_eoi2();
+}
diff --git a/roms/seabios-hppa/src/e820map.c b/roms/seabios-hppa/src/e820map.c
new file mode 100644
index 000000000..39445cf63
--- /dev/null
+++ b/roms/seabios-hppa/src/e820map.c
@@ -0,0 +1,152 @@
+// Support for building memory maps suitable for int 15 e820 calls.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // BUILD_MAX_E820
+#include "e820map.h" // struct e820entry
+#include "output.h" // dprintf
+#include "string.h" // memmove
+
+
+/****************************************************************
+ * e820 memory map
+ ****************************************************************/
+
+// Info on e820 map location and size.
+struct e820entry e820_list[BUILD_MAX_E820] VARFSEG;
+int e820_count VARFSEG;
+
+// Remove an entry from the e820_list.
+static void
+remove_e820(int i)
+{
+ e820_count--;
+ memmove(&e820_list[i], &e820_list[i+1]
+ , sizeof(e820_list[0]) * (e820_count - i));
+}
+
+// Insert an entry in the e820_list at the given position.
+static void
+insert_e820(int i, u64 start, u64 size, u32 type)
+{
+ if (e820_count >= BUILD_MAX_E820) {
+ warn_noalloc();
+ return;
+ }
+
+ memmove(&e820_list[i+1], &e820_list[i]
+ , sizeof(e820_list[0]) * (e820_count - i));
+ e820_count++;
+ struct e820entry *e = &e820_list[i];
+ e->start = start;
+ e->size = size;
+ e->type = type;
+}
+
+static const char *
+e820_type_name(u32 type)
+{
+ switch (type) {
+ case E820_RAM: return "RAM";
+ case E820_RESERVED: return "RESERVED";
+ case E820_ACPI: return "ACPI";
+ case E820_NVS: return "NVS";
+ case E820_UNUSABLE: return "UNUSABLE";
+ default: return "UNKNOWN";
+ }
+}
+
+// Show the current e820_list.
+static void
+dump_map(void)
+{
+ dprintf(1, "e820 map has %d items:\n", e820_count);
+ int i;
+ for (i=0; i<e820_count; i++) {
+ struct e820entry *e = &e820_list[i];
+ u64 e_end = e->start + e->size;
+ dprintf(1, " %d: %016llx - %016llx = %d %s\n", i
+ , e->start, e_end, e->type, e820_type_name(e->type));
+ }
+}
+
+#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
+e820_add(u64 start, u64 size, u32 type)
+{
+ dprintf(8, "Add to e820 map: %08llx %08llx %d\n", start, size, type);
+
+ if (! size)
+ // Huh? Nothing to do.
+ return;
+
+ // Find position of new item (splitting existing item if needed).
+ u64 end = start + size;
+ int i;
+ for (i=0; i<e820_count; i++) {
+ struct e820entry *e = &e820_list[i];
+ u64 e_end = e->start + e->size;
+ if (start > e_end)
+ continue;
+ // Found position - check if an existing item needs to be split.
+ if (start > e->start) {
+ if (type == e->type) {
+ // Same type - merge them.
+ size += start - e->start;
+ start = e->start;
+ } else {
+ // Split existing item.
+ e->size = start - e->start;
+ i++;
+ if (e_end > end)
+ insert_e820(i, end, e_end - end, e->type);
+ }
+ }
+ break;
+ }
+ // Remove/adjust existing items that are overlapping.
+ while (i<e820_count) {
+ struct e820entry *e = &e820_list[i];
+ if (end < e->start)
+ // No overlap - done.
+ break;
+ u64 e_end = e->start + e->size;
+ if (end >= e_end) {
+ // Existing item completely overlapped - remove it.
+ remove_e820(i);
+ continue;
+ }
+ // Not completely overlapped - adjust its start.
+ e->start = end;
+ e->size = e_end - end;
+ if (type == e->type) {
+ // Same type - merge them.
+ size += e->size;
+ remove_e820(i);
+ }
+ break;
+ }
+ // Insert new item.
+ if (type != E820_HOLE)
+ insert_e820(i, start, size, 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
+e820_prepboot(void)
+{
+ dump_map();
+}
diff --git a/roms/seabios-hppa/src/e820map.h b/roms/seabios-hppa/src/e820map.h
new file mode 100644
index 000000000..de8b52300
--- /dev/null
+++ b/roms/seabios-hppa/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/roms/seabios-hppa/src/entryfuncs.S b/roms/seabios-hppa/src/entryfuncs.S
new file mode 100644
index 000000000..7368bb6d5
--- /dev/null
+++ b/roms/seabios-hppa/src/entryfuncs.S
@@ -0,0 +1,165 @@
+// Macros for entering C code
+//
+// Copyright (C) 2008-2014 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+/****************************************************************
+ * Macros for save and restore of 'struct bregs' registers
+ ****************************************************************/
+
+#define PUSHBREGS_size 32
+
+ // Save registers (matches struct bregs) to stack
+ .macro PUSHBREGS
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ pushl %ebx
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushw %es
+ pushw %ds
+ .endm
+
+ // Restore registers (from struct bregs) from stack
+ .macro POPBREGS
+ popw %ds
+ popw %es
+ popl %edi
+ popl %esi
+ popl %ebp
+ popl %ebx
+ popl %edx
+ popl %ecx
+ popl %eax
+ .endm
+
+ // Save registers to struct bregs at %ds:%eax. The caller
+ // should "pushw %ds ; pushl %eax" prior to calling - this macro
+ // will pop them off.
+ .macro SAVEBREGS_POP_DSEAX
+ popl BREGS_eax(%eax)
+ popw BREGS_ds(%eax)
+ movl %edi, BREGS_edi(%eax)
+ movl %esi, BREGS_esi(%eax)
+ movl %ebp, BREGS_ebp(%eax)
+ movl %ebx, BREGS_ebx(%eax)
+ movl %edx, BREGS_edx(%eax)
+ movl %ecx, BREGS_ecx(%eax)
+ movw %es, BREGS_es(%eax)
+ .endm
+
+ // Restore registers from struct bregs at %ds:%eax
+ .macro RESTOREBREGS_DSEAX
+ movl BREGS_edi(%eax), %edi
+ movl BREGS_esi(%eax), %esi
+ movl BREGS_ebp(%eax), %ebp
+ movl BREGS_ebx(%eax), %ebx
+ movl BREGS_edx(%eax), %edx
+ movl BREGS_ecx(%eax), %ecx
+ movw BREGS_es(%eax), %es
+ pushl BREGS_eax(%eax)
+ movw BREGS_ds(%eax), %ds
+ popl %eax
+ .endm
+
+
+/****************************************************************
+ * Entry macros
+ ****************************************************************/
+
+ // Call a C function - this does the minimal work necessary to
+ // call into C. It sets up %ds, backs up %es, and backs up
+ // those registers that are call clobbered by the C compiler.
+ .macro ENTRY cfunc
+ cli // In case something far-calls instead of using "int"
+ cld
+ pushl %eax // Save registers clobbered by C code
+ pushl %ecx
+ pushl %edx
+ pushw %es
+ pushw %ds
+ movw %ss, %ax // Move %ss to %ds
+ movw %ax, %ds
+ pushl %esp // Backup %esp, then clear high bits
+ movzwl %sp, %esp
+ calll \cfunc
+ popl %esp // Restore %esp (including high bits)
+ popw %ds // Restore registers saved above
+ popw %es
+ popl %edx
+ popl %ecx
+ popl %eax
+ .endm
+
+ // Call a C function with current register list as an
+ // argument. This backs up the registers and sets %eax
+ // to point to the backup. On return, the registers are
+ // restored from the structure.
+ .macro ENTRY_ARG cfunc
+ cli
+ cld
+ PUSHBREGS
+ movw %ss, %ax // Move %ss to %ds
+ movw %ax, %ds
+ movl %esp, %ebx // Backup %esp, then zero high bits
+ movzwl %sp, %esp
+ movl %esp, %eax // First arg is pointer to struct bregs
+ calll \cfunc
+ movl %ebx, %esp // Restore %esp (including high bits)
+ POPBREGS
+ .endm
+
+ // As above, but get calling function from stack.
+ .macro ENTRY_ARG_ST
+ cli
+ cld
+ pushl %ecx
+ pushl %edx
+ pushl %ebx
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushw %es
+ pushw %ds
+ movw %ss, %cx // Move %ss to %ds
+ movw %cx, %ds
+ movl %esp, %ebx // Backup %esp, then zero high bits
+ movzwl %sp, %esp
+ movl 28(%esp), %ecx // Get calling function
+ movl %eax, 28(%esp) // Save %eax
+ movl %esp, %eax // First arg is pointer to struct bregs
+ calll *%ecx
+ movl %ebx, %esp // Restore %esp (including high bits)
+ POPBREGS
+ .endm
+
+ // Same as ENTRY_ARG, but don't mangle %esp
+ .macro ENTRY_ARG_ESP cfunc
+ cli
+ cld
+ PUSHBREGS
+ movw %ss, %ax // Move %ss to %ds
+ movw %ax, %ds
+ movl %esp, %eax // First arg is pointer to struct bregs
+ calll \cfunc
+ POPBREGS
+ .endm
+
+ // Reset stack, transition to 32bit mode, and call a C function.
+ .macro ENTRY_INTO32 cfunc
+ xorw %dx, %dx
+ movw %dx, %ss
+ movl $ BUILD_STACK_ADDR , %esp
+ movl $ \cfunc , %edx
+ jmp transition32
+ .endm
+
+ // Declare a function
+ .macro DECLFUNC func
+ .section .text.asm.\func
+ .global \func
+ .endm
diff --git a/roms/seabios-hppa/src/farptr.h b/roms/seabios-hppa/src/farptr.h
new file mode 100644
index 000000000..de6331a69
--- /dev/null
+++ b/roms/seabios-hppa/src/farptr.h
@@ -0,0 +1,220 @@
+// Code to access multiple segments within gcc.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __FARPTR_H
+#define __FARPTR_H
+
+#include "autoconf.h"
+#include "x86.h" // insb
+
+// Dummy definitions used to make sure gcc understands dependencies
+// between SET_SEG and GET/READ/WRITE_SEG macros.
+extern u16 __segment_ES, __segment_CS, __segment_DS, __segment_SS;
+extern u16 __segment_FS, __segment_GS;
+
+// Low level macros for reading/writing memory via a segment selector.
+#define READ8_SEG(prefix, SEG, value, var) \
+ __asm__(prefix "movb %%" #SEG ":%1, %b0" : "=Qi"(value) \
+ : "m"(var), "m"(__segment_ ## SEG))
+#define READ16_SEG(prefix, SEG, value, var) \
+ __asm__(prefix "movw %%" #SEG ":%1, %w0" : "=ri"(value) \
+ : "m"(var), "m"(__segment_ ## SEG))
+#define READ32_SEG(prefix, SEG, value, var) \
+ __asm__(prefix "movl %%" #SEG ":%1, %0" : "=ri"(value) \
+ : "m"(var), "m"(__segment_ ## SEG))
+#define READ64_SEG(prefix, SEG, value, var) do { \
+ union u64_u32_u __value; \
+ union u64_u32_u *__r64_ptr = (union u64_u32_u *)&(var); \
+ READ32_SEG(prefix, SEG, __value.lo, __r64_ptr->lo); \
+ READ32_SEG(prefix, SEG, __value.hi, __r64_ptr->hi); \
+ *(u64*)&(value) = __value.val; \
+ } while (0)
+#define WRITE8_SEG(prefix, SEG, var, value) \
+ __asm__(prefix "movb %b1, %%" #SEG ":%0" : "=m"(var) \
+ : "Q"(value), "m"(__segment_ ## SEG))
+#define WRITE16_SEG(prefix, SEG, var, value) \
+ __asm__(prefix "movw %w1, %%" #SEG ":%0" : "=m"(var) \
+ : "r"(value), "m"(__segment_ ## SEG))
+#define WRITE32_SEG(prefix, SEG, var, value) \
+ __asm__(prefix "movl %1, %%" #SEG ":%0" : "=m"(var) \
+ : "r"(value), "m"(__segment_ ## SEG))
+#define WRITE64_SEG(prefix, SEG, var, value) do { \
+ union u64_u32_u __value; \
+ union u64_u32_u *__w64_ptr = (union u64_u32_u *)&(var); \
+ typeof(var) __value_tmp = (value); \
+ __value.val = *(u64*)&__value_tmp; \
+ WRITE32_SEG(prefix, SEG, __w64_ptr->lo, __value.lo); \
+ WRITE32_SEG(prefix, SEG, __w64_ptr->hi, __value.hi); \
+ } while (0)
+
+// Macros for automatically choosing the appropriate memory size
+// access method.
+extern void __force_link_error__unknown_type(void);
+
+#define __GET_VAR(prefix, seg, var) ({ \
+ typeof(var) __val; \
+ if (sizeof(__val) == 1) \
+ READ8_SEG(prefix, seg, __val, var); \
+ else if (sizeof(__val) == 2) \
+ READ16_SEG(prefix, seg, __val, var); \
+ else if (sizeof(__val) == 4) \
+ READ32_SEG(prefix, seg, __val, var); \
+ else if (sizeof(__val) == 8) \
+ READ64_SEG(prefix, seg, __val, var); \
+ else \
+ __force_link_error__unknown_type(); \
+ __val; })
+
+#define __SET_VAR(prefix, seg, var, val) do { \
+ if (sizeof(var) == 1) \
+ WRITE8_SEG(prefix, seg, var, (val)); \
+ else if (sizeof(var) == 2) \
+ WRITE16_SEG(prefix, seg, var, (val)); \
+ else if (sizeof(var) == 4) \
+ WRITE32_SEG(prefix, seg, var, (val)); \
+ else if (sizeof(var) == 8) \
+ WRITE64_SEG(prefix, seg, var, (val)); \
+ else \
+ __force_link_error__unknown_type(); \
+ } while (0)
+
+#define DECL_SEGFUNCS(SEG) \
+static inline void __set_seg_##SEG(u16 seg) { \
+ __asm__("movw %w1, %%" #SEG : "=m"(__segment_##SEG) \
+ : "rm"(seg)); \
+} \
+static inline u16 __get_seg_##SEG(void) { \
+ u16 res; \
+ __asm__("movw %%" #SEG ", %w0" : "=rm"(res) \
+ : "m"(__segment_##SEG)); \
+ return res; \
+}
+DECL_SEGFUNCS(CS)
+DECL_SEGFUNCS(DS)
+DECL_SEGFUNCS(ES)
+DECL_SEGFUNCS(FS)
+DECL_SEGFUNCS(GS)
+DECL_SEGFUNCS(SS)
+
+// Low level macros for getting/setting a segment register.
+#define __SET_SEG(SEG, value) \
+ __set_seg_##SEG(value)
+#define __GET_SEG(SEG) \
+ __get_seg_##SEG()
+
+// Macros for accessing a variable in another segment. (They
+// automatically update the %es segment and then make the appropriate
+// access.)
+#define __GET_FARVAR(seg, var) ({ \
+ SET_SEG(ES, (seg)); \
+ GET_VAR(ES, (var)); })
+#define __SET_FARVAR(seg, var, val) do { \
+ typeof(var) __sfv_val = (val); \
+ SET_SEG(ES, (seg)); \
+ SET_VAR(ES, (var), __sfv_val); \
+ } while (0)
+
+// Macros for accesssing a 32bit flat mode pointer from 16bit real
+// mode. (They automatically update the %es segment, break the
+// pointer into segment/offset, and then make the access.)
+#define __GET_FLATPTR(ptr) ({ \
+ typeof(&(ptr)) __ptr = &(ptr); \
+ GET_FARVAR(FLATPTR_TO_SEG(__ptr) \
+ , *(typeof(__ptr))FLATPTR_TO_OFFSET(__ptr)); })
+#define __SET_FLATPTR(ptr, val) do { \
+ typeof (&(ptr)) __ptr = &(ptr); \
+ SET_FARVAR(FLATPTR_TO_SEG(__ptr) \
+ , *(typeof(__ptr))FLATPTR_TO_OFFSET(__ptr) \
+ , (val)); \
+ } while (0)
+
+// Macros for converting to/from 32bit flat mode pointers to their
+// equivalent 16bit segment/offset values.
+#if CONFIG_X86
+#define FLATPTR_TO_SEG(p) (((u32)(p)) >> 4)
+#define FLATPTR_TO_OFFSET(p) (((u32)(p)) & 0xf)
+#define MAKE_FLATPTR(seg,off) ((void*)(((u32)(seg)<<4)+(u32)(off)))
+#elif CONFIG_PARISC
+#define FLATPTR_TO_SEG(p) (((u32)(p)) >> 16)
+#define FLATPTR_TO_OFFSET(p) (((u32)(p)) & 0xffff)
+#define MAKE_FLATPTR(seg,off) ((void*)(unsigned long)(off))
+#endif
+
+#if MODESEGMENT == 1
+
+// Definitions when using segmented mode.
+#define GET_FARVAR(seg, var) __GET_FARVAR((seg), (var))
+#define SET_FARVAR(seg, var, val) __SET_FARVAR((seg), (var), (val))
+#define GET_VAR(seg, var) __GET_VAR("", seg, (var))
+#define SET_VAR(seg, var, val) __SET_VAR("", seg, (var), (val))
+#define SET_SEG(SEG, value) __SET_SEG(SEG, (value))
+#define GET_SEG(SEG) __GET_SEG(SEG)
+#define GET_FLATPTR(ptr) __GET_FLATPTR(ptr)
+#define SET_FLATPTR(ptr, val) __SET_FLATPTR((ptr), (val))
+
+static inline void insb_fl(u16 port, void *ptr_fl, u16 count) {
+ SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+ insb(port, (u8*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void insw_fl(u16 port, void *ptr_fl, u16 count) {
+ SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+ insw(port, (u16*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void insl_fl(u16 port, void *ptr_fl, u16 count) {
+ SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+ insl(port, (u32*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void outsb_fl(u16 port, void *ptr_fl, u16 count) {
+ SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+ outsb(port, (u8*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void outsw_fl(u16 port, void *ptr_fl, u16 count) {
+ SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+ outsw(port, (u16*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void outsl_fl(u16 port, void *ptr_fl, u16 count) {
+ SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+ outsl(port, (u32*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+
+#else
+
+// In 32-bit flat mode there is no need to mess with the segments.
+#if CONFIG_X86
+#define GET_FARVAR(seg, var) \
+ (*((typeof(&(var)))MAKE_FLATPTR((seg), &(var))))
+#define SET_FARVAR(seg, var, val) \
+ do { GET_FARVAR((seg), (var)) = (val); } while (0)
+#elif CONFIG_PARISC
+#define GET_FARVAR(seg, var) GET_VAR(seg, var)
+#define SET_FARVAR(seg, var, val) SET_VAR(seg, var, val)
+#endif
+
+#define GET_VAR(seg, var) (var)
+#define SET_VAR(seg, var, val) do { (var) = (val); } while (0)
+#define SET_SEG(SEG, value) ((void)(value))
+#define GET_SEG(SEG) 0
+#define GET_FLATPTR(ptr) (ptr)
+#define SET_FLATPTR(ptr, val) do { (ptr) = (val); } while (0)
+
+#define insb_fl(port, ptr_fl, count) insb(port, ptr_fl, count)
+#define insw_fl(port, ptr_fl, count) insw(port, ptr_fl, count)
+#define insl_fl(port, ptr_fl, count) insl(port, ptr_fl, count)
+#define outsb_fl(port, ptr_fl, count) outsb(port, ptr_fl, count)
+#define outsw_fl(port, ptr_fl, count) outsw(port, ptr_fl, count)
+#define outsl_fl(port, ptr_fl, count) outsl(port, ptr_fl, count)
+
+#endif
+
+#define SEGOFF(s,o) ({struct segoff_s __so; __so.offset=(o); __so.seg=(s); __so;})
+
+static inline struct segoff_s FLATPTR_TO_SEGOFF(void *p) {
+ return SEGOFF(FLATPTR_TO_SEG(p), FLATPTR_TO_OFFSET(p));
+}
+static inline void *SEGOFF_TO_FLATPTR(struct segoff_s so) {
+ return MAKE_FLATPTR(so.seg, so.offset);
+}
+
+#endif // farptr.h
diff --git a/roms/seabios-hppa/src/font.c b/roms/seabios-hppa/src/font.c
new file mode 100644
index 000000000..24cd67f3d
--- /dev/null
+++ b/roms/seabios-hppa/src/font.c
@@ -0,0 +1,141 @@
+#include "types.h" // u8
+
+// Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
+
+/*
+ * This font comes from the fntcol16.zip package (c) by Joseph Gil
+ * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+ * This font is public domain
+ */
+#if CONFIG_X86
+u8 vgafont8[128*8] VARFSEGFIXED(0xfa6e) = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
+ 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
+ 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
+ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
+ 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+ 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
+ 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
+ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
+ 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+ 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
+ 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
+ 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
+ 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+ 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
+ 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+ 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
+ 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
+ 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+ 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
+ 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
+ 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
+ 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
+ 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+ 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+ 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
+ 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
+ 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
+ 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
+ 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
+ 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
+ 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
+ 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
+ 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
+ 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
+ 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
+ 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
+ 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
+ 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
+ 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
+ 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
+ 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
+ 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
+ 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
+ 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
+ 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
+ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+ 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
+ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
+ 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
+ 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
+ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
+ 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
+ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
+ 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
+ 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
+ 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
+ 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
+ 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+ 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
+ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
+};
+#endif
diff --git a/roms/seabios-hppa/src/fw/acpi-dsdt-cpu-hotplug.dsl b/roms/seabios-hppa/src/fw/acpi-dsdt-cpu-hotplug.dsl
new file mode 100644
index 000000000..0f3e83b14
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/acpi-dsdt-cpu-hotplug.dsl
@@ -0,0 +1,78 @@
+/****************************************************************
+ * CPU hotplug
+ ****************************************************************/
+
+Scope(\_SB) {
+ /* Objects filled in by run-time generated SSDT */
+ External(NTFY, MethodObj)
+ External(CPON, PkgObj)
+
+ /* Methods called by run-time generated SSDT Processor objects */
+ Method(CPMA, 1, NotSerialized) {
+ // _MAT method - create an madt apic buffer
+ // Arg0 = Processor ID = Local APIC ID
+ // Local0 = CPON flag for this cpu
+ Store(DerefOf(Index(CPON, Arg0)), Local0)
+ // Local1 = Buffer (in madt apic form) to return
+ Store(Buffer(8) {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}, Local1)
+ // Update the processor id, lapic id, and enable/disable status
+ Store(Arg0, Index(Local1, 2))
+ Store(Arg0, Index(Local1, 3))
+ Store(Local0, Index(Local1, 4))
+ Return (Local1)
+ }
+ Method(CPST, 1, NotSerialized) {
+ // _STA method - return ON status of cpu
+ // Arg0 = Processor ID = Local APIC ID
+ // Local0 = CPON flag for this cpu
+ Store(DerefOf(Index(CPON, Arg0)), Local0)
+ If (Local0) {
+ Return (0xF)
+ } Else {
+ Return (0x0)
+ }
+ }
+ Method(CPEJ, 2, NotSerialized) {
+ // _EJ0 method - eject callback
+ Sleep(200)
+ }
+
+ /* CPU hotplug notify method */
+ OperationRegion(PRST, SystemIO, 0xaf00, 32)
+ Field(PRST, ByteAcc, NoLock, Preserve) {
+ PRS, 256
+ }
+ Method(PRSC, 0) {
+ // Local5 = active cpu bitmap
+ Store(PRS, Local5)
+ // Local2 = last read byte from bitmap
+ Store(Zero, Local2)
+ // Local0 = Processor ID / APIC ID iterator
+ Store(Zero, Local0)
+ While (LLess(Local0, SizeOf(CPON))) {
+ // Local1 = CPON flag for this cpu
+ Store(DerefOf(Index(CPON, Local0)), Local1)
+ If (And(Local0, 0x07)) {
+ // Shift down previously read bitmap byte
+ ShiftRight(Local2, 1, Local2)
+ } Else {
+ // Read next byte from cpu bitmap
+ Store(DerefOf(Index(Local5, ShiftRight(Local0, 3))), Local2)
+ }
+ // Local3 = active state for this cpu
+ Store(And(Local2, 1), Local3)
+
+ If (LNotEqual(Local1, Local3)) {
+ // State change - update CPON with new state
+ Store(Local3, Index(CPON, Local0))
+ // Do CPU notify
+ If (LEqual(Local3, 1)) {
+ NTFY(Local0, 1)
+ } Else {
+ NTFY(Local0, 3)
+ }
+ }
+ Increment(Local0)
+ }
+ }
+}
diff --git a/roms/seabios-hppa/src/fw/acpi-dsdt-dbug.dsl b/roms/seabios-hppa/src/fw/acpi-dsdt-dbug.dsl
new file mode 100644
index 000000000..276321f61
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/acpi-dsdt-dbug.dsl
@@ -0,0 +1,26 @@
+/****************************************************************
+ * Debugging
+ ****************************************************************/
+
+Scope(\) {
+ /* Debug Output */
+ OperationRegion(DBG, SystemIO, 0x0402, 0x01)
+ Field(DBG, ByteAcc, NoLock, Preserve) {
+ DBGB, 8,
+ }
+
+ /* Debug method - use this method to send output to the QEMU
+ * BIOS debug port. This method handles strings, integers,
+ * and buffers. For example: DBUG("abc") DBUG(0x123) */
+ Method(DBUG, 1) {
+ ToHexString(Arg0, Local0)
+ ToBuffer(Local0, Local0)
+ Subtract(SizeOf(Local0), 1, Local1)
+ Store(Zero, Local2)
+ While (LLess(Local2, Local1)) {
+ Store(DerefOf(Index(Local0, Local2)), DBGB)
+ Increment(Local2)
+ }
+ Store(0x0A, DBGB)
+ }
+}
diff --git a/roms/seabios-hppa/src/fw/acpi-dsdt-hpet.dsl b/roms/seabios-hppa/src/fw/acpi-dsdt-hpet.dsl
new file mode 100644
index 000000000..f33e52795
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/acpi-dsdt-hpet.dsl
@@ -0,0 +1,36 @@
+/****************************************************************
+ * HPET
+ ****************************************************************/
+
+Scope(\_SB) {
+ Device(HPET) {
+ Name(_HID, EISAID("PNP0103"))
+ Name(_UID, 0)
+ OperationRegion(HPTM, SystemMemory, 0xFED00000, 0x400)
+ Field(HPTM, DWordAcc, Lock, Preserve) {
+ VEND, 32,
+ PRD, 32,
+ }
+ Method(_STA, 0, NotSerialized) {
+ Store(VEND, Local0)
+ Store(PRD, Local1)
+ ShiftRight(Local0, 16, Local0)
+ If (LOr(LEqual(Local0, 0), LEqual(Local0, 0xffff))) {
+ Return (0x0)
+ }
+ If (LOr(LEqual(Local1, 0), LGreater(Local1, 100000000))) {
+ Return (0x0)
+ }
+ Return (0x0F)
+ }
+ Name(_CRS, ResourceTemplate() {
+#if 0 /* This makes WinXP BSOD for not yet figured reasons. */
+ IRQNoFlags() {2, 8}
+#endif
+ Memory32Fixed(ReadOnly,
+ 0xFED00000, // Address Base
+ 0x00000400, // Address Length
+ )
+ })
+ }
+}
diff --git a/roms/seabios-hppa/src/fw/acpi-dsdt-isa.dsl b/roms/seabios-hppa/src/fw/acpi-dsdt-isa.dsl
new file mode 100644
index 000000000..23761dbba
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/acpi-dsdt-isa.dsl
@@ -0,0 +1,102 @@
+/* Common legacy ISA style devices. */
+Scope(\_SB.PCI0.ISA) {
+
+ Device(RTC) {
+ Name(_HID, EisaId("PNP0B00"))
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x0070, 0x0070, 0x10, 0x02)
+ IRQNoFlags() { 8 }
+ IO(Decode16, 0x0072, 0x0072, 0x02, 0x06)
+ })
+ }
+
+ Device(KBD) {
+ Name(_HID, EisaId("PNP0303"))
+ Method(_STA, 0, NotSerialized) {
+ Return (0x0f)
+ }
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x0060, 0x0060, 0x01, 0x01)
+ IO(Decode16, 0x0064, 0x0064, 0x01, 0x01)
+ IRQNoFlags() { 1 }
+ })
+ }
+
+ Device(MOU) {
+ Name(_HID, EisaId("PNP0F13"))
+ Method(_STA, 0, NotSerialized) {
+ Return (0x0f)
+ }
+ Name(_CRS, ResourceTemplate() {
+ IRQNoFlags() { 12 }
+ })
+ }
+
+ Device(FDC0) {
+ Name(_HID, EisaId("PNP0700"))
+ Method(_STA, 0, NotSerialized) {
+ Store(FDEN, Local0)
+ If (LEqual(Local0, 0)) {
+ Return (0x00)
+ } Else {
+ Return (0x0F)
+ }
+ }
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x03F2, 0x03F2, 0x00, 0x04)
+ IO(Decode16, 0x03F7, 0x03F7, 0x00, 0x01)
+ IRQNoFlags() { 6 }
+ DMA(Compatibility, NotBusMaster, Transfer8) { 2 }
+ })
+ }
+
+ Device(LPT) {
+ Name(_HID, EisaId("PNP0400"))
+ Method(_STA, 0, NotSerialized) {
+ Store(LPEN, Local0)
+ If (LEqual(Local0, 0)) {
+ Return (0x00)
+ } Else {
+ Return (0x0F)
+ }
+ }
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x0378, 0x0378, 0x08, 0x08)
+ IRQNoFlags() { 7 }
+ })
+ }
+
+ Device(COM1) {
+ Name(_HID, EisaId("PNP0501"))
+ Name(_UID, 0x01)
+ Method(_STA, 0, NotSerialized) {
+ Store(CAEN, Local0)
+ If (LEqual(Local0, 0)) {
+ Return (0x00)
+ } Else {
+ Return (0x0F)
+ }
+ }
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x03F8, 0x03F8, 0x00, 0x08)
+ IRQNoFlags() { 4 }
+ })
+ }
+
+ Device(COM2) {
+ Name(_HID, EisaId("PNP0501"))
+ Name(_UID, 0x02)
+ Method(_STA, 0, NotSerialized) {
+ Store(CBEN, Local0)
+ If (LEqual(Local0, 0)) {
+ Return (0x00)
+ } Else {
+ Return (0x0F)
+ }
+ }
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x02F8, 0x02F8, 0x00, 0x08)
+ IRQNoFlags() { 3 }
+ })
+ }
+}
diff --git a/roms/seabios-hppa/src/fw/acpi-dsdt-pci-crs.dsl b/roms/seabios-hppa/src/fw/acpi-dsdt-pci-crs.dsl
new file mode 100644
index 000000000..d4218914f
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/acpi-dsdt-pci-crs.dsl
@@ -0,0 +1,90 @@
+/* PCI CRS (current resources) definition. */
+Scope(\_SB.PCI0) {
+
+ Name(CRES, ResourceTemplate() {
+ WordBusNumber(ResourceProducer, MinFixed, MaxFixed, PosDecode,
+ 0x0000, // Address Space Granularity
+ 0x0000, // Address Range Minimum
+ 0x00FF, // Address Range Maximum
+ 0x0000, // Address Translation Offset
+ 0x0100, // Address Length
+ ,, )
+ IO(Decode16,
+ 0x0CF8, // Address Range Minimum
+ 0x0CF8, // Address Range Maximum
+ 0x01, // Address Alignment
+ 0x08, // Address Length
+ )
+ WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+ 0x0000, // Address Space Granularity
+ 0x0000, // Address Range Minimum
+ 0x0CF7, // Address Range Maximum
+ 0x0000, // Address Translation Offset
+ 0x0CF8, // Address Length
+ ,, , TypeStatic)
+ WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+ 0x0000, // Address Space Granularity
+ 0x0D00, // Address Range Minimum
+ 0xFFFF, // Address Range Maximum
+ 0x0000, // Address Translation Offset
+ 0xF300, // Address Length
+ ,, , TypeStatic)
+ DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
+ 0x00000000, // Address Space Granularity
+ 0x000A0000, // Address Range Minimum
+ 0x000BFFFF, // Address Range Maximum
+ 0x00000000, // Address Translation Offset
+ 0x00020000, // Address Length
+ ,, , AddressRangeMemory, TypeStatic)
+ DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
+ 0x00000000, // Address Space Granularity
+ 0xE0000000, // Address Range Minimum
+ 0xFEBFFFFF, // Address Range Maximum
+ 0x00000000, // Address Translation Offset
+ 0x1EC00000, // Address Length
+ ,, PW32, AddressRangeMemory, TypeStatic)
+ })
+
+ Name(CR64, ResourceTemplate() {
+ QWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
+ 0x00000000, // Address Space Granularity
+ 0x8000000000, // Address Range Minimum
+ 0xFFFFFFFFFF, // Address Range Maximum
+ 0x00000000, // Address Translation Offset
+ 0x8000000000, // Address Length
+ ,, PW64, AddressRangeMemory, TypeStatic)
+ })
+
+ Method(_CRS, 0) {
+ /* Fields provided by dynamically created ssdt */
+ External(P0S, IntObj)
+ External(P0E, IntObj)
+ External(P1V, IntObj)
+ External(P1S, BuffObj)
+ External(P1E, BuffObj)
+ External(P1L, BuffObj)
+
+ /* fixup 32bit pci io window */
+ CreateDWordField(CRES, \_SB.PCI0.PW32._MIN, PS32)
+ CreateDWordField(CRES, \_SB.PCI0.PW32._MAX, PE32)
+ CreateDWordField(CRES, \_SB.PCI0.PW32._LEN, PL32)
+ Store(P0S, PS32)
+ Store(P0E, PE32)
+ Store(Add(Subtract(P0E, P0S), 1), PL32)
+
+ If (LEqual(P1V, Zero)) {
+ Return (CRES)
+ }
+
+ /* fixup 64bit pci io window */
+ CreateQWordField(CR64, \_SB.PCI0.PW64._MIN, PS64)
+ CreateQWordField(CR64, \_SB.PCI0.PW64._MAX, PE64)
+ CreateQWordField(CR64, \_SB.PCI0.PW64._LEN, PL64)
+ Store(P1S, PS64)
+ Store(P1E, PE64)
+ Store(P1L, PL64)
+ /* add window and return result */
+ ConcatenateResTemplate(CRES, CR64, Local0)
+ Return (Local0)
+ }
+}
diff --git a/roms/seabios-hppa/src/fw/acpi-dsdt.dsl b/roms/seabios-hppa/src/fw/acpi-dsdt.dsl
new file mode 100644
index 000000000..3556dcaf1
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/acpi-dsdt.dsl
@@ -0,0 +1,342 @@
+/*
+ * Bochs/QEMU ACPI DSDT ASL definition
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ACPI_EXTRACT_ALL_CODE AmlCode
+
+DefinitionBlock (
+ "acpi-dsdt.aml", // Output Filename
+ "DSDT", // Signature
+ 0x01, // DSDT Compliance Revision
+ "BXPC", // OEMID
+ "BXDSDT", // TABLE ID
+ 0x1 // OEM Revision
+ )
+{
+
+#include "acpi-dsdt-dbug.dsl"
+
+
+/****************************************************************
+ * PCI Bus definition
+ ****************************************************************/
+
+ Scope(\_SB) {
+ Device(PCI0) {
+ Name(_HID, EisaId("PNP0A03"))
+ Name(_ADR, 0x00)
+ Name(_UID, 1)
+ }
+ }
+
+#include "acpi-dsdt-pci-crs.dsl"
+#include "acpi-dsdt-hpet.dsl"
+
+
+/****************************************************************
+ * VGA
+ ****************************************************************/
+
+ Scope(\_SB.PCI0) {
+ Device(VGA) {
+ Name(_ADR, 0x00020000)
+ OperationRegion(PCIC, PCI_Config, Zero, 0x4)
+ Field(PCIC, DWordAcc, NoLock, Preserve) {
+ VEND, 32
+ }
+ Method(_S1D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S2D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S3D, 0, NotSerialized) {
+ If (LEqual(VEND, 0x1001b36)) {
+ Return (0x03) // QXL
+ } Else {
+ Return (0x00)
+ }
+ }
+ }
+ }
+
+
+/****************************************************************
+ * PIIX4 PM
+ ****************************************************************/
+
+ Scope(\_SB.PCI0) {
+ Device(PX13) {
+ Name(_ADR, 0x00010003)
+ OperationRegion(P13C, PCI_Config, 0x00, 0xff)
+ }
+ }
+
+
+/****************************************************************
+ * PIIX3 ISA bridge
+ ****************************************************************/
+
+ Scope(\_SB.PCI0) {
+ Device(ISA) {
+ Name(_ADR, 0x00010000)
+
+ /* PIIX PCI to ISA irq remapping */
+ OperationRegion(P40C, PCI_Config, 0x60, 0x04)
+
+ /* enable bits */
+ Field(\_SB.PCI0.PX13.P13C, AnyAcc, NoLock, Preserve) {
+ Offset(0x5f),
+ , 7,
+ LPEN, 1, // LPT
+ Offset(0x67),
+ , 3,
+ CAEN, 1, // COM1
+ , 3,
+ CBEN, 1, // COM2
+ }
+ Name(FDEN, 1)
+ }
+ }
+
+#include "acpi-dsdt-isa.dsl"
+
+
+/****************************************************************
+ * PCI hotplug
+ ****************************************************************/
+
+ Scope(\_SB.PCI0) {
+ OperationRegion(PCST, SystemIO, 0xae00, 0x08)
+ Field(PCST, DWordAcc, NoLock, WriteAsZeros) {
+ PCIU, 32,
+ PCID, 32,
+ }
+
+ OperationRegion(SEJ, SystemIO, 0xae08, 0x04)
+ Field(SEJ, DWordAcc, NoLock, WriteAsZeros) {
+ B0EJ, 32,
+ }
+
+ /* Methods called by bulk generated PCI devices below */
+
+ /* Methods called by hotplug devices */
+ Method(PCEJ, 1, NotSerialized) {
+ // _EJ0 method - eject callback
+ Store(ShiftLeft(1, Arg0), B0EJ)
+ }
+
+ /* Hotplug notification method supplied by SSDT */
+ External(\_SB.PCI0.PCNT, MethodObj)
+
+ /* PCI hotplug notify method */
+ Method(PCNF, 0) {
+ // Local0 = iterator
+ Store(Zero, Local0)
+ While (LLess(Local0, 31)) {
+ Increment(Local0)
+ If (And(PCIU, ShiftLeft(1, Local0))) {
+ PCNT(Local0, 1)
+ }
+ If (And(PCID, ShiftLeft(1, Local0))) {
+ PCNT(Local0, 3)
+ }
+ }
+ }
+ }
+
+
+/****************************************************************
+ * PCI IRQs
+ ****************************************************************/
+
+ Scope(\_SB) {
+ Scope(PCI0) {
+ Name(_PRT, Package() {
+ /* PCI IRQ routing table, example from ACPI 2.0a specification,
+ section 6.2.8.1 */
+ /* Note: we provide the same info as the PCI routing
+ table of the Bochs BIOS */
+
+#define prt_slot(nr, lnk0, lnk1, lnk2, lnk3) \
+ Package() { nr##ffff, 0, lnk0, 0 }, \
+ Package() { nr##ffff, 1, lnk1, 0 }, \
+ Package() { nr##ffff, 2, lnk2, 0 }, \
+ Package() { nr##ffff, 3, lnk3, 0 }
+
+#define prt_slot0(nr) prt_slot(nr, LNKD, LNKA, LNKB, LNKC)
+#define prt_slot1(nr) prt_slot(nr, LNKA, LNKB, LNKC, LNKD)
+#define prt_slot2(nr) prt_slot(nr, LNKB, LNKC, LNKD, LNKA)
+#define prt_slot3(nr) prt_slot(nr, LNKC, LNKD, LNKA, LNKB)
+
+ prt_slot0(0x0000),
+ /* Device 1 is power mgmt device, and can only use irq 9 */
+ prt_slot(0x0001, LNKS, LNKB, LNKC, LNKD),
+ prt_slot2(0x0002),
+ prt_slot3(0x0003),
+ prt_slot0(0x0004),
+ prt_slot1(0x0005),
+ prt_slot2(0x0006),
+ prt_slot3(0x0007),
+ prt_slot0(0x0008),
+ prt_slot1(0x0009),
+ prt_slot2(0x000a),
+ prt_slot3(0x000b),
+ prt_slot0(0x000c),
+ prt_slot1(0x000d),
+ prt_slot2(0x000e),
+ prt_slot3(0x000f),
+ prt_slot0(0x0010),
+ prt_slot1(0x0011),
+ prt_slot2(0x0012),
+ prt_slot3(0x0013),
+ prt_slot0(0x0014),
+ prt_slot1(0x0015),
+ prt_slot2(0x0016),
+ prt_slot3(0x0017),
+ prt_slot0(0x0018),
+ prt_slot1(0x0019),
+ prt_slot2(0x001a),
+ prt_slot3(0x001b),
+ prt_slot0(0x001c),
+ prt_slot1(0x001d),
+ prt_slot2(0x001e),
+ prt_slot3(0x001f),
+ })
+ }
+
+ Field(PCI0.ISA.P40C, ByteAcc, NoLock, Preserve) {
+ PRQ0, 8,
+ PRQ1, 8,
+ PRQ2, 8,
+ PRQ3, 8
+ }
+
+ Method(IQST, 1, NotSerialized) {
+ // _STA method - get status
+ If (And(0x80, Arg0)) {
+ Return (0x09)
+ }
+ Return (0x0B)
+ }
+ Method(IQCR, 1, Serialized) {
+ // _CRS method - get current settings
+ Name(PRR0, ResourceTemplate() {
+ Interrupt(, Level, ActiveHigh, Shared) { 0 }
+ })
+ CreateDWordField(PRR0, 0x05, PRRI)
+ If (LLess(Arg0, 0x80)) {
+ Store(Arg0, PRRI)
+ }
+ Return (PRR0)
+ }
+
+#define define_link(link, uid, reg) \
+ Device(link) { \
+ Name(_HID, EISAID("PNP0C0F")) \
+ Name(_UID, uid) \
+ Name(_PRS, ResourceTemplate() { \
+ Interrupt(, Level, ActiveHigh, Shared) { \
+ 5, 10, 11 \
+ } \
+ }) \
+ Method(_STA, 0, NotSerialized) { \
+ Return (IQST(reg)) \
+ } \
+ Method(_DIS, 0, NotSerialized) { \
+ Or(reg, 0x80, reg) \
+ } \
+ Method(_CRS, 0, NotSerialized) { \
+ Return (IQCR(reg)) \
+ } \
+ Method(_SRS, 1, NotSerialized) { \
+ CreateDWordField(Arg0, 0x05, PRRI) \
+ Store(PRRI, reg) \
+ } \
+ }
+
+ define_link(LNKA, 0, PRQ0)
+ define_link(LNKB, 1, PRQ1)
+ define_link(LNKC, 2, PRQ2)
+ define_link(LNKD, 3, PRQ3)
+
+ Device(LNKS) {
+ Name(_HID, EISAID("PNP0C0F"))
+ Name(_UID, 4)
+ Name(_PRS, ResourceTemplate() {
+ Interrupt(, Level, ActiveHigh, Shared) { 9 }
+ })
+
+ // The SCI cannot be disabled and is always attached to GSI 9,
+ // so these are no-ops. We only need this link to override the
+ // polarity to active high and match the content of the MADT.
+ Method(_STA, 0, NotSerialized) { Return (0x0b) }
+ Method(_DIS, 0, NotSerialized) { }
+ Method(_CRS, 0, NotSerialized) { Return (_PRS) }
+ Method(_SRS, 1, NotSerialized) { }
+ }
+ }
+
+#include "acpi-dsdt-cpu-hotplug.dsl"
+
+
+/****************************************************************
+ * General purpose events
+ ****************************************************************/
+
+ Scope(\_GPE) {
+ Name(_HID, "ACPI0006")
+
+ Method(_L00) {
+ }
+ Method(_E01) {
+ // PCI hotplug event
+ \_SB.PCI0.PCNF()
+ }
+ Method(_E02) {
+ // CPU hotplug event
+ \_SB.PRSC()
+ }
+ Method(_L03) {
+ }
+ Method(_L04) {
+ }
+ Method(_L05) {
+ }
+ Method(_L06) {
+ }
+ Method(_L07) {
+ }
+ Method(_L08) {
+ }
+ Method(_L09) {
+ }
+ Method(_L0A) {
+ }
+ Method(_L0B) {
+ }
+ Method(_L0C) {
+ }
+ Method(_L0D) {
+ }
+ Method(_L0E) {
+ }
+ Method(_L0F) {
+ }
+ }
+}
diff --git a/roms/seabios-hppa/src/fw/acpi-dsdt.hex b/roms/seabios-hppa/src/fw/acpi-dsdt.hex
new file mode 100644
index 000000000..6a113cdd3
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/acpi-dsdt.hex
@@ -0,0 +1,554 @@
+/* DO NOT EDIT! This is an autogenerated file. See scripts/acpi_extract.py. */
+static unsigned char AmlCode[] = {
+ 0x44, 0x53, 0x44, 0x54, 0x35, 0x11, 0x00, 0x00,
+ 0x01, 0x8b, 0x42, 0x58, 0x50, 0x43, 0x00, 0x00,
+ 0x42, 0x58, 0x44, 0x53, 0x44, 0x54, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x49, 0x4e, 0x54, 0x4c,
+ 0x18, 0x08, 0x15, 0x20, 0x10, 0x49, 0x04, 0x5c,
+ 0x00, 0x5b, 0x80, 0x44, 0x42, 0x47, 0x5f, 0x01,
+ 0x0b, 0x02, 0x04, 0x01, 0x5b, 0x81, 0x0b, 0x44,
+ 0x42, 0x47, 0x5f, 0x01, 0x44, 0x42, 0x47, 0x42,
+ 0x08, 0x14, 0x2c, 0x44, 0x42, 0x55, 0x47, 0x01,
+ 0x98, 0x68, 0x60, 0x96, 0x60, 0x60, 0x74, 0x87,
+ 0x60, 0x01, 0x61, 0x70, 0x00, 0x62, 0xa2, 0x10,
+ 0x95, 0x62, 0x61, 0x70, 0x83, 0x88, 0x60, 0x62,
+ 0x00, 0x44, 0x42, 0x47, 0x42, 0x75, 0x62, 0x70,
+ 0x0a, 0x0a, 0x44, 0x42, 0x47, 0x42, 0x10, 0x22,
+ 0x5f, 0x53, 0x42, 0x5f, 0x5b, 0x82, 0x1b, 0x50,
+ 0x43, 0x49, 0x30, 0x08, 0x5f, 0x48, 0x49, 0x44,
+ 0x0c, 0x41, 0xd0, 0x0a, 0x03, 0x08, 0x5f, 0x41,
+ 0x44, 0x52, 0x00, 0x08, 0x5f, 0x55, 0x49, 0x44,
+ 0x01, 0x10, 0x4e, 0x15, 0x2e, 0x5f, 0x53, 0x42,
+ 0x5f, 0x50, 0x43, 0x49, 0x30, 0x08, 0x43, 0x52,
+ 0x45, 0x53, 0x11, 0x42, 0x07, 0x0a, 0x6e, 0x88,
+ 0x0d, 0x00, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x47,
+ 0x01, 0xf8, 0x0c, 0xf8, 0x0c, 0x01, 0x08, 0x88,
+ 0x0d, 0x00, 0x01, 0x0c, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0xf7, 0x0c, 0x00, 0x00, 0xf8, 0x0c, 0x88,
+ 0x0d, 0x00, 0x01, 0x0c, 0x03, 0x00, 0x00, 0x00,
+ 0x0d, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf3, 0x87,
+ 0x17, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0a, 0x00, 0xff, 0xff, 0x0b,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x87, 0x17, 0x00, 0x00, 0x0c, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff,
+ 0xff, 0xbf, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0x1e, 0x79, 0x00, 0x08, 0x43, 0x52,
+ 0x36, 0x34, 0x11, 0x33, 0x0a, 0x30, 0x8a, 0x2b,
+ 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x79, 0x00, 0x14, 0x41,
+ 0x0a, 0x5f, 0x43, 0x52, 0x53, 0x00, 0x8a, 0x43,
+ 0x52, 0x45, 0x53, 0x0a, 0x5c, 0x50, 0x53, 0x33,
+ 0x32, 0x8a, 0x43, 0x52, 0x45, 0x53, 0x0a, 0x60,
+ 0x50, 0x45, 0x33, 0x32, 0x8a, 0x43, 0x52, 0x45,
+ 0x53, 0x0a, 0x68, 0x50, 0x4c, 0x33, 0x32, 0x70,
+ 0x50, 0x30, 0x53, 0x5f, 0x50, 0x53, 0x33, 0x32,
+ 0x70, 0x50, 0x30, 0x45, 0x5f, 0x50, 0x45, 0x33,
+ 0x32, 0x70, 0x72, 0x74, 0x50, 0x30, 0x45, 0x5f,
+ 0x50, 0x30, 0x53, 0x5f, 0x00, 0x01, 0x00, 0x50,
+ 0x4c, 0x33, 0x32, 0xa0, 0x0c, 0x93, 0x50, 0x31,
+ 0x56, 0x5f, 0x00, 0xa4, 0x43, 0x52, 0x45, 0x53,
+ 0x8f, 0x43, 0x52, 0x36, 0x34, 0x0a, 0x0e, 0x50,
+ 0x53, 0x36, 0x34, 0x8f, 0x43, 0x52, 0x36, 0x34,
+ 0x0a, 0x16, 0x50, 0x45, 0x36, 0x34, 0x8f, 0x43,
+ 0x52, 0x36, 0x34, 0x0a, 0x26, 0x50, 0x4c, 0x36,
+ 0x34, 0x70, 0x50, 0x31, 0x53, 0x5f, 0x50, 0x53,
+ 0x36, 0x34, 0x70, 0x50, 0x31, 0x45, 0x5f, 0x50,
+ 0x45, 0x36, 0x34, 0x70, 0x50, 0x31, 0x4c, 0x5f,
+ 0x50, 0x4c, 0x36, 0x34, 0x84, 0x43, 0x52, 0x45,
+ 0x53, 0x43, 0x52, 0x36, 0x34, 0x60, 0xa4, 0x60,
+ 0x10, 0x4d, 0x08, 0x5f, 0x53, 0x42, 0x5f, 0x5b,
+ 0x82, 0x45, 0x08, 0x48, 0x50, 0x45, 0x54, 0x08,
+ 0x5f, 0x48, 0x49, 0x44, 0x0c, 0x41, 0xd0, 0x01,
+ 0x03, 0x08, 0x5f, 0x55, 0x49, 0x44, 0x00, 0x5b,
+ 0x80, 0x48, 0x50, 0x54, 0x4d, 0x00, 0x0c, 0x00,
+ 0x00, 0xd0, 0xfe, 0x0b, 0x00, 0x04, 0x5b, 0x81,
+ 0x10, 0x48, 0x50, 0x54, 0x4d, 0x13, 0x56, 0x45,
+ 0x4e, 0x44, 0x20, 0x50, 0x52, 0x44, 0x5f, 0x20,
+ 0x14, 0x36, 0x5f, 0x53, 0x54, 0x41, 0x00, 0x70,
+ 0x56, 0x45, 0x4e, 0x44, 0x60, 0x70, 0x50, 0x52,
+ 0x44, 0x5f, 0x61, 0x7a, 0x60, 0x0a, 0x10, 0x60,
+ 0xa0, 0x0c, 0x91, 0x93, 0x60, 0x00, 0x93, 0x60,
+ 0x0b, 0xff, 0xff, 0xa4, 0x00, 0xa0, 0x0e, 0x91,
+ 0x93, 0x61, 0x00, 0x94, 0x61, 0x0c, 0x00, 0xe1,
+ 0xf5, 0x05, 0xa4, 0x00, 0xa4, 0x0a, 0x0f, 0x08,
+ 0x5f, 0x43, 0x52, 0x53, 0x11, 0x11, 0x0a, 0x0e,
+ 0x86, 0x09, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xfe,
+ 0x00, 0x04, 0x00, 0x00, 0x79, 0x00, 0x10, 0x40,
+ 0x06, 0x2e, 0x5f, 0x53, 0x42, 0x5f, 0x50, 0x43,
+ 0x49, 0x30, 0x5b, 0x82, 0x43, 0x05, 0x56, 0x47,
+ 0x41, 0x5f, 0x08, 0x5f, 0x41, 0x44, 0x52, 0x0c,
+ 0x00, 0x00, 0x02, 0x00, 0x5b, 0x80, 0x50, 0x43,
+ 0x49, 0x43, 0x02, 0x00, 0x0a, 0x04, 0x5b, 0x81,
+ 0x0b, 0x50, 0x43, 0x49, 0x43, 0x03, 0x56, 0x45,
+ 0x4e, 0x44, 0x20, 0x14, 0x08, 0x5f, 0x53, 0x31,
+ 0x44, 0x00, 0xa4, 0x00, 0x14, 0x08, 0x5f, 0x53,
+ 0x32, 0x44, 0x00, 0xa4, 0x00, 0x14, 0x19, 0x5f,
+ 0x53, 0x33, 0x44, 0x00, 0xa0, 0x0e, 0x93, 0x56,
+ 0x45, 0x4e, 0x44, 0x0c, 0x36, 0x1b, 0x00, 0x01,
+ 0xa4, 0x0a, 0x03, 0xa1, 0x03, 0xa4, 0x00, 0x10,
+ 0x25, 0x2e, 0x5f, 0x53, 0x42, 0x5f, 0x50, 0x43,
+ 0x49, 0x30, 0x5b, 0x82, 0x19, 0x50, 0x58, 0x31,
+ 0x33, 0x08, 0x5f, 0x41, 0x44, 0x52, 0x0c, 0x03,
+ 0x00, 0x01, 0x00, 0x5b, 0x80, 0x50, 0x31, 0x33,
+ 0x43, 0x02, 0x00, 0x0a, 0xff, 0x10, 0x46, 0x05,
+ 0x2e, 0x5f, 0x53, 0x42, 0x5f, 0x50, 0x43, 0x49,
+ 0x30, 0x5b, 0x82, 0x49, 0x04, 0x49, 0x53, 0x41,
+ 0x5f, 0x08, 0x5f, 0x41, 0x44, 0x52, 0x0c, 0x00,
+ 0x00, 0x01, 0x00, 0x5b, 0x80, 0x50, 0x34, 0x30,
+ 0x43, 0x02, 0x0a, 0x60, 0x0a, 0x04, 0x5b, 0x81,
+ 0x26, 0x5e, 0x2e, 0x50, 0x58, 0x31, 0x33, 0x50,
+ 0x31, 0x33, 0x43, 0x00, 0x00, 0x48, 0x2f, 0x00,
+ 0x07, 0x4c, 0x50, 0x45, 0x4e, 0x01, 0x00, 0x38,
+ 0x00, 0x03, 0x43, 0x41, 0x45, 0x4e, 0x01, 0x00,
+ 0x03, 0x43, 0x42, 0x45, 0x4e, 0x01, 0x08, 0x46,
+ 0x44, 0x45, 0x4e, 0x01, 0x10, 0x4c, 0x1b, 0x2f,
+ 0x03, 0x5f, 0x53, 0x42, 0x5f, 0x50, 0x43, 0x49,
+ 0x30, 0x49, 0x53, 0x41, 0x5f, 0x5b, 0x82, 0x2d,
+ 0x52, 0x54, 0x43, 0x5f, 0x08, 0x5f, 0x48, 0x49,
+ 0x44, 0x0c, 0x41, 0xd0, 0x0b, 0x00, 0x08, 0x5f,
+ 0x43, 0x52, 0x53, 0x11, 0x18, 0x0a, 0x15, 0x47,
+ 0x01, 0x70, 0x00, 0x70, 0x00, 0x10, 0x02, 0x22,
+ 0x00, 0x01, 0x47, 0x01, 0x72, 0x00, 0x72, 0x00,
+ 0x02, 0x06, 0x79, 0x00, 0x5b, 0x82, 0x37, 0x4b,
+ 0x42, 0x44, 0x5f, 0x08, 0x5f, 0x48, 0x49, 0x44,
+ 0x0c, 0x41, 0xd0, 0x03, 0x03, 0x14, 0x09, 0x5f,
+ 0x53, 0x54, 0x41, 0x00, 0xa4, 0x0a, 0x0f, 0x08,
+ 0x5f, 0x43, 0x52, 0x53, 0x11, 0x18, 0x0a, 0x15,
+ 0x47, 0x01, 0x60, 0x00, 0x60, 0x00, 0x01, 0x01,
+ 0x47, 0x01, 0x64, 0x00, 0x64, 0x00, 0x01, 0x01,
+ 0x22, 0x02, 0x00, 0x79, 0x00, 0x5b, 0x82, 0x27,
+ 0x4d, 0x4f, 0x55, 0x5f, 0x08, 0x5f, 0x48, 0x49,
+ 0x44, 0x0c, 0x41, 0xd0, 0x0f, 0x13, 0x14, 0x09,
+ 0x5f, 0x53, 0x54, 0x41, 0x00, 0xa4, 0x0a, 0x0f,
+ 0x08, 0x5f, 0x43, 0x52, 0x53, 0x11, 0x08, 0x0a,
+ 0x05, 0x22, 0x00, 0x10, 0x79, 0x00, 0x5b, 0x82,
+ 0x4a, 0x04, 0x46, 0x44, 0x43, 0x30, 0x08, 0x5f,
+ 0x48, 0x49, 0x44, 0x0c, 0x41, 0xd0, 0x07, 0x00,
+ 0x14, 0x18, 0x5f, 0x53, 0x54, 0x41, 0x00, 0x70,
+ 0x46, 0x44, 0x45, 0x4e, 0x60, 0xa0, 0x06, 0x93,
+ 0x60, 0x00, 0xa4, 0x00, 0xa1, 0x04, 0xa4, 0x0a,
+ 0x0f, 0x08, 0x5f, 0x43, 0x52, 0x53, 0x11, 0x1b,
+ 0x0a, 0x18, 0x47, 0x01, 0xf2, 0x03, 0xf2, 0x03,
+ 0x00, 0x04, 0x47, 0x01, 0xf7, 0x03, 0xf7, 0x03,
+ 0x00, 0x01, 0x22, 0x40, 0x00, 0x2a, 0x04, 0x00,
+ 0x79, 0x00, 0x5b, 0x82, 0x3e, 0x4c, 0x50, 0x54,
+ 0x5f, 0x08, 0x5f, 0x48, 0x49, 0x44, 0x0c, 0x41,
+ 0xd0, 0x04, 0x00, 0x14, 0x18, 0x5f, 0x53, 0x54,
+ 0x41, 0x00, 0x70, 0x4c, 0x50, 0x45, 0x4e, 0x60,
+ 0xa0, 0x06, 0x93, 0x60, 0x00, 0xa4, 0x00, 0xa1,
+ 0x04, 0xa4, 0x0a, 0x0f, 0x08, 0x5f, 0x43, 0x52,
+ 0x53, 0x11, 0x10, 0x0a, 0x0d, 0x47, 0x01, 0x78,
+ 0x03, 0x78, 0x03, 0x08, 0x08, 0x22, 0x80, 0x00,
+ 0x79, 0x00, 0x5b, 0x82, 0x45, 0x04, 0x43, 0x4f,
+ 0x4d, 0x31, 0x08, 0x5f, 0x48, 0x49, 0x44, 0x0c,
+ 0x41, 0xd0, 0x05, 0x01, 0x08, 0x5f, 0x55, 0x49,
+ 0x44, 0x01, 0x14, 0x18, 0x5f, 0x53, 0x54, 0x41,
+ 0x00, 0x70, 0x43, 0x41, 0x45, 0x4e, 0x60, 0xa0,
+ 0x06, 0x93, 0x60, 0x00, 0xa4, 0x00, 0xa1, 0x04,
+ 0xa4, 0x0a, 0x0f, 0x08, 0x5f, 0x43, 0x52, 0x53,
+ 0x11, 0x10, 0x0a, 0x0d, 0x47, 0x01, 0xf8, 0x03,
+ 0xf8, 0x03, 0x00, 0x08, 0x22, 0x10, 0x00, 0x79,
+ 0x00, 0x5b, 0x82, 0x46, 0x04, 0x43, 0x4f, 0x4d,
+ 0x32, 0x08, 0x5f, 0x48, 0x49, 0x44, 0x0c, 0x41,
+ 0xd0, 0x05, 0x01, 0x08, 0x5f, 0x55, 0x49, 0x44,
+ 0x0a, 0x02, 0x14, 0x18, 0x5f, 0x53, 0x54, 0x41,
+ 0x00, 0x70, 0x43, 0x42, 0x45, 0x4e, 0x60, 0xa0,
+ 0x06, 0x93, 0x60, 0x00, 0xa4, 0x00, 0xa1, 0x04,
+ 0xa4, 0x0a, 0x0f, 0x08, 0x5f, 0x43, 0x52, 0x53,
+ 0x11, 0x10, 0x0a, 0x0d, 0x47, 0x01, 0xf8, 0x02,
+ 0xf8, 0x02, 0x00, 0x08, 0x22, 0x08, 0x00, 0x79,
+ 0x00, 0x10, 0x49, 0x08, 0x2e, 0x5f, 0x53, 0x42,
+ 0x5f, 0x50, 0x43, 0x49, 0x30, 0x5b, 0x80, 0x50,
+ 0x43, 0x53, 0x54, 0x01, 0x0b, 0x00, 0xae, 0x0a,
+ 0x08, 0x5b, 0x81, 0x10, 0x50, 0x43, 0x53, 0x54,
+ 0x43, 0x50, 0x43, 0x49, 0x55, 0x20, 0x50, 0x43,
+ 0x49, 0x44, 0x20, 0x5b, 0x80, 0x53, 0x45, 0x4a,
+ 0x5f, 0x01, 0x0b, 0x08, 0xae, 0x0a, 0x04, 0x5b,
+ 0x81, 0x0b, 0x53, 0x45, 0x4a, 0x5f, 0x43, 0x42,
+ 0x30, 0x45, 0x4a, 0x20, 0x14, 0x0f, 0x50, 0x43,
+ 0x45, 0x4a, 0x01, 0x70, 0x79, 0x01, 0x68, 0x00,
+ 0x42, 0x30, 0x45, 0x4a, 0x14, 0x36, 0x50, 0x43,
+ 0x4e, 0x46, 0x00, 0x70, 0x00, 0x60, 0xa2, 0x2c,
+ 0x95, 0x60, 0x0a, 0x1f, 0x75, 0x60, 0xa0, 0x11,
+ 0x7b, 0x50, 0x43, 0x49, 0x55, 0x79, 0x01, 0x60,
+ 0x00, 0x00, 0x50, 0x43, 0x4e, 0x54, 0x60, 0x01,
+ 0xa0, 0x12, 0x7b, 0x50, 0x43, 0x49, 0x44, 0x79,
+ 0x01, 0x60, 0x00, 0x00, 0x50, 0x43, 0x4e, 0x54,
+ 0x60, 0x0a, 0x03, 0x10, 0x4a, 0xa0, 0x5f, 0x53,
+ 0x42, 0x5f, 0x10, 0x47, 0x74, 0x50, 0x43, 0x49,
+ 0x30, 0x08, 0x5f, 0x50, 0x52, 0x54, 0x12, 0x4b,
+ 0x73, 0x80, 0x12, 0x0b, 0x04, 0x0b, 0xff, 0xff,
+ 0x00, 0x4c, 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0b,
+ 0x04, 0x0b, 0xff, 0xff, 0x01, 0x4c, 0x4e, 0x4b,
+ 0x41, 0x00, 0x12, 0x0c, 0x04, 0x0b, 0xff, 0xff,
+ 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x42, 0x00, 0x12,
+ 0x0c, 0x04, 0x0b, 0xff, 0xff, 0x0a, 0x03, 0x4c,
+ 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x01, 0x00, 0x00, 0x4c, 0x4e, 0x4b,
+ 0x53, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x01, 0x00, 0x01, 0x4c, 0x4e, 0x4b, 0x42, 0x00,
+ 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x01, 0x00,
+ 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12,
+ 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x01, 0x00, 0x0a,
+ 0x03, 0x4c, 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x02, 0x00, 0x00, 0x4c,
+ 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x02, 0x00, 0x01, 0x4c, 0x4e, 0x4b,
+ 0x43, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff,
+ 0x02, 0x00, 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x44,
+ 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x02,
+ 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b, 0x41, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x03, 0x00,
+ 0x00, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x03, 0x00, 0x01, 0x4c,
+ 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0e, 0x04, 0x0c,
+ 0xff, 0xff, 0x03, 0x00, 0x0a, 0x02, 0x4c, 0x4e,
+ 0x4b, 0x41, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff,
+ 0xff, 0x03, 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b,
+ 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x04, 0x00, 0x00, 0x4c, 0x4e, 0x4b, 0x44, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x04, 0x00,
+ 0x01, 0x4c, 0x4e, 0x4b, 0x41, 0x00, 0x12, 0x0e,
+ 0x04, 0x0c, 0xff, 0xff, 0x04, 0x00, 0x0a, 0x02,
+ 0x4c, 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0e, 0x04,
+ 0x0c, 0xff, 0xff, 0x04, 0x00, 0x0a, 0x03, 0x4c,
+ 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x05, 0x00, 0x00, 0x4c, 0x4e, 0x4b,
+ 0x41, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x05, 0x00, 0x01, 0x4c, 0x4e, 0x4b, 0x42, 0x00,
+ 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x05, 0x00,
+ 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12,
+ 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x05, 0x00, 0x0a,
+ 0x03, 0x4c, 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x06, 0x00, 0x00, 0x4c,
+ 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x06, 0x00, 0x01, 0x4c, 0x4e, 0x4b,
+ 0x43, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff,
+ 0x06, 0x00, 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x44,
+ 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x06,
+ 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b, 0x41, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x07, 0x00,
+ 0x00, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x07, 0x00, 0x01, 0x4c,
+ 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0e, 0x04, 0x0c,
+ 0xff, 0xff, 0x07, 0x00, 0x0a, 0x02, 0x4c, 0x4e,
+ 0x4b, 0x41, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff,
+ 0xff, 0x07, 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b,
+ 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x08, 0x00, 0x00, 0x4c, 0x4e, 0x4b, 0x44, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x08, 0x00,
+ 0x01, 0x4c, 0x4e, 0x4b, 0x41, 0x00, 0x12, 0x0e,
+ 0x04, 0x0c, 0xff, 0xff, 0x08, 0x00, 0x0a, 0x02,
+ 0x4c, 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0e, 0x04,
+ 0x0c, 0xff, 0xff, 0x08, 0x00, 0x0a, 0x03, 0x4c,
+ 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x09, 0x00, 0x00, 0x4c, 0x4e, 0x4b,
+ 0x41, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x09, 0x00, 0x01, 0x4c, 0x4e, 0x4b, 0x42, 0x00,
+ 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x09, 0x00,
+ 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12,
+ 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x09, 0x00, 0x0a,
+ 0x03, 0x4c, 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x4c,
+ 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x0a, 0x00, 0x01, 0x4c, 0x4e, 0x4b,
+ 0x43, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff,
+ 0x0a, 0x00, 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x44,
+ 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x0a,
+ 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b, 0x41, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x0b, 0x00,
+ 0x00, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x0b, 0x00, 0x01, 0x4c,
+ 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0e, 0x04, 0x0c,
+ 0xff, 0xff, 0x0b, 0x00, 0x0a, 0x02, 0x4c, 0x4e,
+ 0x4b, 0x41, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff,
+ 0xff, 0x0b, 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b,
+ 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x0c, 0x00, 0x00, 0x4c, 0x4e, 0x4b, 0x44, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x0c, 0x00,
+ 0x01, 0x4c, 0x4e, 0x4b, 0x41, 0x00, 0x12, 0x0e,
+ 0x04, 0x0c, 0xff, 0xff, 0x0c, 0x00, 0x0a, 0x02,
+ 0x4c, 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0e, 0x04,
+ 0x0c, 0xff, 0xff, 0x0c, 0x00, 0x0a, 0x03, 0x4c,
+ 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x0d, 0x00, 0x00, 0x4c, 0x4e, 0x4b,
+ 0x41, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x0d, 0x00, 0x01, 0x4c, 0x4e, 0x4b, 0x42, 0x00,
+ 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x0d, 0x00,
+ 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12,
+ 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x0d, 0x00, 0x0a,
+ 0x03, 0x4c, 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x0e, 0x00, 0x00, 0x4c,
+ 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x0e, 0x00, 0x01, 0x4c, 0x4e, 0x4b,
+ 0x43, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff,
+ 0x0e, 0x00, 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x44,
+ 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x0e,
+ 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b, 0x41, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x0f, 0x00,
+ 0x00, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x0f, 0x00, 0x01, 0x4c,
+ 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0e, 0x04, 0x0c,
+ 0xff, 0xff, 0x0f, 0x00, 0x0a, 0x02, 0x4c, 0x4e,
+ 0x4b, 0x41, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff,
+ 0xff, 0x0f, 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b,
+ 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x10, 0x00, 0x00, 0x4c, 0x4e, 0x4b, 0x44, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x10, 0x00,
+ 0x01, 0x4c, 0x4e, 0x4b, 0x41, 0x00, 0x12, 0x0e,
+ 0x04, 0x0c, 0xff, 0xff, 0x10, 0x00, 0x0a, 0x02,
+ 0x4c, 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0e, 0x04,
+ 0x0c, 0xff, 0xff, 0x10, 0x00, 0x0a, 0x03, 0x4c,
+ 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x11, 0x00, 0x00, 0x4c, 0x4e, 0x4b,
+ 0x41, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x11, 0x00, 0x01, 0x4c, 0x4e, 0x4b, 0x42, 0x00,
+ 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x11, 0x00,
+ 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12,
+ 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x11, 0x00, 0x0a,
+ 0x03, 0x4c, 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x12, 0x00, 0x00, 0x4c,
+ 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x12, 0x00, 0x01, 0x4c, 0x4e, 0x4b,
+ 0x43, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff,
+ 0x12, 0x00, 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x44,
+ 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x12,
+ 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b, 0x41, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x13, 0x00,
+ 0x00, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x13, 0x00, 0x01, 0x4c,
+ 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0e, 0x04, 0x0c,
+ 0xff, 0xff, 0x13, 0x00, 0x0a, 0x02, 0x4c, 0x4e,
+ 0x4b, 0x41, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff,
+ 0xff, 0x13, 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b,
+ 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x14, 0x00, 0x00, 0x4c, 0x4e, 0x4b, 0x44, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x14, 0x00,
+ 0x01, 0x4c, 0x4e, 0x4b, 0x41, 0x00, 0x12, 0x0e,
+ 0x04, 0x0c, 0xff, 0xff, 0x14, 0x00, 0x0a, 0x02,
+ 0x4c, 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0e, 0x04,
+ 0x0c, 0xff, 0xff, 0x14, 0x00, 0x0a, 0x03, 0x4c,
+ 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x15, 0x00, 0x00, 0x4c, 0x4e, 0x4b,
+ 0x41, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x15, 0x00, 0x01, 0x4c, 0x4e, 0x4b, 0x42, 0x00,
+ 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x15, 0x00,
+ 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12,
+ 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x15, 0x00, 0x0a,
+ 0x03, 0x4c, 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x16, 0x00, 0x00, 0x4c,
+ 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x16, 0x00, 0x01, 0x4c, 0x4e, 0x4b,
+ 0x43, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff,
+ 0x16, 0x00, 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x44,
+ 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x16,
+ 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b, 0x41, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x17, 0x00,
+ 0x00, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x17, 0x00, 0x01, 0x4c,
+ 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0e, 0x04, 0x0c,
+ 0xff, 0xff, 0x17, 0x00, 0x0a, 0x02, 0x4c, 0x4e,
+ 0x4b, 0x41, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff,
+ 0xff, 0x17, 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b,
+ 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x18, 0x00, 0x00, 0x4c, 0x4e, 0x4b, 0x44, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x18, 0x00,
+ 0x01, 0x4c, 0x4e, 0x4b, 0x41, 0x00, 0x12, 0x0e,
+ 0x04, 0x0c, 0xff, 0xff, 0x18, 0x00, 0x0a, 0x02,
+ 0x4c, 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0e, 0x04,
+ 0x0c, 0xff, 0xff, 0x18, 0x00, 0x0a, 0x03, 0x4c,
+ 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x19, 0x00, 0x00, 0x4c, 0x4e, 0x4b,
+ 0x41, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x19, 0x00, 0x01, 0x4c, 0x4e, 0x4b, 0x42, 0x00,
+ 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x19, 0x00,
+ 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12,
+ 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x19, 0x00, 0x0a,
+ 0x03, 0x4c, 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x4c,
+ 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x1a, 0x00, 0x01, 0x4c, 0x4e, 0x4b,
+ 0x43, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff,
+ 0x1a, 0x00, 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x44,
+ 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x1a,
+ 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b, 0x41, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x1b, 0x00,
+ 0x00, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x1b, 0x00, 0x01, 0x4c,
+ 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0e, 0x04, 0x0c,
+ 0xff, 0xff, 0x1b, 0x00, 0x0a, 0x02, 0x4c, 0x4e,
+ 0x4b, 0x41, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff,
+ 0xff, 0x1b, 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b,
+ 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x1c, 0x00, 0x00, 0x4c, 0x4e, 0x4b, 0x44, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x1c, 0x00,
+ 0x01, 0x4c, 0x4e, 0x4b, 0x41, 0x00, 0x12, 0x0e,
+ 0x04, 0x0c, 0xff, 0xff, 0x1c, 0x00, 0x0a, 0x02,
+ 0x4c, 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0e, 0x04,
+ 0x0c, 0xff, 0xff, 0x1c, 0x00, 0x0a, 0x03, 0x4c,
+ 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x1d, 0x00, 0x00, 0x4c, 0x4e, 0x4b,
+ 0x41, 0x00, 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff,
+ 0x1d, 0x00, 0x01, 0x4c, 0x4e, 0x4b, 0x42, 0x00,
+ 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x1d, 0x00,
+ 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12,
+ 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x1d, 0x00, 0x0a,
+ 0x03, 0x4c, 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x1e, 0x00, 0x00, 0x4c,
+ 0x4e, 0x4b, 0x42, 0x00, 0x12, 0x0d, 0x04, 0x0c,
+ 0xff, 0xff, 0x1e, 0x00, 0x01, 0x4c, 0x4e, 0x4b,
+ 0x43, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff,
+ 0x1e, 0x00, 0x0a, 0x02, 0x4c, 0x4e, 0x4b, 0x44,
+ 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff, 0xff, 0x1e,
+ 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b, 0x41, 0x00,
+ 0x12, 0x0d, 0x04, 0x0c, 0xff, 0xff, 0x1f, 0x00,
+ 0x00, 0x4c, 0x4e, 0x4b, 0x43, 0x00, 0x12, 0x0d,
+ 0x04, 0x0c, 0xff, 0xff, 0x1f, 0x00, 0x01, 0x4c,
+ 0x4e, 0x4b, 0x44, 0x00, 0x12, 0x0e, 0x04, 0x0c,
+ 0xff, 0xff, 0x1f, 0x00, 0x0a, 0x02, 0x4c, 0x4e,
+ 0x4b, 0x41, 0x00, 0x12, 0x0e, 0x04, 0x0c, 0xff,
+ 0xff, 0x1f, 0x00, 0x0a, 0x03, 0x4c, 0x4e, 0x4b,
+ 0x42, 0x00, 0x5b, 0x81, 0x24, 0x2f, 0x03, 0x50,
+ 0x43, 0x49, 0x30, 0x49, 0x53, 0x41, 0x5f, 0x50,
+ 0x34, 0x30, 0x43, 0x01, 0x50, 0x52, 0x51, 0x30,
+ 0x08, 0x50, 0x52, 0x51, 0x31, 0x08, 0x50, 0x52,
+ 0x51, 0x32, 0x08, 0x50, 0x52, 0x51, 0x33, 0x08,
+ 0x14, 0x13, 0x49, 0x51, 0x53, 0x54, 0x01, 0xa0,
+ 0x09, 0x7b, 0x0a, 0x80, 0x68, 0x00, 0xa4, 0x0a,
+ 0x09, 0xa4, 0x0a, 0x0b, 0x14, 0x36, 0x49, 0x51,
+ 0x43, 0x52, 0x09, 0x08, 0x50, 0x52, 0x52, 0x30,
+ 0x11, 0x0e, 0x0a, 0x0b, 0x89, 0x06, 0x00, 0x09,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x8a,
+ 0x50, 0x52, 0x52, 0x30, 0x0a, 0x05, 0x50, 0x52,
+ 0x52, 0x49, 0xa0, 0x0b, 0x95, 0x68, 0x0a, 0x80,
+ 0x70, 0x68, 0x50, 0x52, 0x52, 0x49, 0xa4, 0x50,
+ 0x52, 0x52, 0x30, 0x5b, 0x82, 0x4c, 0x07, 0x4c,
+ 0x4e, 0x4b, 0x41, 0x08, 0x5f, 0x48, 0x49, 0x44,
+ 0x0c, 0x41, 0xd0, 0x0c, 0x0f, 0x08, 0x5f, 0x55,
+ 0x49, 0x44, 0x00, 0x08, 0x5f, 0x50, 0x52, 0x53,
+ 0x11, 0x16, 0x0a, 0x13, 0x89, 0x0e, 0x00, 0x09,
+ 0x03, 0x05, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00,
+ 0x00, 0x0b, 0x00, 0x00, 0x00, 0x79, 0x00, 0x14,
+ 0x0f, 0x5f, 0x53, 0x54, 0x41, 0x00, 0xa4, 0x49,
+ 0x51, 0x53, 0x54, 0x50, 0x52, 0x51, 0x30, 0x14,
+ 0x11, 0x5f, 0x44, 0x49, 0x53, 0x00, 0x7d, 0x50,
+ 0x52, 0x51, 0x30, 0x0a, 0x80, 0x50, 0x52, 0x51,
+ 0x30, 0x14, 0x0f, 0x5f, 0x43, 0x52, 0x53, 0x00,
+ 0xa4, 0x49, 0x51, 0x43, 0x52, 0x50, 0x52, 0x51,
+ 0x30, 0x14, 0x17, 0x5f, 0x53, 0x52, 0x53, 0x01,
+ 0x8a, 0x68, 0x0a, 0x05, 0x50, 0x52, 0x52, 0x49,
+ 0x70, 0x50, 0x52, 0x52, 0x49, 0x50, 0x52, 0x51,
+ 0x30, 0x5b, 0x82, 0x4c, 0x07, 0x4c, 0x4e, 0x4b,
+ 0x42, 0x08, 0x5f, 0x48, 0x49, 0x44, 0x0c, 0x41,
+ 0xd0, 0x0c, 0x0f, 0x08, 0x5f, 0x55, 0x49, 0x44,
+ 0x01, 0x08, 0x5f, 0x50, 0x52, 0x53, 0x11, 0x16,
+ 0x0a, 0x13, 0x89, 0x0e, 0x00, 0x09, 0x03, 0x05,
+ 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b,
+ 0x00, 0x00, 0x00, 0x79, 0x00, 0x14, 0x0f, 0x5f,
+ 0x53, 0x54, 0x41, 0x00, 0xa4, 0x49, 0x51, 0x53,
+ 0x54, 0x50, 0x52, 0x51, 0x31, 0x14, 0x11, 0x5f,
+ 0x44, 0x49, 0x53, 0x00, 0x7d, 0x50, 0x52, 0x51,
+ 0x31, 0x0a, 0x80, 0x50, 0x52, 0x51, 0x31, 0x14,
+ 0x0f, 0x5f, 0x43, 0x52, 0x53, 0x00, 0xa4, 0x49,
+ 0x51, 0x43, 0x52, 0x50, 0x52, 0x51, 0x31, 0x14,
+ 0x17, 0x5f, 0x53, 0x52, 0x53, 0x01, 0x8a, 0x68,
+ 0x0a, 0x05, 0x50, 0x52, 0x52, 0x49, 0x70, 0x50,
+ 0x52, 0x52, 0x49, 0x50, 0x52, 0x51, 0x31, 0x5b,
+ 0x82, 0x4d, 0x07, 0x4c, 0x4e, 0x4b, 0x43, 0x08,
+ 0x5f, 0x48, 0x49, 0x44, 0x0c, 0x41, 0xd0, 0x0c,
+ 0x0f, 0x08, 0x5f, 0x55, 0x49, 0x44, 0x0a, 0x02,
+ 0x08, 0x5f, 0x50, 0x52, 0x53, 0x11, 0x16, 0x0a,
+ 0x13, 0x89, 0x0e, 0x00, 0x09, 0x03, 0x05, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00,
+ 0x00, 0x00, 0x79, 0x00, 0x14, 0x0f, 0x5f, 0x53,
+ 0x54, 0x41, 0x00, 0xa4, 0x49, 0x51, 0x53, 0x54,
+ 0x50, 0x52, 0x51, 0x32, 0x14, 0x11, 0x5f, 0x44,
+ 0x49, 0x53, 0x00, 0x7d, 0x50, 0x52, 0x51, 0x32,
+ 0x0a, 0x80, 0x50, 0x52, 0x51, 0x32, 0x14, 0x0f,
+ 0x5f, 0x43, 0x52, 0x53, 0x00, 0xa4, 0x49, 0x51,
+ 0x43, 0x52, 0x50, 0x52, 0x51, 0x32, 0x14, 0x17,
+ 0x5f, 0x53, 0x52, 0x53, 0x01, 0x8a, 0x68, 0x0a,
+ 0x05, 0x50, 0x52, 0x52, 0x49, 0x70, 0x50, 0x52,
+ 0x52, 0x49, 0x50, 0x52, 0x51, 0x32, 0x5b, 0x82,
+ 0x4d, 0x07, 0x4c, 0x4e, 0x4b, 0x44, 0x08, 0x5f,
+ 0x48, 0x49, 0x44, 0x0c, 0x41, 0xd0, 0x0c, 0x0f,
+ 0x08, 0x5f, 0x55, 0x49, 0x44, 0x0a, 0x03, 0x08,
+ 0x5f, 0x50, 0x52, 0x53, 0x11, 0x16, 0x0a, 0x13,
+ 0x89, 0x0e, 0x00, 0x09, 0x03, 0x05, 0x00, 0x00,
+ 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00,
+ 0x00, 0x79, 0x00, 0x14, 0x0f, 0x5f, 0x53, 0x54,
+ 0x41, 0x00, 0xa4, 0x49, 0x51, 0x53, 0x54, 0x50,
+ 0x52, 0x51, 0x33, 0x14, 0x11, 0x5f, 0x44, 0x49,
+ 0x53, 0x00, 0x7d, 0x50, 0x52, 0x51, 0x33, 0x0a,
+ 0x80, 0x50, 0x52, 0x51, 0x33, 0x14, 0x0f, 0x5f,
+ 0x43, 0x52, 0x53, 0x00, 0xa4, 0x49, 0x51, 0x43,
+ 0x52, 0x50, 0x52, 0x51, 0x33, 0x14, 0x17, 0x5f,
+ 0x53, 0x52, 0x53, 0x01, 0x8a, 0x68, 0x0a, 0x05,
+ 0x50, 0x52, 0x52, 0x49, 0x70, 0x50, 0x52, 0x52,
+ 0x49, 0x50, 0x52, 0x51, 0x33, 0x5b, 0x82, 0x4f,
+ 0x04, 0x4c, 0x4e, 0x4b, 0x53, 0x08, 0x5f, 0x48,
+ 0x49, 0x44, 0x0c, 0x41, 0xd0, 0x0c, 0x0f, 0x08,
+ 0x5f, 0x55, 0x49, 0x44, 0x0a, 0x04, 0x08, 0x5f,
+ 0x50, 0x52, 0x53, 0x11, 0x0e, 0x0a, 0x0b, 0x89,
+ 0x06, 0x00, 0x09, 0x01, 0x09, 0x00, 0x00, 0x00,
+ 0x79, 0x00, 0x14, 0x09, 0x5f, 0x53, 0x54, 0x41,
+ 0x00, 0xa4, 0x0a, 0x0b, 0x14, 0x06, 0x5f, 0x44,
+ 0x49, 0x53, 0x00, 0x14, 0x0b, 0x5f, 0x43, 0x52,
+ 0x53, 0x00, 0xa4, 0x5f, 0x50, 0x52, 0x53, 0x14,
+ 0x06, 0x5f, 0x53, 0x52, 0x53, 0x01, 0x10, 0x47,
+ 0x0e, 0x5f, 0x53, 0x42, 0x5f, 0x14, 0x35, 0x43,
+ 0x50, 0x4d, 0x41, 0x01, 0x70, 0x83, 0x88, 0x43,
+ 0x50, 0x4f, 0x4e, 0x68, 0x00, 0x60, 0x70, 0x11,
+ 0x0b, 0x0a, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x61, 0x70, 0x68, 0x88, 0x61,
+ 0x0a, 0x02, 0x00, 0x70, 0x68, 0x88, 0x61, 0x0a,
+ 0x03, 0x00, 0x70, 0x60, 0x88, 0x61, 0x0a, 0x04,
+ 0x00, 0xa4, 0x61, 0x14, 0x1a, 0x43, 0x50, 0x53,
+ 0x54, 0x01, 0x70, 0x83, 0x88, 0x43, 0x50, 0x4f,
+ 0x4e, 0x68, 0x00, 0x60, 0xa0, 0x05, 0x60, 0xa4,
+ 0x0a, 0x0f, 0xa1, 0x03, 0xa4, 0x00, 0x14, 0x0a,
+ 0x43, 0x50, 0x45, 0x4a, 0x02, 0x5b, 0x22, 0x0a,
+ 0xc8, 0x5b, 0x80, 0x50, 0x52, 0x53, 0x54, 0x01,
+ 0x0b, 0x00, 0xaf, 0x0a, 0x20, 0x5b, 0x81, 0x0c,
+ 0x50, 0x52, 0x53, 0x54, 0x01, 0x50, 0x52, 0x53,
+ 0x5f, 0x40, 0x10, 0x14, 0x4a, 0x06, 0x50, 0x52,
+ 0x53, 0x43, 0x00, 0x70, 0x50, 0x52, 0x53, 0x5f,
+ 0x65, 0x70, 0x00, 0x62, 0x70, 0x00, 0x60, 0xa2,
+ 0x46, 0x05, 0x95, 0x60, 0x87, 0x43, 0x50, 0x4f,
+ 0x4e, 0x70, 0x83, 0x88, 0x43, 0x50, 0x4f, 0x4e,
+ 0x60, 0x00, 0x61, 0xa0, 0x0a, 0x7b, 0x60, 0x0a,
+ 0x07, 0x00, 0x7a, 0x62, 0x01, 0x62, 0xa1, 0x0c,
+ 0x70, 0x83, 0x88, 0x65, 0x7a, 0x60, 0x0a, 0x03,
+ 0x00, 0x00, 0x62, 0x70, 0x7b, 0x62, 0x01, 0x00,
+ 0x63, 0xa0, 0x22, 0x92, 0x93, 0x61, 0x63, 0x70,
+ 0x63, 0x88, 0x43, 0x50, 0x4f, 0x4e, 0x60, 0x00,
+ 0xa0, 0x0a, 0x93, 0x63, 0x01, 0x4e, 0x54, 0x46,
+ 0x59, 0x60, 0x01, 0xa1, 0x08, 0x4e, 0x54, 0x46,
+ 0x59, 0x60, 0x0a, 0x03, 0x75, 0x60, 0x10, 0x4e,
+ 0x09, 0x5f, 0x47, 0x50, 0x45, 0x08, 0x5f, 0x48,
+ 0x49, 0x44, 0x0d, 0x41, 0x43, 0x50, 0x49, 0x30,
+ 0x30, 0x30, 0x36, 0x00, 0x14, 0x06, 0x5f, 0x4c,
+ 0x30, 0x30, 0x00, 0x14, 0x15, 0x5f, 0x45, 0x30,
+ 0x31, 0x00, 0x5c, 0x2f, 0x03, 0x5f, 0x53, 0x42,
+ 0x5f, 0x50, 0x43, 0x49, 0x30, 0x50, 0x43, 0x4e,
+ 0x46, 0x14, 0x10, 0x5f, 0x45, 0x30, 0x32, 0x00,
+ 0x5c, 0x2e, 0x5f, 0x53, 0x42, 0x5f, 0x50, 0x52,
+ 0x53, 0x43, 0x14, 0x06, 0x5f, 0x4c, 0x30, 0x33,
+ 0x00, 0x14, 0x06, 0x5f, 0x4c, 0x30, 0x34, 0x00,
+ 0x14, 0x06, 0x5f, 0x4c, 0x30, 0x35, 0x00, 0x14,
+ 0x06, 0x5f, 0x4c, 0x30, 0x36, 0x00, 0x14, 0x06,
+ 0x5f, 0x4c, 0x30, 0x37, 0x00, 0x14, 0x06, 0x5f,
+ 0x4c, 0x30, 0x38, 0x00, 0x14, 0x06, 0x5f, 0x4c,
+ 0x30, 0x39, 0x00, 0x14, 0x06, 0x5f, 0x4c, 0x30,
+ 0x41, 0x00, 0x14, 0x06, 0x5f, 0x4c, 0x30, 0x42,
+ 0x00, 0x14, 0x06, 0x5f, 0x4c, 0x30, 0x43, 0x00,
+ 0x14, 0x06, 0x5f, 0x4c, 0x30, 0x44, 0x00, 0x14,
+ 0x06, 0x5f, 0x4c, 0x30, 0x45, 0x00, 0x14, 0x06,
+ 0x5f, 0x4c, 0x30, 0x46, 0x00
+};
diff --git a/roms/seabios-hppa/src/fw/acpi.c b/roms/seabios-hppa/src/fw/acpi.c
new file mode 100644
index 000000000..8bc2ca6b5
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/acpi.c
@@ -0,0 +1,685 @@
+// Support for generating ACPI tables (on emulators)
+// DO NOT ADD NEW FEATURES HERE. (See paravirt.c / biostables.c instead.)
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "byteorder.h" // cpu_to_le16
+#include "config.h" // CONFIG_*
+#include "dev-q35.h"
+#include "dev-piix.h"
+#include "hw/pcidevice.h" // pci_find_init_device
+#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "hw/pci_regs.h" // PCI_INTERRUPT_LINE
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "paravirt.h" // RamSize
+#include "romfile.h" // romfile_loadint
+#include "std/acpi.h" // struct rsdp_descriptor
+#include "string.h" // memset
+#include "util.h" // MaxCountCPUs
+#include "x86.h" // readl
+
+#include "fw/acpi-dsdt.hex"
+
+static void
+build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev)
+{
+ h->signature = cpu_to_le32(sig);
+ h->length = cpu_to_le32(len);
+ h->revision = rev;
+ memcpy(h->oem_id, BUILD_APPNAME6, 6);
+ memcpy(h->oem_table_id, BUILD_APPNAME4, 4);
+ memcpy(h->oem_table_id + 4, (void*)&sig, 4);
+ h->oem_revision = cpu_to_le32(1);
+ memcpy(h->asl_compiler_id, BUILD_APPNAME4, 4);
+ h->asl_compiler_revision = cpu_to_le32(1);
+ h->checksum -= checksum(h, len);
+}
+
+static void piix4_fadt_setup(struct pci_device *pci, void *arg)
+{
+ struct fadt_descriptor_rev1 *fadt = arg;
+
+ fadt->model = 1;
+ fadt->reserved1 = 0;
+ fadt->sci_int = cpu_to_le16(PIIX_PM_INTRRUPT);
+ fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
+ fadt->acpi_enable = PIIX_ACPI_ENABLE;
+ fadt->acpi_disable = PIIX_ACPI_DISABLE;
+ fadt->pm1a_evt_blk = cpu_to_le32(acpi_pm_base);
+ fadt->pm1a_cnt_blk = cpu_to_le32(acpi_pm_base + 0x04);
+ fadt->pm_tmr_blk = cpu_to_le32(acpi_pm_base + 0x08);
+ fadt->gpe0_blk = cpu_to_le32(PIIX_GPE0_BLK);
+ fadt->pm1_evt_len = 4;
+ fadt->pm1_cnt_len = 2;
+ fadt->pm_tmr_len = 4;
+ fadt->gpe0_blk_len = PIIX_GPE0_BLK_LEN;
+ fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+ fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+ fadt->flags = cpu_to_le32(ACPI_FADT_F_WBINVD |
+ ACPI_FADT_F_PROC_C1 |
+ ACPI_FADT_F_SLP_BUTTON |
+ ACPI_FADT_F_RTC_S4 |
+ ACPI_FADT_F_USE_PLATFORM_CLOCK);
+}
+
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */
+static void ich9_lpc_fadt_setup(struct pci_device *dev, void *arg)
+{
+ struct fadt_descriptor_rev1 *fadt = arg;
+
+ fadt->model = 1;
+ fadt->reserved1 = 0;
+ fadt->sci_int = cpu_to_le16(9);
+ fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
+ fadt->acpi_enable = ICH9_ACPI_ENABLE;
+ fadt->acpi_disable = ICH9_ACPI_DISABLE;
+ fadt->pm1a_evt_blk = cpu_to_le32(acpi_pm_base);
+ fadt->pm1a_cnt_blk = cpu_to_le32(acpi_pm_base + 0x04);
+ fadt->pm_tmr_blk = cpu_to_le32(acpi_pm_base + 0x08);
+ fadt->gpe0_blk = cpu_to_le32(acpi_pm_base + ICH9_PMIO_GPE0_STS);
+ fadt->pm1_evt_len = 4;
+ fadt->pm1_cnt_len = 2;
+ fadt->pm_tmr_len = 4;
+ fadt->gpe0_blk_len = ICH9_PMIO_GPE0_BLK_LEN;
+ fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+ fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+ fadt->flags = cpu_to_le32(ACPI_FADT_F_WBINVD |
+ ACPI_FADT_F_PROC_C1 |
+ ACPI_FADT_F_SLP_BUTTON |
+ ACPI_FADT_F_RTC_S4 |
+ ACPI_FADT_F_USE_PLATFORM_CLOCK);
+}
+
+static const struct pci_device_id fadt_init_tbl[] = {
+ /* PIIX4 Power Management device (for ACPI) */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+ piix4_fadt_setup),
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC,
+ ich9_lpc_fadt_setup),
+ PCI_DEVICE_END
+};
+
+static void fill_dsdt(struct fadt_descriptor_rev1 *fadt, void *dsdt)
+{
+ if (fadt->dsdt) {
+ free((void *)le32_to_cpu(fadt->dsdt));
+ }
+ fadt->dsdt = cpu_to_le32((u32)dsdt);
+ fadt->checksum -= checksum(fadt, sizeof(*fadt));
+ dprintf(1, "ACPI DSDT=%p\n", dsdt);
+}
+
+static void *
+build_fadt(struct pci_device *pci)
+{
+ struct fadt_descriptor_rev1 *fadt = malloc_high(sizeof(*fadt));
+ struct facs_descriptor_rev1 *facs = memalign_high(64, sizeof(*facs));
+
+ if (!fadt || !facs) {
+ warn_noalloc();
+ return NULL;
+ }
+
+ /* FACS */
+ memset(facs, 0, sizeof(*facs));
+ facs->signature = cpu_to_le32(FACS_SIGNATURE);
+ facs->length = cpu_to_le32(sizeof(*facs));
+
+ /* FADT */
+ memset(fadt, 0, sizeof(*fadt));
+ fadt->firmware_ctrl = cpu_to_le32((u32)facs);
+ fadt->dsdt = 0; /* dsdt will be filled later in acpi_setup()
+ by fill_dsdt() */
+ pci_init_device(fadt_init_tbl, pci, fadt);
+
+ build_header((void*)fadt, FACP_SIGNATURE, sizeof(*fadt), 1);
+
+ return fadt;
+}
+
+static void*
+build_madt(void)
+{
+ int madt_size = (sizeof(struct multiple_apic_table)
+ + sizeof(struct madt_processor_apic) * MaxCountCPUs
+ + sizeof(struct madt_io_apic)
+ + sizeof(struct madt_intsrcovr) * 16
+ + sizeof(struct madt_local_nmi));
+
+ struct multiple_apic_table *madt = malloc_high(madt_size);
+ if (!madt) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(madt, 0, madt_size);
+ madt->local_apic_address = cpu_to_le32(BUILD_APIC_ADDR);
+ madt->flags = cpu_to_le32(1);
+ struct madt_processor_apic *apic = (void*)&madt[1];
+ int i;
+ for (i=0; i<MaxCountCPUs; i++) {
+ apic->type = APIC_PROCESSOR;
+ apic->length = sizeof(*apic);
+ apic->processor_id = i;
+ apic->local_apic_id = i;
+ if (apic_id_is_present(apic->local_apic_id))
+ apic->flags = cpu_to_le32(1);
+ else
+ apic->flags = cpu_to_le32(0);
+ apic++;
+ }
+ struct madt_io_apic *io_apic = (void*)apic;
+ io_apic->type = APIC_IO;
+ io_apic->length = sizeof(*io_apic);
+ io_apic->io_apic_id = BUILD_IOAPIC_ID;
+ io_apic->address = cpu_to_le32(BUILD_IOAPIC_ADDR);
+ io_apic->interrupt = cpu_to_le32(0);
+
+ struct madt_intsrcovr *intsrcovr = (void*)&io_apic[1];
+ if (romfile_loadint("etc/irq0-override", 0)) {
+ memset(intsrcovr, 0, sizeof(*intsrcovr));
+ intsrcovr->type = APIC_XRUPT_OVERRIDE;
+ intsrcovr->length = sizeof(*intsrcovr);
+ intsrcovr->source = 0;
+ intsrcovr->gsi = cpu_to_le32(2);
+ intsrcovr->flags = cpu_to_le16(0); /* conforms to bus specifications */
+ intsrcovr++;
+ }
+ for (i = 1; i < 16; i++) {
+ if (!(BUILD_PCI_IRQS & (1 << i)))
+ /* No need for a INT source override structure. */
+ continue;
+ memset(intsrcovr, 0, sizeof(*intsrcovr));
+ intsrcovr->type = APIC_XRUPT_OVERRIDE;
+ intsrcovr->length = sizeof(*intsrcovr);
+ intsrcovr->source = i;
+ intsrcovr->gsi = cpu_to_le32(i);
+ intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */
+ intsrcovr++;
+ }
+
+ struct madt_local_nmi *local_nmi = (void*)intsrcovr;
+ local_nmi->type = APIC_LOCAL_NMI;
+ local_nmi->length = sizeof(*local_nmi);
+ local_nmi->processor_id = 0xff; /* all processors */
+ local_nmi->flags = cpu_to_le16(0);
+ local_nmi->lint = 1; /* LINT1 */
+ local_nmi++;
+
+ build_header((void*)madt, APIC_SIGNATURE, (void*)local_nmi - (void*)madt, 1);
+ return madt;
+}
+
+// Encode a hex value
+static inline char getHex(u32 val) {
+ val &= 0x0f;
+ return (val <= 9) ? ('0' + val) : ('A' + val - 10);
+}
+
+// Encode a length in an SSDT.
+static u8 *
+encodeLen(u8 *ssdt_ptr, int length, int bytes)
+{
+ switch (bytes) {
+ default:
+ case 4: ssdt_ptr[3] = ((length >> 20) & 0xff);
+ case 3: ssdt_ptr[2] = ((length >> 12) & 0xff);
+ case 2: ssdt_ptr[1] = ((length >> 4) & 0xff);
+ ssdt_ptr[0] = (((bytes-1) & 0x3) << 6) | (length & 0x0f);
+ break;
+ case 1: ssdt_ptr[0] = length & 0x3f;
+ }
+ return ssdt_ptr + bytes;
+}
+
+#include "fw/ssdt-proc.hex"
+
+/* 0x5B 0x83 ProcessorOp PkgLength NameString ProcID */
+#define PROC_OFFSET_CPUHEX (*ssdt_proc_name - *ssdt_proc_start + 2)
+#define PROC_OFFSET_CPUID1 (*ssdt_proc_name - *ssdt_proc_start + 4)
+#define PROC_OFFSET_CPUID2 (*ssdt_proc_id - *ssdt_proc_start)
+#define PROC_SIZEOF (*ssdt_proc_end - *ssdt_proc_start)
+#define PROC_AML (ssdp_proc_aml + *ssdt_proc_start)
+
+/* 0x5B 0x82 DeviceOp PkgLength NameString */
+#define PCIHP_OFFSET_HEX (*ssdt_pcihp_name - *ssdt_pcihp_start + 1)
+#define PCIHP_OFFSET_ID (*ssdt_pcihp_id - *ssdt_pcihp_start)
+#define PCIHP_OFFSET_ADR (*ssdt_pcihp_adr - *ssdt_pcihp_start)
+#define PCIHP_OFFSET_EJ0 (*ssdt_pcihp_ej0 - *ssdt_pcihp_start)
+#define PCIHP_SIZEOF (*ssdt_pcihp_end - *ssdt_pcihp_start)
+#define PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start)
+#define PCI_SLOTS 32
+
+#define SSDT_SIGNATURE 0x54445353 // SSDT
+#define SSDT_HEADER_LENGTH 36
+
+#include "fw/ssdt-misc.hex"
+#include "fw/ssdt-pcihp.hex"
+
+#define PCI_RMV_BASE 0xae0c
+
+static u8*
+build_notify(u8 *ssdt_ptr, const char *name, int skip, int count,
+ const char *target, int ofs)
+{
+ count -= skip;
+
+ *(ssdt_ptr++) = 0x14; // MethodOp
+ ssdt_ptr = encodeLen(ssdt_ptr, 2+5+(12*count), 2);
+ memcpy(ssdt_ptr, name, 4);
+ ssdt_ptr += 4;
+ *(ssdt_ptr++) = 0x02; // MethodOp
+
+ int i;
+ for (i = skip; count-- > 0; i++) {
+ *(ssdt_ptr++) = 0xA0; // IfOp
+ ssdt_ptr = encodeLen(ssdt_ptr, 11, 1);
+ *(ssdt_ptr++) = 0x93; // LEqualOp
+ *(ssdt_ptr++) = 0x68; // Arg0Op
+ *(ssdt_ptr++) = 0x0A; // BytePrefix
+ *(ssdt_ptr++) = i;
+ *(ssdt_ptr++) = 0x86; // NotifyOp
+ memcpy(ssdt_ptr, target, 4);
+ ssdt_ptr[ofs] = getHex(i >> 4);
+ ssdt_ptr[ofs + 1] = getHex(i);
+ ssdt_ptr += 4;
+ *(ssdt_ptr++) = 0x69; // Arg1Op
+ }
+ return ssdt_ptr;
+}
+
+static void patch_pcihp(int slot, u8 *ssdt_ptr, u32 eject)
+{
+ ssdt_ptr[PCIHP_OFFSET_HEX] = getHex(slot >> 4);
+ ssdt_ptr[PCIHP_OFFSET_HEX+1] = getHex(slot);
+ ssdt_ptr[PCIHP_OFFSET_ID] = slot;
+ ssdt_ptr[PCIHP_OFFSET_ADR + 2] = slot;
+
+ /* Runtime patching of EJ0: to disable hotplug for a slot,
+ * replace the method name: _EJ0 by EJ0_. */
+ /* Sanity check */
+ if (memcmp(ssdt_ptr + PCIHP_OFFSET_EJ0, "_EJ0", 4)) {
+ warn_internalerror();
+ }
+ if (!eject) {
+ memcpy(ssdt_ptr + PCIHP_OFFSET_EJ0, "EJ0_", 4);
+ }
+}
+
+static void*
+build_ssdt(void)
+{
+ int acpi_cpus = MaxCountCPUs > 0xff ? 0xff : MaxCountCPUs;
+ int length = (sizeof(ssdp_misc_aml) // _S3_ / _S4_ / _S5_
+ + (1+3+4) // Scope(_SB_)
+ + (acpi_cpus * PROC_SIZEOF) // procs
+ + (1+2+5+(12*acpi_cpus)) // NTFY
+ + (6+2+1+(1*acpi_cpus)) // CPON
+ + (1+3+4) // Scope(PCI0)
+ + ((PCI_SLOTS - 1) * PCIHP_SIZEOF) // slots
+ + (1+2+5+(12*(PCI_SLOTS - 1)))); // PCNT
+ u8 *ssdt = malloc_high(length);
+ if (! ssdt) {
+ warn_noalloc();
+ return NULL;
+ }
+ u8 *ssdt_ptr = ssdt;
+
+ // Copy header and encode fwcfg values in the S3_ / S4_ / S5_ packages
+ int sys_state_size;
+ char *sys_states = romfile_loadfile("etc/system-states", &sys_state_size);
+ if (!sys_states || sys_state_size != 6)
+ sys_states = (char[]){128, 0, 0, 129, 128, 128};
+
+ memcpy(ssdt_ptr, ssdp_misc_aml, sizeof(ssdp_misc_aml));
+ if (!(sys_states[3] & 128))
+ ssdt_ptr[acpi_s3_name[0]] = 'X';
+ if (!(sys_states[4] & 128))
+ ssdt_ptr[acpi_s4_name[0]] = 'X';
+ else
+ ssdt_ptr[acpi_s4_pkg[0] + 1] = ssdt[acpi_s4_pkg[0] + 3] = sys_states[4] & 127;
+
+ // store pci io windows
+ *(u32*)&ssdt_ptr[acpi_pci32_start[0]] = cpu_to_le32(pcimem_start);
+ *(u32*)&ssdt_ptr[acpi_pci32_end[0]] = cpu_to_le32(pcimem_end - 1);
+ if (pcimem64_start) {
+ ssdt_ptr[acpi_pci64_valid[0]] = 1;
+ *(u64*)&ssdt_ptr[acpi_pci64_start[0]] = cpu_to_le64(pcimem64_start);
+ *(u64*)&ssdt_ptr[acpi_pci64_end[0]] = cpu_to_le64(pcimem64_end - 1);
+ *(u64*)&ssdt_ptr[acpi_pci64_length[0]] = cpu_to_le64(
+ pcimem64_end - pcimem64_start);
+ } else {
+ ssdt_ptr[acpi_pci64_valid[0]] = 0;
+ }
+
+ int pvpanic_port = romfile_loadint("etc/pvpanic-port", 0x0);
+ *(u16 *)(ssdt_ptr + *ssdt_isa_pest) = pvpanic_port;
+
+ ssdt_ptr += sizeof(ssdp_misc_aml);
+
+ // build Scope(_SB_) header
+ *(ssdt_ptr++) = 0x10; // ScopeOp
+ ssdt_ptr = encodeLen(ssdt_ptr, length - (ssdt_ptr - ssdt), 3);
+ *(ssdt_ptr++) = '_';
+ *(ssdt_ptr++) = 'S';
+ *(ssdt_ptr++) = 'B';
+ *(ssdt_ptr++) = '_';
+
+ // build Processor object for each processor
+ int i;
+ for (i=0; i<acpi_cpus; i++) {
+ memcpy(ssdt_ptr, PROC_AML, PROC_SIZEOF);
+ ssdt_ptr[PROC_OFFSET_CPUHEX] = getHex(i >> 4);
+ ssdt_ptr[PROC_OFFSET_CPUHEX+1] = getHex(i);
+ ssdt_ptr[PROC_OFFSET_CPUID1] = i;
+ ssdt_ptr[PROC_OFFSET_CPUID2] = i;
+ ssdt_ptr += PROC_SIZEOF;
+ }
+
+ // build "Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...}"
+ // Arg0 = Processor ID = APIC ID
+ ssdt_ptr = build_notify(ssdt_ptr, "NTFY", 0, acpi_cpus, "CP00", 2);
+
+ // build "Name(CPON, Package() { One, One, ..., Zero, Zero, ... })"
+ *(ssdt_ptr++) = 0x08; // NameOp
+ *(ssdt_ptr++) = 'C';
+ *(ssdt_ptr++) = 'P';
+ *(ssdt_ptr++) = 'O';
+ *(ssdt_ptr++) = 'N';
+ *(ssdt_ptr++) = 0x12; // PackageOp
+ ssdt_ptr = encodeLen(ssdt_ptr, 2+1+(1*acpi_cpus), 2);
+ *(ssdt_ptr++) = acpi_cpus;
+ for (i=0; i<acpi_cpus; i++)
+ *(ssdt_ptr++) = (apic_id_is_present(i)) ? 0x01 : 0x00;
+
+ // build Scope(PCI0) opcode
+ *(ssdt_ptr++) = 0x10; // ScopeOp
+ ssdt_ptr = encodeLen(ssdt_ptr, length - (ssdt_ptr - ssdt), 3);
+ *(ssdt_ptr++) = 'P';
+ *(ssdt_ptr++) = 'C';
+ *(ssdt_ptr++) = 'I';
+ *(ssdt_ptr++) = '0';
+
+ // build Device object for each slot
+ u32 rmvc_pcrm = inl(PCI_RMV_BASE);
+ for (i=1; i<PCI_SLOTS; i++) {
+ u32 eject = rmvc_pcrm & (0x1 << i);
+ memcpy(ssdt_ptr, PCIHP_AML, PCIHP_SIZEOF);
+ patch_pcihp(i, ssdt_ptr, eject != 0);
+ ssdt_ptr += PCIHP_SIZEOF;
+ }
+
+ ssdt_ptr = build_notify(ssdt_ptr, "PCNT", 1, PCI_SLOTS, "S00_", 1);
+
+ build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
+
+ //hexdump(ssdt, ssdt_ptr - ssdt);
+
+ return ssdt;
+}
+
+#define HPET_ID 0x000
+#define HPET_PERIOD 0x004
+
+static void*
+build_hpet(void)
+{
+ struct acpi_20_hpet *hpet;
+ const void *hpet_base = (void *)BUILD_HPET_ADDRESS;
+ u32 hpet_vendor = readl(hpet_base + HPET_ID) >> 16;
+ u32 hpet_period = readl(hpet_base + HPET_PERIOD);
+
+ if (hpet_vendor == 0 || hpet_vendor == 0xffff ||
+ hpet_period == 0 || hpet_period > 100000000)
+ return NULL;
+
+ hpet = malloc_high(sizeof(*hpet));
+ if (!hpet) {
+ warn_noalloc();
+ return NULL;
+ }
+
+ memset(hpet, 0, sizeof(*hpet));
+ /* Note timer_block_id value must be kept in sync with value advertised by
+ * emulated hpet
+ */
+ hpet->timer_block_id = cpu_to_le32(0x8086a201);
+ hpet->addr.address = cpu_to_le64(BUILD_HPET_ADDRESS);
+ build_header((void*)hpet, HPET_SIGNATURE, sizeof(*hpet), 1);
+
+ return hpet;
+}
+
+static void
+acpi_build_srat_memory(struct srat_memory_affinity *numamem,
+ u64 base, u64 len, int node, int enabled)
+{
+ numamem->type = SRAT_MEMORY;
+ numamem->length = sizeof(*numamem);
+ memset(numamem->proximity, 0, 4);
+ numamem->proximity[0] = node;
+ numamem->flags = cpu_to_le32(!!enabled);
+ numamem->base_addr = cpu_to_le64(base);
+ numamem->range_length = cpu_to_le64(len);
+}
+
+static void *
+build_srat(void)
+{
+ int numadatasize, numacpusize;
+ u64 *numadata = romfile_loadfile("etc/numa-nodes", &numadatasize);
+ u64 *numacpumap = romfile_loadfile("etc/numa-cpu-map", &numacpusize);
+ if (!numadata || !numacpumap)
+ goto fail;
+ int max_cpu = numacpusize / sizeof(u64);
+ int nb_numa_nodes = numadatasize / sizeof(u64);
+
+ struct system_resource_affinity_table *srat;
+ int srat_size = sizeof(*srat) +
+ sizeof(struct srat_processor_affinity) * max_cpu +
+ sizeof(struct srat_memory_affinity) * (nb_numa_nodes + 2);
+
+ srat = malloc_high(srat_size);
+ if (!srat) {
+ warn_noalloc();
+ goto fail;
+ }
+
+ memset(srat, 0, srat_size);
+ srat->reserved1=cpu_to_le32(1);
+ struct srat_processor_affinity *core = (void*)(srat + 1);
+ int i;
+ u64 curnode;
+
+ for (i = 0; i < max_cpu; ++i) {
+ core->type = SRAT_PROCESSOR;
+ core->length = sizeof(*core);
+ core->local_apic_id = i;
+ curnode = *numacpumap++;
+ core->proximity_lo = curnode;
+ memset(core->proximity_hi, 0, 3);
+ core->local_sapic_eid = 0;
+ if (apic_id_is_present(i))
+ core->flags = cpu_to_le32(1);
+ else
+ core->flags = cpu_to_le32(0);
+ core++;
+ }
+
+
+ /* the memory map is a bit tricky, it contains at least one hole
+ * from 640k-1M and possibly another one from 3.5G-4G.
+ */
+ struct srat_memory_affinity *numamem = (void*)core;
+ int slots = 0;
+ u64 mem_len, mem_base, next_base = 0;
+
+ acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1);
+ next_base = 1024 * 1024;
+ numamem++;
+ slots++;
+ for (i = 1; i < nb_numa_nodes + 1; ++i) {
+ mem_base = next_base;
+ mem_len = *numadata++;
+ if (i == 1)
+ mem_len -= 1024 * 1024;
+ next_base = mem_base + mem_len;
+
+ /* Cut out the PCI hole */
+ if (mem_base <= RamSize && next_base > RamSize) {
+ mem_len -= next_base - RamSize;
+ if (mem_len > 0) {
+ acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+ numamem++;
+ slots++;
+ }
+ mem_base = 1ULL << 32;
+ mem_len = next_base - RamSize;
+ next_base += (1ULL << 32) - RamSize;
+ }
+ acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+ numamem++;
+ slots++;
+ }
+ for (; slots < nb_numa_nodes + 2; slots++) {
+ acpi_build_srat_memory(numamem, 0, 0, 0, 0);
+ numamem++;
+ }
+
+ build_header((void*)srat, SRAT_SIGNATURE, srat_size, 1);
+
+ free(numadata);
+ free(numacpumap);
+ return srat;
+fail:
+ free(numadata);
+ free(numacpumap);
+ return NULL;
+}
+
+static void *
+build_mcfg_q35(void)
+{
+ struct acpi_table_mcfg *mcfg;
+
+ int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]);
+ mcfg = malloc_high(len);
+ if (!mcfg) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(mcfg, 0, len);
+ mcfg->allocation[0].address = cpu_to_le64(Q35_HOST_BRIDGE_PCIEXBAR_ADDR);
+ mcfg->allocation[0].pci_segment = cpu_to_le16(Q35_HOST_PCIE_PCI_SEGMENT);
+ mcfg->allocation[0].start_bus_number = Q35_HOST_PCIE_START_BUS_NUMBER;
+ mcfg->allocation[0].end_bus_number = Q35_HOST_PCIE_END_BUS_NUMBER;
+
+ build_header((void *)mcfg, MCFG_SIGNATURE, len, 1);
+ return mcfg;
+}
+
+static const struct pci_device_id acpi_find_tbl[] = {
+ /* PIIX4 Power Management device. */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL),
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC, NULL),
+ PCI_DEVICE_END,
+};
+
+#define MAX_ACPI_TABLES 20
+void
+acpi_setup(void)
+{
+ if (! CONFIG_ACPI)
+ return;
+
+ dprintf(3, "init ACPI tables\n");
+
+ // This code is hardcoded for PIIX4 Power Management device.
+ struct pci_device *pci = pci_find_init_device(acpi_find_tbl, NULL);
+ if (!pci)
+ // Device not found
+ return;
+
+ // Build ACPI tables
+ u32 tables[MAX_ACPI_TABLES], tbl_idx = 0;
+
+#define ACPI_INIT_TABLE(X) \
+ do { \
+ tables[tbl_idx] = cpu_to_le32((u32)(X)); \
+ if (le32_to_cpu(tables[tbl_idx])) \
+ tbl_idx++; \
+ } while(0)
+
+ struct fadt_descriptor_rev1 *fadt = build_fadt(pci);
+ ACPI_INIT_TABLE(fadt);
+ ACPI_INIT_TABLE(build_ssdt());
+ ACPI_INIT_TABLE(build_madt());
+ ACPI_INIT_TABLE(build_hpet());
+ ACPI_INIT_TABLE(build_srat());
+ if (pci->device == PCI_DEVICE_ID_INTEL_ICH9_LPC)
+ ACPI_INIT_TABLE(build_mcfg_q35());
+
+ struct romfile_s *file = NULL;
+ for (;;) {
+ file = romfile_findprefix("acpi/", file);
+ if (!file)
+ break;
+ struct acpi_table_header *table = malloc_high(file->size);
+ if (!table) {
+ warn_noalloc();
+ continue;
+ }
+ int ret = file->copy(file, table, file->size);
+ if (ret <= sizeof(*table))
+ continue;
+ if (table->signature == DSDT_SIGNATURE) {
+ if (fadt) {
+ fill_dsdt(fadt, table);
+ }
+ } else {
+ ACPI_INIT_TABLE(table);
+ }
+ if (tbl_idx == MAX_ACPI_TABLES) {
+ warn_noalloc();
+ break;
+ }
+ }
+
+ if (CONFIG_ACPI_DSDT && fadt && !fadt->dsdt) {
+ /* default DSDT */
+ struct acpi_table_header *dsdt = malloc_high(sizeof(AmlCode));
+ if (!dsdt) {
+ warn_noalloc();
+ return;
+ }
+ memcpy(dsdt, AmlCode, sizeof(AmlCode));
+ fill_dsdt(fadt, dsdt);
+ /* Strip out compiler-generated header if any */
+ memset(dsdt, 0, sizeof *dsdt);
+ build_header(dsdt, DSDT_SIGNATURE, sizeof(AmlCode), 1);
+ }
+
+ // Build final rsdt table
+ struct rsdt_descriptor_rev1 *rsdt;
+ size_t rsdt_len = sizeof(*rsdt) + sizeof(u32) * tbl_idx;
+ rsdt = malloc_high(rsdt_len);
+ if (!rsdt) {
+ warn_noalloc();
+ return;
+ }
+ memset(rsdt, 0, rsdt_len);
+ memcpy(rsdt->table_offset_entry, tables, sizeof(u32) * tbl_idx);
+ build_header((void*)rsdt, RSDT_SIGNATURE, rsdt_len, 1);
+
+ // Build rsdp pointer table
+ struct rsdp_descriptor rsdp;
+ memset(&rsdp, 0, sizeof(rsdp));
+ rsdp.signature = cpu_to_le64(RSDP_SIGNATURE);
+ memcpy(rsdp.oem_id, BUILD_APPNAME6, 6);
+ rsdp.rsdt_physical_address = cpu_to_le32((u32)rsdt);
+ rsdp.checksum -= checksum(&rsdp, 20);
+ copy_acpi_rsdp(&rsdp);
+}
diff --git a/roms/seabios-hppa/src/fw/biostables.c b/roms/seabios-hppa/src/fw/biostables.c
new file mode 100644
index 000000000..794b5be83
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/biostables.c
@@ -0,0 +1,518 @@
+// Support for manipulating bios tables (pir, mptable, acpi, smbios).
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#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 "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 "string.h" // memcpy
+#include "util.h" // copy_table
+#include "x86.h" // outb
+
+struct pir_header *PirAddr VARFSEG;
+
+void
+copy_pir(void *pos)
+{
+ struct pir_header *p = pos;
+ if (p->signature != PIR_SIGNATURE)
+ return;
+ if (PirAddr)
+ return;
+ if (p->size < sizeof(*p))
+ return;
+ if (checksum(pos, p->size) != 0)
+ return;
+ void *newpos = malloc_fseg(p->size);
+ if (!newpos) {
+ warn_noalloc();
+ return;
+ }
+ dprintf(1, "Copying PIR from %p to %p\n", pos, newpos);
+ memcpy(newpos, pos, p->size);
+ PirAddr = newpos;
+}
+
+void
+copy_mptable(void *pos)
+{
+ struct mptable_floating_s *p = pos;
+ if (p->signature != MPTABLE_SIGNATURE)
+ return;
+ if (!p->physaddr)
+ return;
+ if (checksum(pos, sizeof(*p)) != 0)
+ 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.)
+ struct mptable_floating_s *newpos = malloc_fseg(length + mpclength);
+ if (!newpos) {
+ warn_noalloc();
+ return;
+ }
+ dprintf(1, "Copying MPTABLE from %p/%x to %p\n", pos, p->physaddr, newpos);
+ memcpy(newpos, pos, length);
+ newpos->physaddr = (u32)newpos + length;
+ newpos->checksum -= checksum(newpos, sizeof(*newpos));
+ memcpy((void*)newpos + length, (void*)p->physaddr, mpclength);
+}
+
+
+/****************************************************************
+ * ACPI
+ ****************************************************************/
+
+static int
+get_acpi_rsdp_length(void *pos, unsigned size)
+{
+ struct rsdp_descriptor *p = pos;
+ if (p->signature != RSDP_SIGNATURE)
+ return -1;
+ u32 length = 20;
+ if (length > size)
+ return -1;
+ if (checksum(pos, length) != 0)
+ return -1;
+ if (p->revision > 1) {
+ length = p->length;
+ if (length > size)
+ return -1;
+ if (checksum(pos, length) != 0)
+ return -1;
+ }
+ return length;
+}
+
+struct rsdp_descriptor *RsdpAddr;
+
+void
+copy_acpi_rsdp(void *pos)
+{
+ if (RsdpAddr)
+ return;
+ int length = get_acpi_rsdp_length(pos, -1);
+ if (length < 0)
+ return;
+ void *newpos = malloc_fseg(length);
+ if (!newpos) {
+ warn_noalloc();
+ return;
+ }
+ dprintf(1, "Copying ACPI RSDP from %p to %p\n", pos, newpos);
+ memcpy(newpos, pos, length);
+ RsdpAddr = newpos;
+}
+
+void *find_acpi_rsdp(void)
+{
+ 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)
+ if (get_acpi_rsdp_length((void *)pos, end - pos) >= 0)
+ return (void *)pos;
+
+ return NULL;
+}
+
+void *
+find_acpi_table(u32 signature)
+{
+ dprintf(4, "rsdp=%p\n", RsdpAddr);
+ if (!RsdpAddr || RsdpAddr->signature != RSDP_SIGNATURE)
+ return NULL;
+ struct rsdt_descriptor_rev1 *rsdt = (void*)RsdpAddr->rsdt_physical_address;
+ struct xsdt_descriptor_rev2 *xsdt =
+ RsdpAddr->xsdt_physical_address >= 0x100000000
+ ? NULL : (void*)(u32)(RsdpAddr->xsdt_physical_address);
+ dprintf(4, "rsdt=%p\n", rsdt);
+ dprintf(4, "xsdt=%p\n", xsdt);
+
+ if (xsdt && xsdt->signature == XSDT_SIGNATURE) {
+ void *end = (void*)xsdt + xsdt->length;
+ int i;
+ for (i=0; (void*)&xsdt->table_offset_entry[i] < end; i++) {
+ if (xsdt->table_offset_entry[i] >= 0x100000000)
+ continue; /* above 4G */
+ struct acpi_table_header *tbl = (void*)(u32)xsdt->table_offset_entry[i];
+ if (!tbl || tbl->signature != signature)
+ continue;
+ dprintf(1, "table(%x)=%p (via xsdt)\n", signature, tbl);
+ return tbl;
+ }
+ }
+
+ if (rsdt && rsdt->signature == RSDT_SIGNATURE) {
+ void *end = (void*)rsdt + rsdt->length;
+ int i;
+ for (i=0; (void*)&rsdt->table_offset_entry[i] < end; i++) {
+ struct acpi_table_header *tbl = (void*)rsdt->table_offset_entry[i];
+ if (!tbl || tbl->signature != signature)
+ continue;
+ dprintf(1, "table(%x)=%p (via rsdt)\n", signature, tbl);
+ return tbl;
+ }
+ }
+
+ dprintf(4, "no table %x found\n", signature);
+ return NULL;
+}
+
+u32
+find_resume_vector(void)
+{
+ struct fadt_descriptor_rev1 *fadt = find_acpi_table(FACP_SIGNATURE);
+ if (!fadt)
+ return 0;
+ struct facs_descriptor_rev1 *facs = (void*)fadt->firmware_ctrl;
+ dprintf(4, "facs=%p\n", facs);
+ if (! facs || facs->signature != FACS_SIGNATURE)
+ return 0;
+ // Found it.
+ dprintf(4, "resume addr=%d\n", facs->firmware_waking_vector);
+ return facs->firmware_waking_vector;
+}
+
+static struct acpi_20_generic_address acpi_reset_reg;
+static u8 acpi_reset_val;
+u32 acpi_pm1a_cnt VARFSEG;
+u16 acpi_pm_base = 0xb000;
+
+#define acpi_ga_to_bdf(addr) pci_to_bdf(0, (addr >> 32) & 0xffff, (addr >> 16) & 0xffff)
+
+void
+acpi_reboot(void)
+{
+ // Check it passed the sanity checks in acpi_set_reset_reg() and was set
+ if (acpi_reset_reg.register_bit_width != 8)
+ return;
+
+ u64 addr = le64_to_cpu(acpi_reset_reg.address);
+
+ dprintf(1, "ACPI hard reset %d:%llx (%x)\n",
+ acpi_reset_reg.address_space_id, addr, acpi_reset_val);
+
+ switch (acpi_reset_reg.address_space_id) {
+ case 0: // System Memory
+ writeb((void *)(u32)addr, acpi_reset_val);
+ break;
+ case 1: // System I/O
+ outb(acpi_reset_val, addr);
+ break;
+ case 2: // PCI config space
+ pci_config_writeb(acpi_ga_to_bdf(addr), addr & 0xffff, acpi_reset_val);
+ break;
+ }
+}
+
+static void
+acpi_set_reset_reg(struct acpi_20_generic_address *reg, u8 val)
+{
+ if (!reg || reg->address_space_id > 2 ||
+ reg->register_bit_width != 8 || reg->register_bit_offset)
+ return;
+
+ acpi_reset_reg = *reg;
+ acpi_reset_val = val;
+}
+
+void
+find_acpi_features(void)
+{
+ struct fadt_descriptor_rev1 *fadt = find_acpi_table(FACP_SIGNATURE);
+ if (!fadt)
+ return;
+ u32 pm_tmr = le32_to_cpu(fadt->pm_tmr_blk);
+ u32 pm1a_cnt = le32_to_cpu(fadt->pm1a_cnt_blk);
+ dprintf(4, "pm_tmr_blk=%x\n", pm_tmr);
+ if (pm_tmr)
+ pmtimer_setup(pm_tmr);
+ if (pm1a_cnt)
+ acpi_pm1a_cnt = pm1a_cnt;
+
+ // Theoretically we should check the 'reset_reg_sup' flag, but Windows
+ // doesn't and thus nobody seems to *set* it. If the table is large enough
+ // to include it, let the sanity checks in acpi_set_reset_reg() suffice.
+ if (fadt->length >= 129) {
+ void *p = fadt;
+ acpi_set_reset_reg(p + 116, *(u8 *)(p + 128));
+ }
+ acpi_dsdt_parse();
+}
+
+
+/****************************************************************
+ * SMBIOS
+ ****************************************************************/
+
+// Iterator for each sub-table in the smbios blob.
+void *
+smbios_next(struct smbios_entry_point *smbios, void *prev)
+{
+ if (!smbios)
+ return NULL;
+ void *start = (void*)smbios->structure_table_address;
+ void *end = start + smbios->structure_table_length;
+
+ if (!prev) {
+ prev = start;
+ } else {
+ struct smbios_structure_header *hdr = prev;
+ if (prev + sizeof(*hdr) > end)
+ return NULL;
+ prev += hdr->length + 2;
+ while (prev < end && (*(u8*)(prev-1) != '\0' || *(u8*)(prev-2) != '\0'))
+ prev++;
+ }
+ struct smbios_structure_header *hdr = prev;
+ if (prev >= end || prev + sizeof(*hdr) >= end || prev + hdr->length >= end)
+ return NULL;
+ return prev;
+}
+
+struct smbios_entry_point *SMBiosAddr;
+
+void
+copy_smbios(void *pos)
+{
+ if (SMBiosAddr)
+ return;
+ struct smbios_entry_point *p = pos;
+ if (p->signature != SMBIOS_SIGNATURE)
+ return;
+ if (checksum(pos, 0x10) != 0)
+ return;
+ if (memcmp(p->intermediate_anchor_string, "_DMI_", 5))
+ return;
+ if (checksum(pos+0x10, p->length-0x10) != 0)
+ return;
+ struct smbios_entry_point *newpos = malloc_fseg(p->length);
+ if (!newpos) {
+ warn_noalloc();
+ return;
+ }
+ dprintf(1, "Copying SMBIOS entry point from %p to %p\n", pos, newpos);
+ memcpy(newpos, pos, p->length);
+ SMBiosAddr = newpos;
+}
+
+void
+display_uuid(void)
+{
+ struct smbios_type_1 *tbl = smbios_next(SMBiosAddr, NULL);
+ int minlen = offsetof(struct smbios_type_1, uuid) + sizeof(tbl->uuid);
+ for (; tbl; tbl = smbios_next(SMBiosAddr, tbl))
+ if (tbl->header.type == 1 && tbl->header.length >= minlen) {
+ u8 *uuid = tbl->uuid;
+ u8 empty_uuid[sizeof(tbl->uuid)] = { 0 };
+ if (memcmp(uuid, empty_uuid, sizeof(empty_uuid)) == 0)
+ return;
+
+ /*
+ * 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;
+ }
+}
+
+#define set_str_field_or_skip(type, field, value) \
+ do { \
+ int size = (value != NULL) ? strlen(value) + 1 : 0; \
+ if (size > 1) { \
+ memcpy(end, value, size); \
+ end += size; \
+ p->field = ++str_index; \
+ } else { \
+ p->field = 0; \
+ } \
+ } while (0)
+
+static void *
+smbios_new_type_0(void *start,
+ const char *vendor, const char *version, const char *date)
+{
+ struct smbios_type_0 *p = (struct smbios_type_0 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_0);
+ int str_index = 0;
+
+ p->header.type = 0;
+ p->header.length = sizeof(struct smbios_type_0);
+ p->header.handle = 0;
+
+ set_str_field_or_skip(0, vendor_str, vendor);
+ set_str_field_or_skip(0, bios_version_str, version);
+ p->bios_starting_address_segment = 0xe800;
+ set_str_field_or_skip(0, bios_release_date_str, date);
+
+ p->bios_rom_size = 0; /* FIXME */
+
+ /* BIOS characteristics not supported */
+ memset(p->bios_characteristics, 0, 8);
+ p->bios_characteristics[0] = 0x08;
+
+ /* Enable targeted content distribution (needed for SVVP) */
+ p->bios_characteristics_extension_bytes[0] = 0;
+ p->bios_characteristics_extension_bytes[1] = 4;
+
+ p->system_bios_major_release = 0;
+ p->system_bios_minor_release = 0;
+ p->embedded_controller_major_release = 0xFF;
+ p->embedded_controller_minor_release = 0xFF;
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+#define BIOS_NAME "SeaBIOS"
+#define BIOS_DATE "04/01/2014"
+
+static int
+smbios_romfile_setup(void)
+{
+ struct romfile_s *f_anchor = romfile_find("etc/smbios/smbios-anchor");
+ struct romfile_s *f_tables = romfile_find("etc/smbios/smbios-tables");
+ struct smbios_entry_point ep;
+ struct smbios_type_0 *t0;
+ u16 qtables_len, need_t0 = 1;
+ u8 *qtables, *tables;
+
+ if (!f_anchor || !f_tables || f_anchor->size != sizeof(ep))
+ return 0;
+
+ f_anchor->copy(f_anchor, &ep, f_anchor->size);
+
+ if (f_tables->size != ep.structure_table_length)
+ return 0;
+
+ qtables = malloc_tmphigh(f_tables->size);
+ if (!qtables) {
+ warn_noalloc();
+ return 0;
+ }
+ f_tables->copy(f_tables, qtables, f_tables->size);
+ ep.structure_table_address = (u32)qtables; /* for smbios_next(), below */
+
+ /* did we get a type 0 structure ? */
+ for (t0 = smbios_next(&ep, NULL); t0; t0 = smbios_next(&ep, t0))
+ if (t0->header.type == 0) {
+ need_t0 = 0;
+ break;
+ }
+
+ qtables_len = ep.structure_table_length;
+ if (need_t0) {
+ /* common case: add our own type 0, with 3 strings and 4 '\0's */
+ u16 t0_len = sizeof(struct smbios_type_0) + strlen(BIOS_NAME) +
+ strlen(VERSION) + strlen(BIOS_DATE) + 4;
+ if (t0_len > (0xffff - ep.structure_table_length)) {
+ dprintf(1, "Insufficient space (%d bytes) to add SMBIOS type 0 table (%d bytes)\n",
+ 0xffff - ep.structure_table_length, t0_len);
+ need_t0 = 0;
+ } else {
+ ep.structure_table_length += t0_len;
+ if (t0_len > ep.max_structure_size)
+ ep.max_structure_size = t0_len;
+ ep.number_of_structures++;
+ }
+ }
+
+ /* allocate final blob and record its address in the entry point */
+ if (ep.structure_table_length > BUILD_MAX_SMBIOS_FSEG)
+ tables = malloc_high(ep.structure_table_length);
+ else
+ tables = malloc_fseg(ep.structure_table_length);
+ if (!tables) {
+ warn_noalloc();
+ free(qtables);
+ return 0;
+ }
+ ep.structure_table_address = (u32)tables;
+
+ /* populate final blob */
+ if (need_t0)
+ tables = smbios_new_type_0(tables, BIOS_NAME, VERSION, BIOS_DATE);
+ memcpy(tables, qtables, qtables_len);
+ free(qtables);
+
+ /* finalize entry point */
+ ep.checksum -= checksum(&ep, 0x10);
+ ep.intermediate_checksum -= checksum((void *)&ep + 0x10, ep.length - 0x10);
+
+ copy_smbios(&ep);
+ return 1;
+}
+
+void
+smbios_setup(void)
+{
+ if (smbios_romfile_setup())
+ return;
+ smbios_legacy_setup();
+}
+
+void
+copy_table(void *pos)
+{
+ copy_pir(pos);
+ copy_mptable(pos);
+ copy_acpi_rsdp(pos);
+ copy_smbios(pos);
+}
diff --git a/roms/seabios-hppa/src/fw/coreboot.c b/roms/seabios-hppa/src/fw/coreboot.c
new file mode 100644
index 000000000..7c0954b53
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/coreboot.c
@@ -0,0 +1,569 @@
+// Coreboot interface support.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "block.h" // MAXDESCSIZE
+#include "byteorder.h" // be32_to_cpu
+#include "config.h" // CONFIG_*
+#include "e820map.h" // e820_add
+#include "hw/pcidevice.h" // pci_probe_devices
+#include "lzmadecode.h" // LzmaDecode
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "paravirt.h" // PlatformRunningOn
+#include "romfile.h" // romfile_findprefix
+#include "stacks.h" // yield
+#include "string.h" // memset
+#include "util.h" // coreboot_preinit
+
+
+/****************************************************************
+ * Memory map
+ ****************************************************************/
+
+struct cb_header {
+ u32 signature;
+ u32 header_bytes;
+ u32 header_checksum;
+ u32 table_bytes;
+ u32 table_checksum;
+ u32 table_entries;
+};
+
+#define CB_SIGNATURE 0x4f49424C // "LBIO"
+
+struct cb_memory_range {
+ u64 start;
+ u64 size;
+ u32 type;
+};
+
+#define CB_MEM_TABLE 16
+
+struct cb_memory {
+ u32 tag;
+ u32 size;
+ struct cb_memory_range map[0];
+};
+
+#define CB_TAG_MEMORY 0x01
+
+#define MEM_RANGE_COUNT(_rec) \
+ (((_rec)->size - sizeof(*(_rec))) / sizeof((_rec)->map[0]))
+
+struct cb_mainboard {
+ u32 tag;
+ u32 size;
+ u8 vendor_idx;
+ u8 part_idx;
+ char strings[0];
+};
+
+#define CB_TAG_MAINBOARD 0x0003
+
+struct cb_forward {
+ u32 tag;
+ u32 size;
+ u64 forward;
+};
+
+#define CB_TAG_FORWARD 0x11
+
+struct cb_cbmem_ref {
+ u32 tag;
+ u32 size;
+ u64 cbmem_addr;
+};
+
+#define CB_TAG_CBMEM_CONSOLE 0x17
+
+struct cbmem_console {
+ u32 size;
+ u32 cursor;
+ u8 body[0];
+} PACKED;
+#define CBMC_CURSOR_MASK ((1 << 28) - 1)
+#define CBMC_OVERFLOW (1 << 31)
+static struct cbmem_console *cbcon = NULL;
+
+static u16
+ipchksum(char *buf, int count)
+{
+ u16 *p = (u16*)buf;
+ u32 sum = 0;
+ while (count > 1) {
+ sum += GET_FARVAR(0, *p);
+ p++;
+ count -= 2;
+ }
+ if (count)
+ sum += GET_FARVAR(0, *(u8*)p);
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+ return ~sum;
+}
+
+// Try to locate the coreboot header in a given address range.
+static struct cb_header *
+find_cb_header(u32 addr, int len)
+{
+ u32 end = addr + len;
+ for (; addr < end; addr += 16) {
+ struct cb_header *cbh = (void*)addr;
+ if (GET_FARVAR(0, cbh->signature) != CB_SIGNATURE)
+ continue;
+ u32 tsize = GET_FARVAR(0, cbh->table_bytes);
+ if (! tsize)
+ continue;
+ if (ipchksum((void*)addr, sizeof(*cbh)) != 0)
+ continue;
+ if (ipchksum((void*)addr + sizeof(*cbh), tsize)
+ != GET_FARVAR(0, cbh->table_checksum))
+ continue;
+ return cbh;
+ }
+ return NULL;
+}
+
+// Try to find the coreboot memory table in the given coreboot table.
+void *
+find_cb_subtable(struct cb_header *cbh, u32 tag)
+{
+ char *tbl = (char *)cbh + sizeof(*cbh);
+ u32 count = GET_FARVAR(0, cbh->table_entries);
+ int i;
+ for (i=0; i<count; i++) {
+ struct cb_memory *cbm = (void*)tbl;
+ tbl += GET_FARVAR(0, cbm->size);
+ if (GET_FARVAR(0, cbm->tag) == tag)
+ return cbm;
+ }
+ return NULL;
+}
+
+struct cb_header *
+find_cb_table(void)
+{
+ struct cb_header *cbh = find_cb_header(0, 0x1000);
+ if (!cbh)
+ return NULL;
+ struct cb_forward *cbf = find_cb_subtable(cbh, CB_TAG_FORWARD);
+ if (cbf) {
+ dprintf(3, "Found coreboot table forwarder.\n");
+ cbh = find_cb_header(GET_FARVAR(0, cbf->forward), 0x100);
+ if (!cbh)
+ return NULL;
+ }
+ return cbh;
+}
+
+static struct cb_memory *CBMemTable;
+const char *CBvendor = "", *CBpart = "";
+
+// Populate max ram and e820 map info by scanning for a coreboot table.
+void
+coreboot_preinit(void)
+{
+ if (!CONFIG_COREBOOT)
+ return;
+
+ dprintf(3, "Attempting to find coreboot table\n");
+
+ // Find coreboot table.
+ struct cb_header *cbh = find_cb_table();
+ if (!cbh)
+ goto fail;
+ dprintf(3, "Now attempting to find coreboot memory map\n");
+ struct cb_memory *cbm = CBMemTable = find_cb_subtable(cbh, CB_TAG_MEMORY);
+ if (!cbm)
+ goto fail;
+
+ int i, count = MEM_RANGE_COUNT(cbm);
+ for (i=0; i<count; i++) {
+ struct cb_memory_range *m = &cbm->map[i];
+ u32 type = m->type;
+ if (type == CB_MEM_TABLE)
+ type = E820_RESERVED;
+ e820_add(m->start, m->size, type);
+ }
+
+ // Ughh - coreboot likes to set a map at 0x0000-0x1000, but this
+ // confuses grub. So, override it.
+ e820_add(0, 16*1024, E820_RAM);
+
+ struct cb_cbmem_ref *cbref = find_cb_subtable(cbh, CB_TAG_CBMEM_CONSOLE);
+ if (cbref) {
+ cbcon = (void*)(u32)cbref->cbmem_addr;
+ debug_banner();
+ dprintf(1, "Found coreboot cbmem console @ %llx\n", cbref->cbmem_addr);
+ }
+
+ struct cb_mainboard *cbmb = find_cb_subtable(cbh, CB_TAG_MAINBOARD);
+ if (cbmb) {
+ CBvendor = &cbmb->strings[cbmb->vendor_idx];
+ CBpart = &cbmb->strings[cbmb->part_idx];
+ dprintf(1, "Found mainboard %s %s\n", CBvendor, CBpart);
+ }
+
+ return;
+
+fail:
+ // No table found.. Use 16Megs as a dummy value.
+ dprintf(1, "Unable to find coreboot table!\n");
+ e820_add(0, 16*1024*1024, E820_RAM);
+ return;
+}
+
+void coreboot_debug_putc(char c)
+{
+ if (!CONFIG_DEBUG_COREBOOT)
+ return;
+ if (!cbcon)
+ return;
+ u32 cursor = cbcon->cursor & CBMC_CURSOR_MASK;
+ u32 flags = cbcon->cursor & ~CBMC_CURSOR_MASK;
+ if (cursor >= cbcon->size)
+ return; // Old coreboot version with legacy overflow mechanism.
+ cbcon->body[cursor++] = c;
+ if (cursor >= cbcon->size) {
+ cursor = 0;
+ flags |= CBMC_OVERFLOW;
+ }
+ cbcon->cursor = flags | cursor;
+}
+
+/****************************************************************
+ * BIOS table copying
+ ****************************************************************/
+
+// Attempt to find (and relocate) any standard bios tables found in a
+// given address range.
+static void
+scan_tables(u32 start, u32 size)
+{
+ void *p = (void*)ALIGN(start, 16);
+ void *end = (void*)start + size;
+ for (; p<end; p += 16)
+ copy_table(p);
+}
+
+void
+coreboot_platform_setup(void)
+{
+ if (!CONFIG_COREBOOT)
+ return;
+ pci_probe_devices();
+
+ struct cb_memory *cbm = CBMemTable;
+ if (!cbm)
+ return;
+
+ dprintf(3, "Relocating coreboot bios tables\n");
+
+ // Scan CB_MEM_TABLE areas for bios tables.
+ int i, count = MEM_RANGE_COUNT(cbm);
+ for (i=0; i<count; i++) {
+ struct cb_memory_range *m = &cbm->map[i];
+ if (m->type == CB_MEM_TABLE)
+ scan_tables(m->start, m->size);
+ }
+
+ find_acpi_features();
+}
+
+
+/****************************************************************
+ * ulzma
+ ****************************************************************/
+
+// Uncompress data in flash to an area of memory.
+static int
+ulzma(u8 *dst, u32 maxlen, const u8 *src, u32 srclen)
+{
+ dprintf(3, "Uncompressing data %d@%p to %d@%p\n", srclen, src, maxlen, dst);
+ CLzmaDecoderState state;
+ int ret = LzmaDecodeProperties(&state.Properties, src, LZMA_PROPERTIES_SIZE);
+ if (ret != LZMA_RESULT_OK) {
+ dprintf(1, "LzmaDecodeProperties error - %d\n", ret);
+ return -1;
+ }
+ u8 scratch[15980];
+ int need = (LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+ if (need > sizeof(scratch)) {
+ dprintf(1, "LzmaDecode need %d have %d\n", need, (unsigned int)sizeof(scratch));
+ return -1;
+ }
+ state.Probs = (CProb *)scratch;
+
+ u32 dstlen = *(u32*)(src + LZMA_PROPERTIES_SIZE);
+ if (dstlen > maxlen) {
+ dprintf(1, "LzmaDecode too large (max %d need %d)\n", maxlen, dstlen);
+ return -1;
+ }
+ u32 inProcessed, outProcessed;
+ ret = LzmaDecode(&state, src + LZMA_PROPERTIES_SIZE + 8, srclen
+ , &inProcessed, dst, dstlen, &outProcessed);
+ if (ret) {
+ dprintf(1, "LzmaDecode returned %d\n", ret);
+ return -1;
+ }
+ return dstlen;
+}
+
+
+/****************************************************************
+ * Coreboot flash format
+ ****************************************************************/
+
+#define CBFS_HEADER_MAGIC 0x4F524243
+#define CBFS_VERSION1 0x31313131
+
+struct cbfs_header {
+ u32 magic;
+ u32 version;
+ u32 romsize;
+ u32 bootblocksize;
+ u32 align;
+ u32 offset;
+ u32 pad[2];
+} PACKED;
+
+#define CBFS_FILE_MAGIC 0x455649484352414cLL // LARCHIVE
+
+struct cbfs_file {
+ u64 magic;
+ u32 len;
+ u32 type;
+ u32 checksum;
+ u32 offset;
+ char filename[0];
+} PACKED;
+
+struct cbfs_romfile_s {
+ struct romfile_s file;
+ struct cbfs_file *fhdr;
+ void *data;
+ u32 rawsize, flags;
+};
+
+// Copy a file to memory (uncompressing if necessary)
+static int
+cbfs_copyfile(struct romfile_s *file, void *dst, u32 maxlen)
+{
+ if (!CONFIG_COREBOOT_FLASH)
+ return -1;
+
+ struct cbfs_romfile_s *cfile;
+ cfile = container_of(file, struct cbfs_romfile_s, file);
+ u32 size = cfile->rawsize;
+ void *src = cfile->data;
+ if (cfile->flags) {
+ // Compressed - copy to temp ram and uncompress it.
+ void *temp = malloc_tmphigh(size);
+ if (!temp) {
+ warn_noalloc();
+ return -1;
+ }
+ iomemcpy(temp, src, size);
+ int ret = ulzma(dst, maxlen, temp, size);
+ yield();
+ free(temp);
+ return ret;
+ }
+
+ // 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;
+}
+
+// Process CBFS links file. The links file is a newline separated
+// file where each line has a "link name" and a "destination name"
+// separated by a space character.
+static void
+process_links_file(void)
+{
+ char *links = romfile_loadfile("links", NULL), *next = links;
+ while (next) {
+ // Parse out linkname and destname
+ char *linkname = next;
+ next = strchr(linkname, '\n');
+ if (next)
+ *next++ = '\0';
+ char *comment = strchr(linkname, '#');
+ if (comment)
+ *comment = '\0';
+ linkname = nullTrailingSpace(linkname);
+ char *destname = strchr(linkname, ' ');
+ if (!destname)
+ continue;
+ *destname++ = '\0';
+ destname = nullTrailingSpace(destname);
+ // Lookup destname and create new romfile entry for linkname
+ struct romfile_s *ufile = romfile_find(destname);
+ if (!ufile)
+ continue;
+ struct cbfs_romfile_s *cufile
+ = container_of(ufile, struct cbfs_romfile_s, file);
+ struct cbfs_romfile_s *cfile = malloc_tmp(sizeof(*cfile));
+ if (!cfile) {
+ warn_noalloc();
+ break;
+ }
+ memcpy(cfile, cufile, sizeof(*cfile));
+ strtcpy(cfile->file.name, linkname, sizeof(cfile->file.name));
+ romfile_add(&cfile->file);
+ }
+ free(links);
+}
+
+void
+coreboot_cbfs_init(void)
+{
+ if (!CONFIG_COREBOOT_FLASH)
+ 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));
+ return;
+ }
+ dprintf(1, "Found CBFS header at %p\n", hdr);
+
+ u32 romsize = be32_to_cpu(hdr->romsize);
+ u32 romstart = CONFIG_CBFS_LOCATION - romsize;
+ struct cbfs_file *fhdr = (void*)romstart + be32_to_cpu(hdr->offset);
+ for (;;) {
+ if ((u32)fhdr - romstart > romsize)
+ break;
+ u64 magic = fhdr->magic;
+ if (magic != CBFS_FILE_MAGIC)
+ break;
+ struct cbfs_romfile_s *cfile = malloc_tmp(sizeof(*cfile));
+ if (!cfile) {
+ warn_noalloc();
+ break;
+ }
+ memset(cfile, 0, sizeof(*cfile));
+ strtcpy(cfile->file.name, fhdr->filename, sizeof(cfile->file.name));
+ cfile->file.size = cfile->rawsize = be32_to_cpu(fhdr->len);
+ cfile->fhdr = fhdr;
+ cfile->file.copy = cbfs_copyfile;
+ cfile->data = (void*)fhdr + be32_to_cpu(fhdr->offset);
+ int len = strlen(cfile->file.name);
+ if (len > 5 && strcmp(&cfile->file.name[len-5], ".lzma") == 0) {
+ // Using compression.
+ cfile->flags = 1;
+ cfile->file.name[len-5] = '\0';
+ cfile->file.size = *(u32*)(cfile->data + LZMA_PROPERTIES_SIZE);
+ }
+ romfile_add(&cfile->file);
+
+ fhdr = (void*)ALIGN((u32)cfile->data + cfile->rawsize
+ , be32_to_cpu(hdr->align));
+ }
+
+ process_links_file();
+}
+
+struct cbfs_payload_segment {
+ u32 type;
+ u32 compression;
+ u32 offset;
+ u64 load_addr;
+ u32 len;
+ u32 mem_len;
+} PACKED;
+
+#define PAYLOAD_SEGMENT_BSS 0x20535342
+#define PAYLOAD_SEGMENT_ENTRY 0x52544E45
+
+#define CBFS_COMPRESS_NONE 0
+#define CBFS_COMPRESS_LZMA 1
+
+struct cbfs_payload {
+ struct cbfs_payload_segment segments[1];
+};
+
+void
+cbfs_run_payload(struct cbfs_file *fhdr)
+{
+ if (!CONFIG_COREBOOT_FLASH || !fhdr)
+ return;
+ dprintf(1, "Run %s\n", fhdr->filename);
+ struct cbfs_payload *pay = (void*)fhdr + be32_to_cpu(fhdr->offset);
+ struct cbfs_payload_segment *seg = pay->segments;
+ for (;;) {
+ void *src = (void*)pay + be32_to_cpu(seg->offset);
+ void *dest = (void*)(u32)be64_to_cpu(seg->load_addr);
+ u32 src_len = be32_to_cpu(seg->len);
+ u32 dest_len = be32_to_cpu(seg->mem_len);
+ switch (seg->type) {
+ case PAYLOAD_SEGMENT_BSS:
+ dprintf(3, "BSS segment %d@%p\n", dest_len, dest);
+ memset(dest, 0, dest_len);
+ break;
+ case PAYLOAD_SEGMENT_ENTRY: {
+ dprintf(1, "Calling addr %p\n", dest);
+ void (*func)(void) = dest;
+ func();
+ return;
+ }
+ default:
+ dprintf(3, "Segment %x %d@%p -> %d@%p\n"
+ , seg->type, src_len, src, dest_len, dest);
+ if (seg->compression == cpu_to_be32(CBFS_COMPRESS_NONE)) {
+ if (src_len > dest_len)
+ src_len = dest_len;
+ memcpy(dest, src, src_len);
+ } else if (CONFIG_LZMA
+ && seg->compression == cpu_to_be32(CBFS_COMPRESS_LZMA)) {
+ int ret = ulzma(dest, dest_len, src, src_len);
+ if (ret < 0)
+ return;
+ src_len = ret;
+ } else {
+ dprintf(1, "No support for compression type %x\n"
+ , seg->compression);
+ return;
+ }
+ if (dest_len > src_len)
+ memset(dest + src_len, 0, dest_len - src_len);
+ break;
+ }
+ seg++;
+ }
+}
+
+// Register payloads in "img/" directory with boot system.
+void
+cbfs_payload_setup(void)
+{
+ if (!CONFIG_COREBOOT_FLASH)
+ return;
+ struct romfile_s *file = NULL;
+ for (;;) {
+ file = romfile_findprefix("img/", file);
+ if (!file)
+ break;
+ struct cbfs_romfile_s *cfile;
+ cfile = container_of(file, struct cbfs_romfile_s, file);
+ const char *filename = file->name;
+ char *desc = znprintf(MAXDESCSIZE, "Payload [%s]", &filename[4]);
+ boot_add_cbfs(cfile->fhdr, desc, bootprio_find_named_rom(filename, 0));
+ }
+}
diff --git a/roms/seabios-hppa/src/fw/csm.c b/roms/seabios-hppa/src/fw/csm.c
new file mode 100644
index 000000000..c0be9eb33
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/csm.c
@@ -0,0 +1,374 @@
+// Compatibility Support Module (CSM) for UEFI / EDK-II
+//
+// Copyright © 2013 Intel Corporation
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "bregs.h" // struct bregs
+#include "config.h" // CONFIG_*
+#include "e820map.h" // e820_add
+#include "farptr.h" // MAKE_FLATPTR
+#include "hw/pci.h" // pci_to_bdf
+#include "hw/pcidevice.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
+
+#define UINT8 u8
+#define UINT16 u16
+#define UINT32 u32
+#include "std/LegacyBios.h"
+
+struct rsdp_descriptor csm_rsdp VARFSEG __aligned(16);
+
+EFI_COMPATIBILITY16_TABLE csm_compat_table VARFSEG __aligned(16) = {
+ .Signature = 0x24454649,
+ .TableChecksum = 0 /* Filled in by checkrom.py */,
+ .TableLength = sizeof(csm_compat_table),
+ .Compatibility16CallSegment = SEG_BIOS,
+ .Compatibility16CallOffset = 0 /* Filled in by checkrom.py */,
+ .OemIdStringPointer = (u32)"SeaBIOS",
+ .AcpiRsdPtrPointer = (u32)&csm_rsdp,
+};
+
+EFI_TO_COMPATIBILITY16_INIT_TABLE *csm_init_table;
+EFI_TO_COMPATIBILITY16_BOOT_TABLE *csm_boot_table;
+
+static u16 PICMask = PIC_IRQMASK_DEFAULT;
+
+extern void __csm_return(struct bregs *regs) __noreturn;
+
+static void
+csm_return(struct bregs *regs)
+{
+ u32 rommax = rom_get_max();
+
+ dprintf(3, "handle_csm returning AX=%04x\n", regs->ax);
+
+ csm_compat_table.UmaAddress = rommax;
+ csm_compat_table.UmaSize = SYMBOL(final_readonly_start) - rommax;
+
+ PICMask = pic_irqmask_read();
+ __csm_return(regs);
+}
+
+static void
+csm_maininit(struct bregs *regs)
+{
+ interface_init();
+ pci_probe_devices();
+
+ csm_compat_table.PnPInstallationCheckSegment = SEG_BIOS;
+ csm_compat_table.PnPInstallationCheckOffset = get_pnp_offset();
+
+ regs->ax = 0;
+
+ csm_return(regs);
+}
+
+/* Legacy16InitializeYourself */
+static void
+handle_csm_0000(struct bregs *regs)
+{
+ qemu_preinit();
+
+ dprintf(3, "Legacy16InitializeYourself table %04x:%04x\n", regs->es,
+ regs->bx);
+
+ csm_init_table = MAKE_FLATPTR(regs->es, regs->bx);
+
+ dprintf(3, "BiosLessThan1MB %08x\n", csm_init_table->BiosLessThan1MB);
+ dprintf(3, "HiPmmMemory %08x\n", csm_init_table->HiPmmMemory);
+ dprintf(3, "HiPmmMemorySize %08x\n", csm_init_table->HiPmmMemorySizeInBytes);
+ dprintf(3, "ReverseThunk %04x:%04x\n", csm_init_table->ReverseThunkCallSegment,
+ csm_init_table->ReverseThunkCallOffset);
+ dprintf(3, "NumE820Entries %08x\n", csm_init_table->NumberE820Entries);
+ dprintf(3, "OsMemoryAbove1M %08x\n", csm_init_table->OsMemoryAbove1Mb);
+ dprintf(3, "ThunkStart %08x\n", csm_init_table->ThunkStart);
+ dprintf(3, "ThunkSize %08x\n", csm_init_table->ThunkSizeInBytes);
+ dprintf(3, "LoPmmMemory %08x\n", csm_init_table->LowPmmMemory);
+ dprintf(3, "LoPmmMemorySize %08x\n", csm_init_table->LowPmmMemorySizeInBytes);
+
+ malloc_csm_preinit(csm_init_table->LowPmmMemory,
+ csm_init_table->LowPmmMemorySizeInBytes,
+ csm_init_table->HiPmmMemory,
+ csm_init_table->HiPmmMemorySizeInBytes);
+ reloc_preinit(csm_maininit, regs);
+}
+
+/* Legacy16UpdateBbs */
+static void
+handle_csm_0001(struct bregs *regs)
+{
+ if (!CONFIG_BOOT) {
+ regs->ax = 1;
+ return;
+ }
+
+ dprintf(3, "Legacy16UpdateBbs table %04x:%04x\n", regs->es, regs->bx);
+
+ csm_boot_table = MAKE_FLATPTR(regs->es, regs->bx);
+ dprintf(3, "MajorVersion %04x\n", csm_boot_table->MajorVersion);
+ dprintf(3, "MinorVersion %04x\n", csm_boot_table->MinorVersion);
+ dprintf(3, "AcpiTable %08x\n", csm_boot_table->AcpiTable);
+ dprintf(3, "SmbiosTable %08x\n", csm_boot_table->SmbiosTable);
+ dprintf(3, "SmbiosTableLength %08x\n", csm_boot_table->SmbiosTableLength);
+// dprintf(3, "SioData %08x\n", csm_boot_table->SioData);
+ dprintf(3, "DevicePathType %04x\n", csm_boot_table->DevicePathType);
+ dprintf(3, "PciIrqMask %04x\n", csm_boot_table->PciIrqMask);
+ dprintf(3, "NumberE820Entries %08x\n", csm_boot_table->NumberE820Entries);
+// dprintf(3, "HddInfo %08x\n", csm_boot_table->HddInfo);
+ dprintf(3, "NumberBbsEntries %08x\n", csm_boot_table->NumberBbsEntries);
+ dprintf(3, "BBsTable %08x\n", csm_boot_table->BbsTable);
+ dprintf(3, "SmmTable %08x\n", csm_boot_table->SmmTable);
+ dprintf(3, "OsMemoryAbove1Mb %08x\n", csm_boot_table->OsMemoryAbove1Mb);
+ dprintf(3, "UnconventionalDeviceTable %08x\n", csm_boot_table->UnconventionalDeviceTable);
+
+ regs->ax = 0;
+}
+
+/* PrepareToBoot */
+static void
+handle_csm_0002(struct bregs *regs)
+{
+ if (!CONFIG_BOOT) {
+ regs->ax = 1;
+ return;
+ }
+
+ dprintf(3, "PrepareToBoot table %04x:%04x\n", regs->es, regs->bx);
+
+ struct e820entry *p = (void *)csm_compat_table.E820Pointer;
+ int i;
+ for (i=0; i < csm_compat_table.E820Length / sizeof(struct e820entry); i++)
+ 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;
+ e820_add(hi_pmm_end - BUILD_MAX_HIGHTABLE, BUILD_MAX_HIGHTABLE, E820_RESERVED);
+ }
+
+ // For PCIBIOS 1ab10e
+ if (csm_compat_table.IrqRoutingTablePointer &&
+ csm_compat_table.IrqRoutingTableLength) {
+ PirAddr = (void *)csm_compat_table.IrqRoutingTablePointer;
+ dprintf(3, "CSM PIRQ table at %p\n", PirAddr);
+ }
+
+ // For find_resume_vector()... and find_acpi_features()
+ if (csm_rsdp.signature == RSDP_SIGNATURE) {
+ RsdpAddr = &csm_rsdp;
+ dprintf(3, "CSM ACPI RSDP at %p\n", RsdpAddr);
+
+ find_acpi_features();
+ }
+
+ // SMBIOS table needs to be copied into the f-seg
+ // XX: OVMF doesn't seem to set SmbiosTableLength so don't check it
+ if (csm_boot_table->SmbiosTable && !SMBiosAddr)
+ copy_smbios((void *)csm_boot_table->SmbiosTable);
+
+ // MPTABLE is just there; we don't care where.
+
+ // EFI may have reinitialised the video using its *own* driver.
+ enable_vga_console();
+
+ // EFI fills this in for us. Zero it for now...
+ struct bios_data_area_s *bda = get_bda_ptr();
+ bda->hdcount = 0;
+
+ thread_setup();
+ mathcp_setup();
+ timer_setup();
+ clock_setup();
+ device_hardware_setup();
+ wait_threads();
+ interactive_bootmenu();
+
+ prepareboot();
+
+ regs->ax = 0;
+}
+
+/* Boot */
+static void
+handle_csm_0003(struct bregs *regs)
+{
+ if (!CONFIG_BOOT) {
+ regs->ax = 1;
+ return;
+ }
+
+ dprintf(3, "Boot\n");
+
+ startBoot();
+
+ regs->ax = 1;
+}
+
+/* Legacy16DispatchOprom */
+static void
+handle_csm_0005(struct bregs *regs)
+{
+ EFI_DISPATCH_OPROM_TABLE *table = MAKE_FLATPTR(regs->es, regs->bx);
+ struct rom_header *rom;
+ u16 bdf;
+
+ if (!CONFIG_OPTIONROMS) {
+ regs->ax = 1;
+ return;
+ }
+
+ dprintf(3, "Legacy16DispatchOprom rom %p\n", table);
+
+ dprintf(3, "OpromSegment %04x\n", table->OpromSegment);
+ dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
+ dprintf(3, "PnPInstallationCheck %04x:%04x\n",
+ table->PnPInstallationCheckSegment,
+ table->PnPInstallationCheckOffset);
+ dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
+
+ rom = MAKE_FLATPTR(table->OpromSegment, 0);
+ bdf = pci_bus_devfn_to_bdf(table->PciBus, table->PciDeviceFunction);
+
+ rom_reserve(rom->size * 512);
+
+ // XX PnP seg/ofs should never be other than default
+ callrom(rom, bdf);
+
+ rom_confirm(rom->size * 512);
+
+ regs->bx = 0; // FIXME
+ regs->ax = 0;
+}
+
+/* Legacy16GetTableAddress */
+static void
+handle_csm_0006(struct bregs *regs)
+{
+ u16 size = regs->cx;
+ u16 align = regs->dx;
+ u16 region = regs->bx; // (1 for F000 seg, 2 for E000 seg, 0 for either)
+ void *chunk = NULL;
+
+ dprintf(3, "Legacy16GetTableAddress size %x align %x region %d\n",
+ size, align, region);
+
+ if (!region)
+ region = 3;
+
+ // DX = Required address alignment. Bit mapped.
+ // First non-zero bit from the right is the alignment.*/
+ if (align) {
+ align = 1 << __ffs(align);
+ if (align < MALLOC_MIN_ALIGN)
+ align = MALLOC_MIN_ALIGN;
+ } else {
+ align = MALLOC_MIN_ALIGN;
+ }
+
+ if (region & 2)
+ chunk = _malloc(&ZoneLow, size, align);
+ if (!chunk && (region & 1))
+ chunk = _malloc(&ZoneFSeg, size, align);
+
+ dprintf(3, "Legacy16GetTableAddress size %x align %x region %d yields %p\n",
+ size, align, region, chunk);
+ if (chunk) {
+ regs->ds = FLATPTR_TO_SEG(chunk);
+ regs->bx = FLATPTR_TO_OFFSET(chunk);
+ regs->ax = 0;
+ } else {
+ regs->ax = 1;
+ }
+}
+
+void VISIBLE32INIT
+handle_csm(struct bregs *regs)
+{
+ ASSERT32FLAT();
+
+ if (!CONFIG_CSM)
+ return;
+
+ dprintf(3, "handle_csm regs %p AX=%04x\n", regs, regs->ax);
+
+ code_mutable_preinit();
+ pic_irqmask_write(PICMask);
+
+ switch(regs->ax) {
+ case 0000: handle_csm_0000(regs); break;
+ case 0001: handle_csm_0001(regs); break;
+ case 0002: handle_csm_0002(regs); break;
+ case 0003: handle_csm_0003(regs); break;
+// case 0004: handle_csm_0004(regs); break;
+ case 0005: handle_csm_0005(regs); break;
+ case 0006: handle_csm_0006(regs); break;
+// case 0007: handle_csm_0007(regs); break;
+// case 0008: hamdle_csm_0008(regs); break;
+ default: regs->al = 1;
+ }
+
+ csm_return(regs);
+}
+
+static int csm_prio_to_seabios(u16 csm_prio)
+{
+ switch (csm_prio) {
+ case BBS_DO_NOT_BOOT_FROM:
+ case BBS_IGNORE_ENTRY:
+ return -1;
+
+ case BBS_LOWEST_PRIORITY:
+ case BBS_UNPRIORITIZED_ENTRY:
+ default:
+ // SeaBIOS default priorities start at 1, with 0 being used for
+ // an item explicitly selected from interactive_bootmenu().
+ // As in find_prio(), add 1 to the value being returned.
+ return csm_prio + 1;
+ }
+}
+
+int csm_bootprio_ata(struct pci_device *pci, int chanid, int slave)
+{
+ if (!csm_boot_table)
+ return -1;
+ BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
+ int index = 1 + (chanid * 2) + slave;
+ dprintf(3, "CSM bootprio for ATA%d,%d (index %d) is %d\n", chanid, slave,
+ index, bbs[index].BootPriority);
+ return csm_prio_to_seabios(bbs[index].BootPriority);
+}
+
+int csm_bootprio_fdc(struct pci_device *pci, int port, int fdid)
+{
+ if (!csm_boot_table)
+ return -1;
+ BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
+ dprintf(3, "CSM bootprio for FDC is %d\n", bbs[0].BootPriority);
+ return csm_prio_to_seabios(bbs[0].BootPriority);
+}
+
+int csm_bootprio_pci(struct pci_device *pci)
+{
+ if (!csm_boot_table)
+ return -1;
+ BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
+ int i;
+
+ for (i = 5; i < csm_boot_table->NumberBbsEntries; i++) {
+ if (pci->bdf == pci_to_bdf(bbs[i].Bus, bbs[i].Device, bbs[i].Function)) {
+ dprintf(3, "CSM bootprio for PCI(%d,%d,%d) is %d\n", bbs[i].Bus,
+ bbs[i].Device, bbs[i].Function, bbs[i].BootPriority);
+ return csm_prio_to_seabios(bbs[i].BootPriority);
+ }
+ }
+ return -1;
+}
diff --git a/roms/seabios-hppa/src/fw/dev-pci.h b/roms/seabios-hppa/src/fw/dev-pci.h
new file mode 100644
index 000000000..30bb25a33
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/dev-pci.h
@@ -0,0 +1,52 @@
+#ifndef _PCI_CAP_H
+#define _PCI_CAP_H
+
+#include "types.h"
+
+/*
+ *
+ * QEMU-specific vendor(Red Hat)-specific capability.
+ * It's intended to provide some hints for firmware to init PCI devices.
+ *
+ * Its structure is shown below:
+ *
+ * Header:
+ *
+ * u8 id; Standard PCI Capability Header field
+ * u8 next; Standard PCI Capability Header field
+ * u8 len; Standard PCI Capability Header field
+ * u8 type; Red Hat vendor-specific capability type
+ * Data:
+ *
+ * u32 bus_res; minimum bus number to reserve;
+ * this is necessary for PCI Express Root Ports
+ * to support PCI bridges hotplug
+ * u64 io; IO space to reserve
+ * u32 mem; non-prefetchable memory to reserve
+ *
+ * At most of the following two fields may be set to a value
+ * different from 0xFF...F:
+ * u32 prefetchable_mem_32; prefetchable memory to reserve (32-bit MMIO)
+ * u64 prefetchable_mem_64; prefetchable memory to reserve (64-bit MMIO)
+ *
+ * If any field value in Data section is 0xFF...F,
+ * it means that such kind of reservation is not needed and must be ignored.
+ *
+*/
+
+/* Offset of vendor-specific capability type field */
+#define PCI_CAP_REDHAT_TYPE_OFFSET 3
+
+/* List of valid Red Hat vendor-specific capability types */
+#define REDHAT_CAP_RESOURCE_RESERVE 1
+
+
+/* Offsets of RESOURCE_RESERVE capability fields */
+#define RES_RESERVE_BUS_RES 4
+#define RES_RESERVE_IO 8
+#define RES_RESERVE_MEM 16
+#define RES_RESERVE_PREF_MEM_32 20
+#define RES_RESERVE_PREF_MEM_64 24
+#define RES_RESERVE_CAP_SIZE 32
+
+#endif /* _PCI_CAP_H */
diff --git a/roms/seabios-hppa/src/fw/dev-piix.h b/roms/seabios-hppa/src/fw/dev-piix.h
new file mode 100644
index 000000000..c389f171a
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/dev-piix.h
@@ -0,0 +1,29 @@
+#ifndef __DEV_PIIX_H
+#define __DEV_PIIX_H
+
+#define I440FX_PAM0 0x59
+#define I440FX_SMRAM 0x72
+
+#define PIIX_PMBASE 0x40
+#define PIIX_PMREGMISC 0x80
+#define PIIX_SMBHSTBASE 0x90
+#define PIIX_SMBHSTCFG 0xd2
+#define PIIX_DEVACTB 0x58
+#define PIIX_DEVACTB_APMC_EN (1 << 25)
+
+#define PIIX_PORT_ELCR1 0x4d0
+#define PIIX_PORT_ELCR2 0x4d1
+
+/* ICH9 PM I/O registers */
+#define PIIX_GPE0_BLK 0xafe0
+#define PIIX_GPE0_BLK_LEN 4
+#define PIIX_PMIO_GLBCTL 0x28
+#define PIIX_PMIO_GLBCTL_SMI_EN 1
+
+/* FADT ACPI_ENABLE/ACPI_DISABLE */
+#define PIIX_ACPI_ENABLE 0xf1
+#define PIIX_ACPI_DISABLE 0xf0
+
+#define PIIX_PM_INTRRUPT 9 // irq 9
+
+#endif // dev-piix.h
diff --git a/roms/seabios-hppa/src/fw/dev-q35.h b/roms/seabios-hppa/src/fw/dev-q35.h
new file mode 100644
index 000000000..201825deb
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/dev-q35.h
@@ -0,0 +1,52 @@
+#ifndef __DEV_Q35_H
+#define __DEV_Q35_H
+
+#include "types.h" // u16
+
+#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0
+#define Q35_HOST_BRIDGE_PAM0 0x90
+#define Q35_HOST_BRIDGE_SMRAM 0x9d
+#define Q35_HOST_BRIDGE_PCIEXBAR 0x60
+#define Q35_HOST_BRIDGE_PCIEXBAR_SIZE (256 * 1024 * 1024)
+#define Q35_HOST_BRIDGE_PCIEXBAR_ADDR 0xb0000000
+#define Q35_HOST_BRIDGE_PCIEXBAREN ((u64)1)
+#define Q35_HOST_PCIE_PCI_SEGMENT 0
+#define Q35_HOST_PCIE_START_BUS_NUMBER 0
+#define Q35_HOST_PCIE_END_BUS_NUMBER 255
+
+#define PCI_DEVICE_ID_INTEL_ICH9_LPC 0x2918
+#define ICH9_LPC_PMBASE 0x40
+#define ICH9_LPC_PMBASE_RTE 0x1
+
+#define ICH9_LPC_ACPI_CTRL 0x44
+#define ICH9_LPC_ACPI_CTRL_ACPI_EN 0x80
+#define ICH9_LPC_PIRQA_ROUT 0x60
+#define ICH9_LPC_PIRQE_ROUT 0x68
+#define ICH9_LPC_PIRQ_ROUT_IRQEN 0x80
+#define ICH9_LPC_GEN_PMCON_1 0xa0
+#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
+#define ICH9_SMB_HOSTC_HST_EN 0x01
+
+#define ICH9_ACPI_ENABLE 0x2
+#define ICH9_ACPI_DISABLE 0x3
+
+/* ICH9 LPC PM I/O registers are 128 ports and 128-aligned */
+#define ICH9_PMIO_GPE0_STS 0x20
+#define ICH9_PMIO_GPE0_BLK_LEN 0x10
+#define ICH9_PMIO_SMI_EN 0x30
+#define ICH9_PMIO_SMI_EN_APMC_EN (1 << 5)
+#define ICH9_PMIO_SMI_EN_GLB_SMI_EN (1 << 0)
+
+/* FADT ACPI_ENABLE/ACPI_DISABLE */
+#define ICH9_APM_ACPI_ENABLE 0x2
+#define ICH9_APM_ACPI_DISABLE 0x3
+
+#endif // dev-q35.h
diff --git a/roms/seabios-hppa/src/fw/dsdt_parser.c b/roms/seabios-hppa/src/fw/dsdt_parser.c
new file mode 100644
index 000000000..eb5496f35
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/dsdt_parser.c
@@ -0,0 +1,673 @@
+// Support for parsing dsdt acpi tables
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "list.h" // hlist_*
+#include "malloc.h" // malloc_*
+#include "output.h" // dprintf
+#include "string.h" // memcpy
+#include "util.h"
+#include "std/acpi.h" // struct rsdp_descriptor
+
+/****************************************************************
+ * DSDT parser
+ ****************************************************************/
+
+struct acpi_device {
+ struct hlist_node node;
+ char name[16];
+ u8 *hid_aml;
+ u8 *sta_aml;
+ u8 *crs_data;
+ int crs_size;
+};
+static struct hlist_head acpi_devices VARVERIFY32INIT;
+static const int parse_dumpdevs = 0;
+
+struct parse_state {
+ char name[32];
+ struct acpi_device *dev;
+ int error;
+ int depth;
+};
+
+static void parse_termlist(struct parse_state *s,
+ u8 *ptr, int offset, int pkglength);
+
+static void hex(const u8 *ptr, int count, int lvl, const char *item)
+{
+ int l = 0, i;
+
+ do {
+ dprintf(lvl, "%s: %04x: ", item, l);
+ for (i = l; i < l+16; i += 4)
+ dprintf(lvl, "%02x %02x %02x %02x ",
+ ptr[i+0], ptr[i+1], ptr[i+2], ptr[i+3]);
+ for (i = l; i < l+16; i++)
+ dprintf(lvl, "%c", (ptr[i] > 0x20 && ptr[i] < 0x80)
+ ? ptr[i] : '.');
+ dprintf(lvl, "\n");
+ l += 16;
+ } while (l < count);
+}
+
+static u64 parse_resource_int(u8 *ptr, int count)
+{
+ u64 value = 0;
+ int index = 0;
+
+ for (index = 0; index < count; index++)
+ value |= (u64)ptr[index] << (index * 8);
+ return value;
+}
+
+static int parse_resource_bit(u8 *ptr, int count)
+{
+ int bit;
+
+ for (bit = 0; bit < count*8; bit++)
+ if (ptr[bit/8] & (1 << (bit%8)))
+ return bit;
+ return 0;
+}
+
+static int parse_resource(u8 *ptr, int length, int *type, u64 *min, u64 *max)
+{
+ int rname, rsize;
+ u64 len;
+
+ *type = -1;
+ *min = 0;
+ *max = 0;
+ len = 0;
+ if (!(ptr[0] & 0x80)) {
+ /* small resource */
+ rname = (ptr[0] >> 3) & 0x0f;
+ rsize = ptr[0] & 0x07;
+ rsize++;
+ switch (rname) {
+ case 0x04: /* irq */
+ *min = parse_resource_bit(ptr + 1, rsize);
+ *max = *min;
+ *type = 3;
+ break;
+ case 0x0f: /* end marker */
+ return 0;
+ case 0x08: /* io */
+ *min = parse_resource_int(ptr + 2, 2);
+ *max = parse_resource_int(ptr + 4, 2);
+ if (*min == *max) {
+ *max = *min + ptr[7] - 1;
+ *type = 1;
+ }
+ break;
+ case 0x09: /* fixed io */
+ *min = parse_resource_int(ptr + 2, 2);
+ *max = *min + ptr[4] - 1;
+ *type = 1;
+ break;
+ default:
+ dprintf(3, "%s: small: 0x%x (len %d)\n",
+ __func__, rname, rsize);
+ break;
+ }
+ } else {
+ /* large resource */
+ rname = ptr[0] & 0x7f;
+ rsize = ptr[2] << 8 | ptr[1];
+ rsize += 3;
+ switch (rname) {
+ case 0x06: /* 32-bit Fixed Location Memory Range Descriptor */
+ *min = parse_resource_int(ptr + 4, 4);
+ len = parse_resource_int(ptr + 8, 4);
+ *max = *min + len - 1;
+ *type = 0;
+ break;
+ case 0x07: /* DWORD Address Space Descriptor */
+ *min = parse_resource_int(ptr + 10, 4);
+ *max = parse_resource_int(ptr + 14, 4);
+ *type = ptr[3];
+ break;
+ case 0x08: /* WORD Address Space Descriptor */
+ *min = parse_resource_int(ptr + 8, 2);
+ *max = parse_resource_int(ptr + 10, 2);
+ *type = ptr[3];
+ break;
+ case 0x09: /* irq */
+ *min = parse_resource_int(ptr + 5, 4);
+ *max = *min;
+ *type = 3;
+ break;
+ case 0x0a: /* QWORD Address Space Descriptor */
+ *min = parse_resource_int(ptr + 14, 8);
+ *max = parse_resource_int(ptr + 22, 8);
+ *type = ptr[3];
+ break;
+ default:
+ dprintf(3, "%s: large: 0x%x (len %d)\n", __func__, rname, rsize);
+ break;
+ }
+ }
+ return rsize;
+}
+
+static int find_resource(u8 *ptr, int len, int kind, u64 *min, u64 *max)
+{
+ int type, size, offset = 0;
+
+ do {
+ size = parse_resource(ptr + offset, len - offset,
+ &type, min, max);
+ if (kind == type)
+ return 0;
+ offset += size;
+ } while (size > 0 && offset < len);
+ return -1;
+}
+
+static int print_resources(const char *prefix, u8 *ptr, int len)
+{
+ static const char *typename[] = { "mem", "i/o", "bus" };
+ int type, size, offset = 0;
+ u64 min, max;
+
+ do {
+ size = parse_resource(ptr + offset, len - offset,
+ &type, &min, &max);
+ switch (type) {
+ case 0:
+ case 1:
+ case 2:
+ dprintf(1, "%s%s 0x%llx -> 0x%llx\n",
+ prefix, typename[type], min, max);
+ break;
+ case 3:
+ dprintf(1, "%sirq %lld\n", prefix, min);
+ break;
+ }
+ offset += size;
+ } while (size > 0 && offset < len);
+ return -1;
+}
+
+static int parse_nameseg(u8 *ptr, char **dst)
+{
+ if (dst && *dst) {
+ *(dst[0]++) = ptr[0];
+ if (ptr[1] != '_')
+ *(dst[0]++) = ptr[1];
+ if (ptr[2] != '_')
+ *(dst[0]++) = ptr[2];
+ if (ptr[3] != '_')
+ *(dst[0]++) = ptr[3];
+ *(dst[0]) = 0;
+ }
+ return 4;
+}
+
+static int parse_namestring(struct parse_state *s,
+ u8 *ptr, const char *item)
+{
+ char *dst = s->name;
+ int offset = 0;
+ int i, count;
+
+ for (;;) {
+ switch (ptr[offset]) {
+ case 0: /* null name */
+ offset++;
+ *(dst++) = 0;
+ break;
+ case 0x2e:
+ offset++;
+ offset += parse_nameseg(ptr + offset, &dst);
+ *(dst++) = '.';
+ offset += parse_nameseg(ptr + offset, &dst);
+ break;
+ case 0x2f:
+ offset++;
+ count = ptr[offset];
+ offset++;
+ for (i = 0; i < count; i++) {
+ if (i)
+ *(dst++) = '.';
+ offset += parse_nameseg(ptr + offset, &dst);
+ }
+ break;
+ case '\\':
+ *(dst++) = '\\';
+ offset++;
+ continue;
+ case '^':
+ *(dst++) = '^';
+ offset++;
+ continue;
+ case 'A' ... 'Z':
+ case '_':
+ offset += parse_nameseg(ptr, &dst);
+ break;
+ default:
+ hex(ptr, 16, 3, __func__);
+ s->error = 1;
+ break;
+ }
+ break;
+ }
+ dprintf(5, "%s: %d %s '%s'\n", __func__, s->depth,
+ item, s->name);
+ return offset;
+}
+
+static int parse_termarg_int(u8 *ptr, int *error, u64 *dst)
+{
+ u64 value;
+ int offset = 1;
+
+ switch (ptr[0]) {
+ case 0x00: /* zero */
+ value = 0;
+ break;
+ case 0x01: /* one */
+ value = 1;
+ break;
+ case 0x0a: /* byte prefix */
+ value = ptr[1];
+ offset++;
+ break;
+ case 0x0b: /* word prefix */
+ value = ptr[1] |
+ ((unsigned long)ptr[2] << 8);
+ offset += 2;
+ break;
+ case 0x0c: /* dword prefix */
+ value = ptr[1] |
+ ((unsigned long)ptr[2] << 8) |
+ ((unsigned long)ptr[3] << 16) |
+ ((unsigned long)ptr[4] << 24);
+ offset += 4;
+ break;
+ default:
+ value = 0;
+ hex(ptr, 16, 3, __func__);
+ if (error)
+ *error = 1;
+ break;
+ }
+
+ if (dst)
+ *dst = value;
+ dprintf(5, "%s: 0x%llx\n", __func__, value);
+ return offset;
+}
+
+static int parse_pkglength(u8 *ptr, int *pkglength)
+{
+ int offset = 2;
+
+ *pkglength = 0;
+ switch (ptr[0] >> 6) {
+ case 3:
+ *pkglength |= ptr[3] << 20;
+ offset++;
+ case 2:
+ *pkglength |= ptr[2] << 12;
+ offset++;
+ case 1:
+ *pkglength |= ptr[1] << 4;
+ *pkglength |= ptr[0] & 0x0f;
+ return offset;
+ case 0:
+ default:
+ *pkglength |= ptr[0] & 0x3f;
+ return 1;
+ }
+}
+
+static int parse_pkg_common(struct parse_state *s,
+ u8 *ptr, const char *item, int *pkglength)
+{
+ int offset;
+
+ offset = parse_pkglength(ptr, pkglength);
+ offset += parse_namestring(s, ptr + offset, item);
+ return offset;
+}
+
+static int parse_pkg_scope(struct parse_state *s,
+ u8 *ptr)
+{
+ int offset, pkglength;
+
+ offset = parse_pkg_common(s, ptr, "scope", &pkglength);
+ parse_termlist(s, ptr, offset, pkglength);
+ return pkglength;
+}
+
+static int parse_pkg_device(struct parse_state *s,
+ u8 *ptr)
+{
+ int offset, pkglength;
+
+ offset = parse_pkg_common(s, ptr, "device", &pkglength);
+
+ s->dev = malloc_tmp(sizeof(struct acpi_device));
+ if (!s->dev) {
+ warn_noalloc();
+ s->error = 1;
+ return pkglength;
+ }
+
+ memset(s->dev, 0, sizeof(struct acpi_device));
+ hlist_add_head(&s->dev->node, &acpi_devices);
+ strtcpy(s->dev->name, s->name, sizeof(s->name));
+ parse_termlist(s, ptr, offset, pkglength);
+ s->dev = NULL;
+
+ return pkglength;
+}
+
+static int parse_pkg_buffer(struct parse_state *s,
+ u8 *ptr)
+{
+ u64 blen;
+ int pkglength, offset;
+
+ offset = parse_pkglength(ptr, &pkglength);
+ offset += parse_termarg_int(ptr + offset, &s->error, &blen);
+ if (s->dev && strcmp(s->name, "_CRS") == 0) {
+ s->dev->crs_data = ptr + offset;
+ s->dev->crs_size = blen;
+ }
+ return pkglength;
+}
+
+static int parse_pkg_skip(struct parse_state *s,
+ u8 *ptr, int op, int name)
+{
+ int pkglength, offset;
+ char item[8];
+
+ snprintf(item, sizeof(item), "op %x", op);
+ offset = parse_pkglength(ptr, &pkglength);
+ if (name) {
+ parse_namestring(s, ptr + offset, item);
+ } else {
+ dprintf(5, "%s: %s (%d)\n", __func__, item, pkglength);
+ }
+ return pkglength;
+}
+
+static int parse_termobj(struct parse_state *s,
+ u8 *ptr)
+{
+ int offset = 1;
+
+ if (s->depth == 16) {
+ dprintf(1, "%s: deep recursion\n", __func__);
+ s->error = 1;
+ return offset;
+ }
+
+ s->depth++;
+ switch (ptr[0]) {
+ case 0x00: /* zero */
+ break;
+ case 0x01: /* one */
+ break;
+ case 0x08: /* name op */
+ offset += parse_namestring(s, ptr + offset, "name");
+ offset += parse_termobj(s, ptr + offset);
+ if (s->dev && strcmp(s->name, "_HID") == 0)
+ s->dev->hid_aml = ptr;
+ if (s->dev && strcmp(s->name, "_STA") == 0)
+ s->dev->sta_aml = ptr;
+ break;
+ case 0x0a: /* byte prefix */
+ offset++;
+ break;
+ case 0x0b: /* word prefix */
+ offset += 2;
+ break;
+ case 0x0c: /* dword prefix */
+ offset += 4;
+ break;
+ case 0x0d: /* string prefix */
+ while (ptr[offset])
+ offset++;
+ offset++;
+ break;
+ case 0x10: /* scope op */
+ offset += parse_pkg_scope(s, ptr + offset);
+ break;
+ case 0x11: /* buffer op */
+ offset += parse_pkg_buffer(s, ptr + offset);
+ break;
+ case 0x12: /* package op */
+ case 0x13: /* var package op */
+ offset += parse_pkg_skip(s, ptr + offset, ptr[0], 0);
+ break;
+ case 0x14: /* method op */
+ offset += parse_pkg_skip(s, ptr + offset, ptr[0], 1);
+ if (s->dev && strcmp(s->name, "_STA") == 0)
+ s->dev->sta_aml = ptr;
+ break;
+ case 0x5b: /* ext op prefix */
+ offset++;
+ switch (ptr[1]) {
+ case 0x01: /* mutex op */
+ offset += parse_namestring(s, ptr + offset, "mutex");
+ offset++; /* sync flags */
+ break;
+ case 0x80: /* op region op */
+ offset += parse_namestring(s, ptr + offset, "op region");
+ offset++; /* region space */
+ offset += parse_termarg_int(ptr + offset, &s->error, NULL);
+ offset += parse_termarg_int(ptr + offset, &s->error, NULL);
+ break;
+ case 0x81: /* field op */
+ case 0x83: /* processor op */
+ case 0x84: /* power resource op */
+ case 0x85: /* thermal zone op */
+ offset += parse_pkg_skip(s, ptr + offset, 0x5b00 | ptr[1], 1);
+ break;
+ case 0x82: /* device op */
+ offset += parse_pkg_device(s, ptr + offset);
+ break;
+ default:
+ hex(ptr, 16, 3, __func__);
+ s->error = 1;
+ break;
+ }
+ break;
+ default:
+ hex(ptr, 16, 3, __func__);
+ s->error = 1;
+ break;
+ }
+ s->depth--;
+
+ return offset;
+}
+
+static void parse_termlist(struct parse_state *s,
+ u8 *ptr, int offset, int pkglength)
+{
+ for (;;) {
+ offset += parse_termobj(s, ptr + offset);
+ if (offset == pkglength)
+ return;
+ if (offset > pkglength) {
+ dprintf(1, "%s: overrun: %d/%d\n", __func__,
+ offset, pkglength);
+ s->error = 1;
+ return;
+ }
+ if (s->error) {
+ dprintf(1, "%s: parse error, skip from %d/%d\n", __func__,
+ offset, pkglength);
+ s->error = 0;
+ return;
+ }
+ }
+}
+
+static struct acpi_device *acpi_dsdt_find(struct acpi_device *prev,
+ const u8 *aml1, int size1,
+ const u8 *aml2, int size2)
+{
+ struct acpi_device *dev;
+ struct hlist_node *node;
+
+ if (!prev)
+ node = acpi_devices.first;
+ else
+ node = prev->node.next;
+
+ for (; node != NULL; node = dev->node.next) {
+ dev = container_of(node, struct acpi_device, node);
+ if (!aml1 && !aml2)
+ return dev;
+ if (!dev->hid_aml)
+ continue;
+ if (aml1 && memcmp(dev->hid_aml + 5, aml1, size1) == 0)
+ return dev;
+ if (aml2 && memcmp(dev->hid_aml + 5, aml2, size2) == 0)
+ return dev;
+ }
+ return NULL;
+}
+
+static int acpi_dsdt_present(struct acpi_device *dev)
+{
+ if (!dev)
+ return 0; /* no */
+ if (!dev->sta_aml)
+ return 1; /* yes */
+ if (dev->sta_aml[0] == 0x14)
+ return -1; /* unknown (can't evaluate method) */
+ if (dev->sta_aml[0] == 0x08) {
+ u64 value = 0;
+ parse_termarg_int(dev->sta_aml + 5, NULL, &value);
+ if (value == 0)
+ return 0; /* no */
+ else
+ return 1; /* yes */
+ }
+ return -1; /* unknown (should not happen) */
+}
+
+/****************************************************************
+ * DSDT parser, public interface
+ ****************************************************************/
+
+struct acpi_device *acpi_dsdt_find_string(struct acpi_device *prev,
+ const char *hid)
+{
+ if (!CONFIG_ACPI_PARSE)
+ return NULL;
+
+ u8 aml[10];
+ int len = snprintf((char*)aml, sizeof(aml), "\x0d%s", hid);
+ return acpi_dsdt_find(prev, aml, len, NULL, 0);
+}
+
+struct acpi_device *acpi_dsdt_find_eisaid(struct acpi_device *prev, u16 eisaid)
+{
+ if (!CONFIG_ACPI_PARSE)
+ return NULL;
+ u8 aml1[] = {
+ 0x0c, 0x41, 0xd0,
+ eisaid >> 8,
+ eisaid & 0xff
+ };
+ u8 aml2[10];
+ int len2 = snprintf((char*)aml2, sizeof(aml2), "\x0dPNP%04X", eisaid);
+ return acpi_dsdt_find(prev, aml1, 5, aml2, len2);
+}
+
+char *acpi_dsdt_name(struct acpi_device *dev)
+{
+ if (!CONFIG_ACPI_PARSE || !dev)
+ return NULL;
+ return dev->name;
+}
+
+int acpi_dsdt_find_io(struct acpi_device *dev, u64 *min, u64 *max)
+{
+ if (!CONFIG_ACPI_PARSE || !dev || !dev->crs_data)
+ return -1;
+ return find_resource(dev->crs_data, dev->crs_size,
+ 1 /* I/O */, min, max);
+}
+
+int acpi_dsdt_find_mem(struct acpi_device *dev, u64 *min, u64 *max)
+{
+ if (!CONFIG_ACPI_PARSE || !dev || !dev->crs_data)
+ return -1;
+ return find_resource(dev->crs_data, dev->crs_size,
+ 0 /* mem */, min, max);
+}
+
+int acpi_dsdt_find_irq(struct acpi_device *dev, u64 *irq)
+{
+ u64 max;
+ if (!CONFIG_ACPI_PARSE || !dev || !dev->crs_data)
+ return -1;
+ return find_resource(dev->crs_data, dev->crs_size,
+ 3 /* irq */, irq, &max);
+}
+
+int acpi_dsdt_present_eisaid(u16 eisaid)
+{
+ if (!CONFIG_ACPI_PARSE)
+ return -1; /* unknown */
+ if (hlist_empty(&acpi_devices))
+ return -1; /* unknown (no dsdt table) */
+
+ struct acpi_device *dev = acpi_dsdt_find_eisaid(NULL, eisaid);
+ return acpi_dsdt_present(dev);
+}
+
+void acpi_dsdt_parse(void)
+{
+ if (!CONFIG_ACPI_PARSE)
+ return;
+
+ struct fadt_descriptor_rev1 *fadt = find_acpi_table(FACP_SIGNATURE);
+ if (!fadt)
+ return;
+ u8 *dsdt = (void*)(fadt->dsdt);
+ if (!dsdt)
+ return;
+
+ u32 length = *(u32*)(dsdt + 4);
+ u32 offset = 0x24;
+ dprintf(1, "ACPI: parse DSDT at %p (len %d)\n", dsdt, length);
+
+ struct parse_state s;
+ memset(&s, 0, sizeof(s));
+ parse_termlist(&s, dsdt, offset, length);
+
+ if (!parse_dumpdevs)
+ return;
+
+ struct acpi_device *dev;
+ dprintf(1, "ACPI: dumping dsdt devices\n");
+ for (dev = acpi_dsdt_find(NULL, NULL, 0, NULL, 0);
+ dev != NULL;
+ dev = acpi_dsdt_find(dev, NULL, 0, NULL, 0)) {
+ dprintf(1, " %s", acpi_dsdt_name(dev));
+ if (dev->hid_aml)
+ dprintf(1, ", hid");
+ if (dev->sta_aml)
+ dprintf(1, ", sta (0x%x)", dev->sta_aml[0]);
+ if (dev->crs_data)
+ dprintf(1, ", crs");
+ dprintf(1, "\n");
+ if (dev->crs_data)
+ print_resources(" ", dev->crs_data, dev->crs_size);
+ }
+}
diff --git a/roms/seabios-hppa/src/fw/lzmadecode.c b/roms/seabios-hppa/src/fw/lzmadecode.c
new file mode 100644
index 000000000..65819b53c
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/lzmadecode.c
@@ -0,0 +1,398 @@
+/*
+ LzmaDecode.c
+ LZMA Decoder (optimized for Speed version)
+
+ LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this Code, expressly permits you to
+ statically or dynamically link your Code (or bind by name) to the
+ interfaces of this file without subjecting your linked Code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "lzmadecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+ { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+
+
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+ { UpdateBit0(p); mi <<= 1; A0; } else \
+ { UpdateBit1(p); mi = (mi + mi) + 1; A1; }
+
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+ { int i = numLevels; res = 1; \
+ do { CProb *cp = probs + res; RC_GET_BIT(cp, res) } while(--i != 0); \
+ res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+ unsigned char prop0;
+ if (size < LZMA_PROPERTIES_SIZE)
+ return LZMA_RESULT_DATA_ERROR;
+ prop0 = propsData[0];
+ if (prop0 >= (9 * 5 * 5))
+ return LZMA_RESULT_DATA_ERROR;
+ {
+ for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+ for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+ propsRes->lc = prop0;
+ /*
+ unsigned char remainder = (unsigned char)(prop0 / 9);
+ propsRes->lc = prop0 % 9;
+ propsRes->pb = remainder / 5;
+ propsRes->lp = remainder % 5;
+ */
+ }
+
+ return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+ CProb *p = vs->Probs;
+ SizeT nowPos = 0;
+ Byte previousByte = 0;
+ UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+ UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+ int lc = vs->Properties.lc;
+
+
+ int state = 0;
+ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+ int len = 0;
+ const Byte *Buffer;
+ const Byte *BufferLim;
+ UInt32 Range;
+ UInt32 Code;
+
+ *inSizeProcessed = 0;
+ *outSizeProcessed = 0;
+
+ {
+ UInt32 i;
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ }
+
+ RC_INIT(inStream, inSize);
+
+
+ while(nowPos < outSize)
+ {
+ CProb *prob;
+ UInt32 bound;
+ int posState = (int)(
+ (nowPos
+ )
+ & posStateMask);
+
+ prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ int symbol = 1;
+ UpdateBit0(prob)
+ prob = p + Literal + (LZMA_LIT_SIZE *
+ (((
+ (nowPos
+ )
+ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+ if (state >= kNumLitStates)
+ {
+ int matchByte;
+ matchByte = outStream[nowPos - rep0];
+ do
+ {
+ int bit;
+ CProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & 0x100);
+ probLit = prob + 0x100 + bit + symbol;
+ RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+ }
+ while (symbol < 0x100);
+ }
+ while (symbol < 0x100)
+ {
+ CProb *probLit = prob + symbol;
+ RC_GET_BIT(probLit, symbol)
+ }
+ previousByte = (Byte)symbol;
+
+ outStream[nowPos++] = previousByte;
+ if (state < 4) state = 0;
+ else if (state < 10) state -= 3;
+ else state -= 6;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRep + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < kNumLitStates ? 0 : 3;
+ prob = p + LenCoder;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG0 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+
+ if (nowPos == 0)
+ return LZMA_RESULT_DATA_ERROR;
+
+ state = state < kNumLitStates ? 9 : 11;
+ previousByte = outStream[nowPos - rep0];
+ outStream[nowPos++] = previousByte;
+
+ continue;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ }
+ }
+ else
+ {
+ UInt32 distance;
+ UpdateBit1(prob);
+ prob = p + IsRepG1 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG2 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = p + RepLenCoder;
+ }
+ {
+ int numBits, offset;
+ CProb *probLen = prob + LenChoice;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ numBits = kLenNumLowBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenChoice2;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ numBits = kLenNumMidBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ numBits = kLenNumHighBits;
+ }
+ }
+ RangeDecoderBitTreeDecode(probLen, numBits, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ int posSlot;
+ state += kNumLitStates;
+ prob = p + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+ rep0 = (2 | ((UInt32)posSlot & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ rep0 <<= numDirectBits;
+ prob = p + SpecPos + rep0 - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ RC_NORMALIZE
+ Range >>= 1;
+ rep0 <<= 1;
+ if (Code >= Range)
+ {
+ Code -= Range;
+ rep0 |= 1;
+ }
+ }
+ while (--numDirectBits != 0);
+ prob = p + Align;
+ rep0 <<= kNumAlignBits;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ int i = 1;
+ int mi = 1;
+ do
+ {
+ CProb *prob3 = prob + mi;
+ RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+ i <<= 1;
+ }
+ while(--numDirectBits != 0);
+ }
+ }
+ else
+ rep0 = posSlot;
+ if (++rep0 == (UInt32)(0))
+ {
+ /* it's for stream version */
+ len = kLzmaStreamWasFinishedId;
+ break;
+ }
+ }
+
+ len += kMatchMinLen;
+ if (rep0 > nowPos)
+ return LZMA_RESULT_DATA_ERROR;
+
+
+ do
+ {
+ previousByte = outStream[nowPos - rep0];
+ len--;
+ outStream[nowPos++] = previousByte;
+ }
+ while(len != 0 && nowPos < outSize);
+ }
+ }
+ RC_NORMALIZE;
+
+
+ *inSizeProcessed = (SizeT)(Buffer - inStream);
+ *outSizeProcessed = nowPos;
+ return LZMA_RESULT_OK;
+}
diff --git a/roms/seabios-hppa/src/fw/lzmadecode.h b/roms/seabios-hppa/src/fw/lzmadecode.h
new file mode 100644
index 000000000..dedde0de6
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/lzmadecode.h
@@ -0,0 +1,67 @@
+/*
+ LzmaDecode.h
+ LZMA Decoder interface
+
+ LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+typedef unsigned char Byte;
+typedef unsigned short UInt16;
+typedef unsigned int UInt32;
+typedef UInt32 SizeT;
+
+#define CProb UInt16
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+ int lc;
+ int lp;
+ int pb;
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+ CLzmaProperties Properties;
+ CProb *Probs;
+
+
+} CLzmaDecoderState;
+
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
diff --git a/roms/seabios-hppa/src/fw/mptable.c b/roms/seabios-hppa/src/fw/mptable.c
new file mode 100644
index 000000000..47385cc5d
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/mptable.c
@@ -0,0 +1,197 @@
+// MPTable generation (on emulators)
+// DO NOT ADD NEW FEATURES HERE. (See paravirt.c / biostables.c instead.)
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "hw/pci.h" // pci_bdf_to_bus
+#include "hw/pcidevice.h" // foreachpci
+#include "hw/pci_regs.h" // PCI_INTERRUPT_PIN
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "romfile.h" // romfile_loadint
+#include "std/mptable.h" // MPTABLE_SIGNATURE
+#include "string.h" // memset
+#include "util.h" // MaxCountCPUs
+#include "x86.h" // cpuid
+
+void
+mptable_setup(void)
+{
+ if (! CONFIG_MPTABLE)
+ return;
+
+ dprintf(3, "init MPTable\n");
+
+ // Config structure in temp area.
+ struct mptable_config_s *config = malloc_tmp(32*1024);
+ if (!config) {
+ warn_noalloc();
+ return;
+ }
+ memset(config, 0, sizeof(*config));
+ config->signature = MPCONFIG_SIGNATURE;
+ config->spec = 4;
+ memcpy(config->oemid, BUILD_CPUNAME8, sizeof(config->oemid));
+ memcpy(config->productid, "0.1 ", sizeof(config->productid));
+ config->lapic = BUILD_APIC_ADDR;
+
+ // Detect cpu info
+ u32 cpuid_signature, ebx, ecx, cpuid_features;
+ cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features);
+ if (! cpuid_signature) {
+ // Use default values.
+ cpuid_signature = 0x600;
+ cpuid_features = 0x201;
+ }
+ int pkgcpus = 1;
+ if (cpuid_features & (1 << 28)) {
+ /* Only populate the MPS tables with the first logical CPU in
+ each package */
+ pkgcpus = (ebx >> 16) & 0xff;
+ pkgcpus = 1 << (__fls(pkgcpus - 1) + 1); /* round up to power of 2 */
+ }
+ u8 apic_version = readl((u8*)BUILD_APIC_ADDR + 0x30) & 0xff;
+
+ // CPU definitions.
+ struct mpt_cpu *cpus = (void*)&config[1], *cpu = cpus;
+ int i;
+ for (i = 0; i < MaxCountCPUs; i+=pkgcpus) {
+ memset(cpu, 0, sizeof(*cpu));
+ cpu->type = MPT_TYPE_CPU;
+ cpu->apicid = i;
+ cpu->apicver = apic_version;
+ /* cpu flags: enabled, bootstrap cpu */
+ cpu->cpuflag = (apic_id_is_present(i) ? 0x01 : 0x00) | ((i==0) ? 0x02 : 0x00);
+ cpu->cpusignature = cpuid_signature;
+ cpu->featureflag = cpuid_features;
+ cpu++;
+ }
+ int entrycount = cpu - cpus;
+
+ // PCI bus
+ struct mpt_bus *buses = (void*)cpu, *bus = buses;
+ if (!hlist_empty(&PCIDevices)) {
+ memset(bus, 0, sizeof(*bus));
+ bus->type = MPT_TYPE_BUS;
+ bus->busid = 0;
+ memcpy(bus->bustype, "PCI ", sizeof(bus->bustype));
+ bus++;
+ entrycount++;
+ }
+
+ /* isa bus */
+ int isabusid = bus - buses;
+ memset(bus, 0, sizeof(*bus));
+ bus->type = MPT_TYPE_BUS;
+ bus->busid = isabusid;
+ memcpy(bus->bustype, "ISA ", sizeof(bus->bustype));
+ bus++;
+ entrycount++;
+
+ /* ioapic */
+ u8 ioapic_id = BUILD_IOAPIC_ID;
+ struct mpt_ioapic *ioapic = (void*)bus;
+ memset(ioapic, 0, sizeof(*ioapic));
+ ioapic->type = MPT_TYPE_IOAPIC;
+ ioapic->apicid = ioapic_id;
+ ioapic->apicver = 0x11;
+ ioapic->flags = 1; // enable
+ ioapic->apicaddr = BUILD_IOAPIC_ADDR;
+ entrycount++;
+
+ /* irqs */
+ struct mpt_intsrc *intsrcs = (void*)&ioapic[1], *intsrc = intsrcs;
+ int dev = -1;
+ unsigned short pinmask = 0;
+
+ struct pci_device *pci;
+ foreachpci(pci) {
+ u16 bdf = pci->bdf;
+ if (pci_bdf_to_bus(bdf) != 0)
+ break;
+ int pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
+ int irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+ if (pin == 0)
+ continue;
+ if (dev != pci_bdf_to_busdev(bdf)) {
+ dev = pci_bdf_to_busdev(bdf);
+ pinmask = 0;
+ }
+ if (pinmask & (1 << pin)) /* pin was seen already */
+ continue;
+ pinmask |= (1 << pin);
+ memset(intsrc, 0, sizeof(*intsrc));
+ intsrc->type = MPT_TYPE_INTSRC;
+ intsrc->irqtype = 0; /* INT */
+ intsrc->irqflag = 1; /* active high */
+ intsrc->srcbus = pci_bdf_to_bus(bdf); /* PCI bus */
+ intsrc->srcbusirq = (pci_bdf_to_dev(bdf) << 2) | (pin - 1);
+ intsrc->dstapic = ioapic_id;
+ intsrc->dstirq = irq;
+ intsrc++;
+ }
+
+ int irq0_override = romfile_loadint("etc/irq0-override", 0);
+ for (i = 0; i < 16; i++) {
+ memset(intsrc, 0, sizeof(*intsrc));
+ if (BUILD_PCI_IRQS & (1 << i))
+ continue;
+ intsrc->type = MPT_TYPE_INTSRC;
+ intsrc->irqtype = 0; /* INT */
+ intsrc->irqflag = 0; /* conform to bus spec */
+ intsrc->srcbus = isabusid; /* ISA bus */
+ intsrc->srcbusirq = i;
+ intsrc->dstapic = ioapic_id;
+ intsrc->dstirq = i;
+ if (irq0_override) {
+ /* Destination 2 is covered by irq0->inti2 override (i ==
+ 0). Source IRQ 2 is unused */
+ if (i == 0)
+ intsrc->dstirq = 2;
+ else if (i == 2)
+ intsrc--;
+ }
+ intsrc++;
+ }
+
+ /* Local interrupt assignment */
+ intsrc->type = MPT_TYPE_LOCAL_INT;
+ intsrc->irqtype = 3; /* ExtINT */
+ intsrc->irqflag = 0; /* PO, EL default */
+ intsrc->srcbus = isabusid; /* ISA */
+ intsrc->srcbusirq = 0;
+ intsrc->dstapic = 0; /* BSP == APIC #0 */
+ intsrc->dstirq = 0; /* LINTIN0 */
+ intsrc++;
+
+ intsrc->type = MPT_TYPE_LOCAL_INT;
+ intsrc->irqtype = 1; /* NMI */
+ intsrc->irqflag = 0; /* PO, EL default */
+ intsrc->srcbus = isabusid; /* ISA */
+ intsrc->srcbusirq = 0;
+ intsrc->dstapic = 0xff; /* to all local APICs */
+ intsrc->dstirq = 1; /* LINTIN1 */
+ intsrc++;
+ entrycount += intsrc - intsrcs;
+
+ // Finalize config structure.
+ int length = (void*)intsrc - (void*)config;
+ config->entrycount = entrycount;
+ config->length = length;
+ config->checksum -= checksum(config, length);
+
+ // floating pointer structure
+ struct mptable_floating_s floating;
+ memset(&floating, 0, sizeof(floating));
+ floating.signature = MPTABLE_SIGNATURE;
+ floating.physaddr = (u32)config;
+ floating.length = 1;
+ floating.spec_rev = 4;
+ floating.checksum -= checksum(&floating, sizeof(floating));
+ copy_mptable(&floating);
+ free(config);
+}
diff --git a/roms/seabios-hppa/src/fw/mtrr.c b/roms/seabios-hppa/src/fw/mtrr.c
new file mode 100644
index 000000000..3e799cea2
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/mtrr.c
@@ -0,0 +1,105 @@
+// Initialize MTRRs - mostly useful on KVM.
+//
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "output.h" // dprintf
+#include "paravirt.h" // RamSize
+#include "util.h" // mtrr_setup
+#include "x86.h" // cpuid
+
+#define MSR_MTRRcap 0x000000fe
+#define MSR_MTRRfix64K_00000 0x00000250
+#define MSR_MTRRfix16K_80000 0x00000258
+#define MSR_MTRRfix16K_A0000 0x00000259
+#define MSR_MTRRfix4K_C0000 0x00000268
+#define MSR_MTRRfix4K_C8000 0x00000269
+#define MSR_MTRRfix4K_D0000 0x0000026a
+#define MSR_MTRRfix4K_D8000 0x0000026b
+#define MSR_MTRRfix4K_E0000 0x0000026c
+#define MSR_MTRRfix4K_E8000 0x0000026d
+#define MSR_MTRRfix4K_F0000 0x0000026e
+#define MSR_MTRRfix4K_F8000 0x0000026f
+#define MSR_MTRRdefType 0x000002ff
+
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
+#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+#define MTRR_MEMTYPE_UC 0
+#define MTRR_MEMTYPE_WC 1
+#define MTRR_MEMTYPE_WT 4
+#define MTRR_MEMTYPE_WP 5
+#define MTRR_MEMTYPE_WB 6
+
+void mtrr_setup(void)
+{
+ if (!CONFIG_MTRR_INIT)
+ return;
+
+ u32 eax, ebx, ecx, edx, cpuid_features;
+ cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+ if (!(cpuid_features & CPUID_MTRR))
+ return;
+ if (!(cpuid_features & CPUID_MSR))
+ return;
+
+ dprintf(3, "init mtrr\n");
+
+ u32 mtrr_cap = rdmsr(MSR_MTRRcap);
+ int vcnt = mtrr_cap & 0xff;
+ int fix = mtrr_cap & 0x100;
+ if (!vcnt || !fix)
+ return;
+
+ // Disable MTRRs
+ wrmsr_smp(MSR_MTRRdefType, 0);
+
+ // Set fixed MTRRs
+ union u64b {
+ u8 valb[8];
+ u64 val;
+ } u;
+ u.val = 0;
+ int i;
+ for (i = 0; i < 8; i++)
+ if (RamSize >= 65536 * (i + 1))
+ u.valb[i] = MTRR_MEMTYPE_WB;
+ wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
+ u.val = 0;
+ for (i = 0; i < 8; i++)
+ if (RamSize >= 0x80000 + 16384 * (i + 1))
+ u.valb[i] = MTRR_MEMTYPE_WB;
+ wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
+ wrmsr_smp(MSR_MTRRfix16K_A0000, 0); // 0xA0000-0xC0000 is uncached
+ int j;
+ for (j = 0; j < 8; j++) {
+ u.val = 0;
+ for (i = 0; i < 8; i++)
+ if (RamSize >= 0xC0000 + j * 0x8000 + 4096 * (i + 1))
+ u.valb[i] = MTRR_MEMTYPE_WP;
+ wrmsr_smp(MSR_MTRRfix4K_C0000 + j, u.val);
+ }
+
+ // Set variable MTRRs
+ int phys_bits = 36;
+ cpuid(0x80000000u, &eax, &ebx, &ecx, &edx);
+ if (eax >= 0x80000008) {
+ /* Get physical bits from leaf 0x80000008 (if available) */
+ cpuid(0x80000008u, &eax, &ebx, &ecx, &edx);
+ phys_bits = eax & 0xff;
+ }
+ u64 phys_mask = ((1ull << phys_bits) - 1);
+ for (i=0; i<vcnt; i++) {
+ wrmsr_smp(MTRRphysBase_MSR(i), 0);
+ wrmsr_smp(MTRRphysMask_MSR(i), 0);
+ }
+ /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
+ wrmsr_smp(MTRRphysBase_MSR(0), pcimem_start | MTRR_MEMTYPE_UC);
+ wrmsr_smp(MTRRphysMask_MSR(0)
+ , (-((1ull<<32)-pcimem_start) & phys_mask) | 0x800);
+
+ // Enable fixed and variable MTRRs; set default type.
+ wrmsr_smp(MSR_MTRRdefType, 0xc00 | MTRR_MEMTYPE_WB);
+}
diff --git a/roms/seabios-hppa/src/fw/multiboot.c b/roms/seabios-hppa/src/fw/multiboot.c
new file mode 100644
index 000000000..d9df06764
--- /dev/null
+++ b/roms/seabios-hppa/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/roms/seabios-hppa/src/fw/paravirt.c b/roms/seabios-hppa/src/fw/paravirt.c
new file mode 100644
index 000000000..fba4e52db
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/paravirt.c
@@ -0,0 +1,721 @@
+// Paravirtualization support.
+//
+// Copyright (C) 2013 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2009 Red Hat Inc.
+//
+// Authors:
+// Gleb Natapov <gnatapov@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "byteorder.h" // be32_to_cpu
+#include "config.h" // CONFIG_QEMU
+#include "e820map.h" // e820_add
+#include "hw/pci.h" // pci_config_readw
+#include "hw/pcidevice.h" // pci_probe_devices
+#include "hw/pci_regs.h" // PCI_DEVICE_ID
+#include "hw/serialio.h" // PORT_SERIAL1
+#include "hw/rtc.h" // CMOS_*
+#include "hw/virtio-mmio.h" // virtio_mmio_acpi
+#include "malloc.h" // malloc_tmp
+#include "output.h" // dprintf
+#include "paravirt.h" // qemu_cfg_preinit
+#include "romfile.h" // romfile_loadint
+#include "romfile_loader.h" // romfile_loader_execute
+#include "string.h" // memset
+#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;
+// Amount of continuous ram >4Gig
+u64 RamSizeOver4G;
+// Type of emulator platform.
+int PlatformRunningOn VARFSEG;
+// cfg enabled
+int cfg_enabled = 0;
+// cfg_dma enabled
+int cfg_dma_enabled = 0;
+
+inline int qemu_cfg_enabled(void)
+{
+ return cfg_enabled;
+}
+
+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.
+ */
+#define KVM_CPUID_SIGNATURE 0x40000000
+
+static void kvm_detect(void)
+{
+ unsigned int eax, ebx, ecx, edx;
+ char signature[13];
+
+ cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
+ memcpy(signature + 0, &ebx, 4);
+ memcpy(signature + 4, &ecx, 4);
+ memcpy(signature + 8, &edx, 4);
+ signature[12] = 0;
+
+ if (strcmp(signature, "KVMKVMKVM") == 0) {
+ dprintf(1, "Running on KVM\n");
+ PlatformRunningOn |= PF_KVM;
+ if (eax >= KVM_CPUID_SIGNATURE + 0x10) {
+ cpuid(KVM_CPUID_SIGNATURE + 0x10, &eax, &ebx, &ecx, &edx);
+ dprintf(1, "kvm: have invtsc, freq %u kHz\n", eax);
+ tsctimer_setfreq(eax, "invtsc");
+ }
+ }
+}
+
+#define KVM_FEATURE_CLOCKSOURCE 0
+#define KVM_FEATURE_CLOCKSOURCE2 3
+
+#define MSR_KVM_SYSTEM_TIME 0x12
+#define MSR_KVM_SYSTEM_TIME_NEW 0x4b564d01
+
+#define PVCLOCK_TSC_STABLE_BIT (1 << 0)
+
+struct pvclock_vcpu_time_info *kvmclock;
+
+static void kvmclock_init(void)
+{
+ unsigned int eax, ebx, ecx, edx, msr;
+
+ if (!runningOnKVM())
+ return;
+
+ cpuid(KVM_CPUID_SIGNATURE + 0x01, &eax, &ebx, &ecx, &edx);
+ if (eax & (1 << KVM_FEATURE_CLOCKSOURCE2))
+ msr = MSR_KVM_SYSTEM_TIME_NEW;
+ else if (eax & (1 << KVM_FEATURE_CLOCKSOURCE))
+ msr = MSR_KVM_SYSTEM_TIME;
+ else
+ return;
+
+ kvmclock = memalign_low(sizeof(*kvmclock), 32);
+ memset(kvmclock, 0, sizeof(*kvmclock));
+ u32 value = (u32)(kvmclock);
+ dprintf(1, "kvmclock: at 0x%x (msr 0x%x)\n", value, msr);
+ wrmsr(msr, value | 0x01);
+
+ if (!(kvmclock->flags & PVCLOCK_TSC_STABLE_BIT))
+ return;
+ u32 MHz = (1000 << 16) / (kvmclock->tsc_to_system_mul >> 16);
+ if (kvmclock->tsc_shift < 0)
+ MHz <<= -kvmclock->tsc_shift;
+ else
+ MHz >>= kvmclock->tsc_shift;
+ dprintf(1, "kvmclock: stable tsc, %d MHz\n", MHz);
+ tsctimer_setfreq(MHz * 1000, "kvmclock");
+}
+
+static void qemu_detect(void)
+{
+ if (!CONFIG_QEMU_HARDWARE)
+ return;
+
+ // Setup QEMU debug output port
+ qemu_debug_preinit();
+
+ // check northbridge @ 00:00.0
+ u16 v = pci_config_readw(0, PCI_VENDOR_ID);
+ if (v == 0x0000 || v == 0xffff)
+ return;
+ u16 d = pci_config_readw(0, PCI_DEVICE_ID);
+ u16 sv = pci_config_readw(0, PCI_SUBSYSTEM_VENDOR_ID);
+ u16 sd = pci_config_readw(0, PCI_SUBSYSTEM_ID);
+
+ if (sv != 0x1af4 || /* Red Hat, Inc */
+ sd != 0x1100) /* Qemu virtual machine */
+ return;
+
+ PlatformRunningOn |= PF_QEMU;
+ switch (d) {
+ case 0x1237:
+ dprintf(1, "Running on QEMU (i440fx)\n");
+ break;
+ case 0x29c0:
+ dprintf(1, "Running on QEMU (q35)\n");
+ break;
+ default:
+ dprintf(1, "Running on QEMU (unknown nb: %04x:%04x)\n", v, d);
+ break;
+ }
+}
+
+static int qemu_early_e820(void);
+
+void
+qemu_preinit(void)
+{
+ qemu_detect();
+ kvm_detect();
+
+ if (!CONFIG_QEMU)
+ return;
+
+ if (runningOnXen()) {
+ xen_ramsize_preinit();
+ return;
+ }
+
+ // try read e820 table first
+ if (!qemu_early_e820()) {
+ // when it fails get memory size from nvram.
+ u32 rs = ((rtc_read(CMOS_MEM_EXTMEM2_LOW) << 16)
+ | (rtc_read(CMOS_MEM_EXTMEM2_HIGH) << 24));
+ if (rs)
+ rs += 16 * 1024 * 1024;
+ else
+ rs = (((rtc_read(CMOS_MEM_EXTMEM_LOW) << 10)
+ | (rtc_read(CMOS_MEM_EXTMEM_HIGH) << 18))
+ + 1 * 1024 * 1024);
+ RamSize = rs;
+ e820_add(0, rs, E820_RAM);
+ dprintf(1, "RamSize: 0x%08x [cmos]\n", RamSize);
+ }
+
+ /* reserve 256KB BIOS area at the end of 4 GB */
+ e820_add(0xfffc0000, 256*1024, E820_RESERVED);
+}
+
+#define MSR_IA32_FEATURE_CONTROL 0x0000003a
+
+static void msr_feature_control_setup(void)
+{
+ u64 feature_control_bits = romfile_loadint("etc/msr_feature_control", 0);
+ if (feature_control_bits)
+ wrmsr_smp(MSR_IA32_FEATURE_CONTROL, feature_control_bits);
+}
+
+void
+qemu_platform_setup(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ if (runningOnXen()) {
+ pci_probe_devices();
+ xen_hypercall_setup();
+ xen_biostable_setup();
+ return;
+ }
+
+ kvmclock_init();
+
+ // Initialize pci
+ pci_setup();
+ smm_device_setup();
+ smm_setup();
+
+ // Initialize mtrr, msr_feature_control and smp
+ mtrr_setup();
+ msr_feature_control_setup();
+ smp_setup();
+
+ // Create bios tables
+ if (MaxCountCPUs <= 255) {
+ pirtable_setup();
+ mptable_setup();
+ }
+ smbios_setup();
+
+ if (CONFIG_FW_ROMFILE_LOAD) {
+ int loader_err;
+
+ dprintf(3, "load ACPI tables\n");
+
+ loader_err = romfile_loader_execute("etc/table-loader");
+
+ RsdpAddr = find_acpi_rsdp();
+
+ if (RsdpAddr) {
+ acpi_dsdt_parse();
+ virtio_mmio_setup_acpi();
+ return;
+ }
+ /* If present, loader should have installed an RSDP.
+ * Not installed? We might still be able to continue
+ * using the builtin RSDP.
+ */
+ if (!loader_err)
+ warn_internalerror();
+ }
+
+ acpi_setup();
+}
+
+
+/****************************************************************
+ * QEMU firmware config (fw_cfg) interface
+ ****************************************************************/
+
+// List of QEMU fw_cfg entries. DO NOT ADD MORE. (All new content
+// should be passed via the fw_cfg "file" interface.)
+#define QEMU_CFG_SIGNATURE 0x00
+#define QEMU_CFG_ID 0x01
+#define QEMU_CFG_UUID 0x02
+#define QEMU_CFG_NOGRAPHIC 0x04
+#define QEMU_CFG_NUMA 0x0d
+#define QEMU_CFG_BOOT_MENU 0x0e
+#define QEMU_CFG_NB_CPUS 0x05
+#define QEMU_CFG_MAX_CPUS 0x0f
+#define QEMU_CFG_FILE_DIR 0x19
+#define QEMU_CFG_ARCH_LOCAL 0x8000
+#define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0)
+#define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1)
+#define QEMU_CFG_IRQ0_OVERRIDE (QEMU_CFG_ARCH_LOCAL + 2)
+#define QEMU_CFG_E820_TABLE (QEMU_CFG_ARCH_LOCAL + 3)
+
+static void
+qemu_cfg_select(u16 f)
+{
+ outw(f, PORT_QEMU_CFG_CTL);
+}
+
+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)
+{
+ 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_write(void *buf, int len)
+{
+ if (len == 0) {
+ return;
+ }
+
+ if (qemu_cfg_dma_enabled()) {
+ qemu_cfg_dma_transfer(buf, len, QEMU_CFG_DMA_CTL_WRITE);
+ } else {
+ warn_internalerror();
+ }
+}
+
+static void
+qemu_cfg_skip(int len)
+{
+ 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)
+{
+ 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);
+ }
+}
+
+static void
+qemu_cfg_write_entry(void *buf, int e, int len)
+{
+ if (qemu_cfg_dma_enabled()) {
+ u32 control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT
+ | QEMU_CFG_DMA_CTL_WRITE;
+ qemu_cfg_dma_transfer(buf, len, control);
+ } else {
+ warn_internalerror();
+ }
+}
+
+struct qemu_romfile_s {
+ struct romfile_s file;
+ int select, skip;
+};
+
+static int
+qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen)
+{
+ if (file->size > maxlen)
+ return -1;
+ struct qemu_romfile_s *qfile;
+ qfile = container_of(file, struct qemu_romfile_s, file);
+ 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;
+}
+
+// Bare-bones function for writing a file knowing only its unique
+// identifying key (select)
+int
+qemu_cfg_write_file_simple(void *src, u16 key, u32 offset, u32 len)
+{
+ if (offset == 0) {
+ /* Do it in one transfer */
+ qemu_cfg_write_entry(src, key, len);
+ } else {
+ qemu_cfg_select(key);
+ qemu_cfg_skip(offset);
+ qemu_cfg_write(src, len);
+ }
+ return len;
+}
+
+int
+qemu_cfg_write_file(void *src, struct romfile_s *file, u32 offset, u32 len)
+{
+ if ((offset + len) > file->size)
+ return -1;
+
+ if (!qemu_cfg_dma_enabled() || (file->copy != qemu_cfg_read_file)) {
+ warn_internalerror();
+ return -1;
+ }
+ return qemu_cfg_write_file_simple(src, qemu_get_romfile_key(file),
+ offset, len);
+}
+
+static void
+qemu_romfile_add(char *name, int select, int skip, int size)
+{
+ struct qemu_romfile_s *qfile = malloc_tmp(sizeof(*qfile));
+ if (!qfile) {
+ warn_noalloc();
+ return;
+ }
+ memset(qfile, 0, sizeof(*qfile));
+ strtcpy(qfile->file.name, name, sizeof(qfile->file.name));
+ qfile->file.size = size;
+ qfile->select = select;
+ qfile->skip = skip;
+ qfile->file.copy = qemu_cfg_read_file;
+ romfile_add(&qfile->file);
+}
+
+u16
+qemu_get_romfile_key(struct romfile_s *file)
+{
+ struct qemu_romfile_s *qfile;
+ if (file->copy != qemu_cfg_read_file) {
+ warn_internalerror();
+ return 0;
+ }
+ qfile = container_of(file, struct qemu_romfile_s, file);
+ return qfile->select;
+}
+
+static int rtc_present(void)
+{
+ return rtc_read(CMOS_RTC_MONTH) != 0xff;
+}
+
+u16
+qemu_get_present_cpus_count(void)
+{
+ u16 smp_count = 0;
+ if (qemu_cfg_enabled()) {
+ qemu_cfg_read_entry(&smp_count, QEMU_CFG_NB_CPUS, sizeof(smp_count));
+ }
+ if (rtc_present()) {
+ u16 cmos_cpu_count = rtc_read(CMOS_BIOS_SMP_COUNT) + 1;
+ if (smp_count < cmos_cpu_count) {
+ smp_count = cmos_cpu_count;
+ }
+ }
+ return smp_count;
+}
+
+struct e820_reservation {
+ u64 address;
+ u64 length;
+ u32 type;
+};
+
+#define SMBIOS_FIELD_ENTRY 0
+#define SMBIOS_TABLE_ENTRY 1
+
+struct qemu_smbios_header {
+ u16 length;
+ u8 headertype;
+ u8 tabletype;
+ u16 fieldoffset;
+} PACKED;
+
+static void
+qemu_cfg_e820(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ if (romfile_find("etc/e820")) {
+ // qemu_early_e820() has handled everything
+ return;
+ }
+
+ // QEMU_CFG_E820_TABLE has reservations only
+ u32 count32;
+ qemu_cfg_read_entry(&count32, QEMU_CFG_E820_TABLE, sizeof(count32));
+ if (count32) {
+ struct e820_reservation entry;
+ int i;
+ for (i = 0; i < count32; i++) {
+ qemu_cfg_read(&entry, sizeof(entry));
+ 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
+ e820_add(0xfffbc000, 4*4096, E820_RESERVED);
+ }
+
+ // Check for memory over 4Gig in cmos
+ u64 high = ((rtc_read(CMOS_MEM_HIGHMEM_LOW) << 16)
+ | ((u32)rtc_read(CMOS_MEM_HIGHMEM_MID) << 24)
+ | ((u64)rtc_read(CMOS_MEM_HIGHMEM_HIGH) << 32));
+ RamSizeOver4G = high;
+ e820_add(0x100000000ull, high, E820_RAM);
+ dprintf(1, "RamSizeOver4G: 0x%016llx [cmos]\n", RamSizeOver4G);
+}
+
+// Populate romfile entries for legacy fw_cfg ports (that predate the
+// "file" interface).
+static void
+qemu_cfg_legacy(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ // Misc config items.
+ qemu_romfile_add("etc/show-boot-menu", QEMU_CFG_BOOT_MENU, 0, 2);
+ qemu_romfile_add("etc/irq0-override", QEMU_CFG_IRQ0_OVERRIDE, 0, 1);
+ qemu_romfile_add("etc/max-cpus", QEMU_CFG_MAX_CPUS, 0, 2);
+
+ // NUMA data
+ u64 numacount;
+ qemu_cfg_read_entry(&numacount, QEMU_CFG_NUMA, sizeof(numacount));
+ int max_cpu = romfile_loadint("etc/max-cpus", 0);
+ qemu_romfile_add("etc/numa-cpu-map", QEMU_CFG_NUMA, sizeof(numacount)
+ , max_cpu*sizeof(u64));
+ qemu_romfile_add("etc/numa-nodes", QEMU_CFG_NUMA
+ , sizeof(numacount) + max_cpu*sizeof(u64)
+ , numacount*sizeof(u64));
+
+ // ACPI tables
+ char name[128];
+ u16 cnt;
+ qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
+ int i, offset = sizeof(cnt);
+ for (i = 0; i < cnt; i++) {
+ u16 len;
+ qemu_cfg_read(&len, sizeof(len));
+ offset += sizeof(len);
+ snprintf(name, sizeof(name), "acpi/table%d", i);
+ qemu_romfile_add(name, QEMU_CFG_ACPI_TABLES, offset, len);
+ qemu_cfg_skip(len);
+ offset += len;
+ }
+
+ // SMBIOS info
+ qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
+ offset = sizeof(cnt);
+ for (i = 0; i < cnt; i++) {
+ struct qemu_smbios_header header;
+ qemu_cfg_read(&header, sizeof(header));
+ if (header.headertype == SMBIOS_FIELD_ENTRY) {
+ snprintf(name, sizeof(name), "smbios/field%d-%d"
+ , header.tabletype, header.fieldoffset);
+ qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
+ , offset + sizeof(header)
+ , header.length - sizeof(header));
+ } else {
+ snprintf(name, sizeof(name), "smbios/table%d-%d"
+ , header.tabletype, i);
+ qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
+ , offset + 3, header.length - 3);
+ }
+ qemu_cfg_skip(header.length - sizeof(header));
+ offset += header.length;
+ }
+}
+
+struct QemuCfgFile {
+ u32 size; /* file size */
+ u16 select; /* write this to 0x510 to read it */
+ u16 reserved;
+ char name[56];
+};
+
+static int qemu_cfg_detect(void)
+{
+ if (cfg_enabled)
+ return 1;
+
+ // Detect fw_cfg interface.
+ qemu_cfg_select(QEMU_CFG_SIGNATURE);
+ char *sig = "QEMU";
+ int i;
+ for (i = 0; i < 4; i++)
+ if (inb(PORT_QEMU_CFG_DATA) != sig[i])
+ return 0;
+
+ dprintf(1, "Found QEMU fw_cfg\n");
+ cfg_enabled = 1;
+
+ // 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;
+ }
+ return 1;
+}
+
+void qemu_cfg_init(void)
+{
+ if (!runningOnQEMU())
+ return;
+
+ if (!qemu_cfg_detect())
+ return;
+
+ // Populate romfiles for legacy fw_cfg entries
+ qemu_cfg_legacy();
+
+ // Load files found in the fw_cfg file directory
+ u32 count;
+ qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
+ count = be32_to_cpu(count);
+ u32 e;
+ for (e = 0; e < count; e++) {
+ struct QemuCfgFile qfile;
+ qemu_cfg_read(&qfile, sizeof(qfile));
+ qemu_romfile_add(qfile.name, be16_to_cpu(qfile.select)
+ , 0, be32_to_cpu(qfile.size));
+ }
+
+ qemu_cfg_e820();
+
+ if (romfile_find("etc/table-loader")) {
+ acpi_pm_base = 0x0600;
+ dprintf(1, "Moving pm_base to 0x%x\n", acpi_pm_base);
+ }
+
+ // serial console
+ u16 nogfx = 0;
+ qemu_cfg_read_entry(&nogfx, QEMU_CFG_NOGRAPHIC, sizeof(nogfx));
+ if (nogfx && !romfile_find("etc/sercon-port")
+ && !romfile_find("vgaroms/sgabios.bin"))
+ const_romfile_add_int("etc/sercon-port", PORT_SERIAL1);
+}
+
+/*
+ * This runs before malloc and romfile are ready, so we have to work
+ * with stack allocations and read from fw_cfg in chunks.
+ */
+static int qemu_early_e820(void)
+{
+ struct e820_reservation table;
+ struct QemuCfgFile qfile;
+ u32 select = 0, size = 0;
+ u32 count, i;
+
+ if (!qemu_cfg_detect())
+ return 0;
+
+ // find e820 table
+ qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
+ count = be32_to_cpu(count);
+ for (i = 0; i < count; i++) {
+ qemu_cfg_read(&qfile, sizeof(qfile));
+ if (memcmp(qfile.name, "etc/e820", 9) != 0)
+ continue;
+ select = be16_to_cpu(qfile.select);
+ size = be32_to_cpu(qfile.size);
+ break;
+ }
+ if (select == 0) {
+ // may happen on old qemu
+ dprintf(1, "qemu/e820: fw_cfg file etc/e820 not found\n");
+ return 0;
+ }
+
+ // walk e820 table
+ qemu_cfg_select(select);
+ count = size/sizeof(table);
+ for (i = 0, select = 0; i < count; i++) {
+ qemu_cfg_read(&table, sizeof(table));
+ switch (table.type) {
+ case E820_RESERVED:
+ e820_add(table.address, table.length, table.type);
+ dprintf(3, "qemu/e820: addr 0x%016llx len 0x%016llx [reserved]\n",
+ table.address, table.length);
+ break;
+ case E820_RAM:
+ e820_add(table.address, table.length, table.type);
+ dprintf(1, "qemu/e820: addr 0x%016llx len 0x%016llx [RAM]\n",
+ table.address, table.length);
+ if (table.address < 0x100000000LL) {
+ // below 4g
+ if (RamSize < table.address + table.length)
+ RamSize = table.address + table.length;
+ } else {
+ // above 4g
+ if (RamSizeOver4G < table.address + table.length - 0x100000000LL)
+ RamSizeOver4G = table.address + table.length - 0x100000000LL;
+ }
+ }
+ }
+
+ dprintf(3, "qemu/e820: RamSize: 0x%08x\n", RamSize);
+ dprintf(3, "qemu/e820: RamSizeOver4G: 0x%016llx\n", RamSizeOver4G);
+ return 1;
+}
diff --git a/roms/seabios-hppa/src/fw/paravirt.h b/roms/seabios-hppa/src/fw/paravirt.h
new file mode 100644
index 000000000..40ab3f5f1
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/paravirt.h
@@ -0,0 +1,85 @@
+#ifndef __PV_H
+#define __PV_H
+
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+#include "romfile.h" // struct romfile_s
+
+// kvmclock
+struct pvclock_vcpu_time_info {
+ u32 version;
+ u32 pad0;
+ u64 tsc_timestamp;
+ u64 system_time;
+ u32 tsc_to_system_mul;
+ s8 tsc_shift;
+ u8 flags;
+ u8 pad[2];
+} __attribute__((__packed__)); /* 32 bytes */
+
+// Types of paravirtualized platforms.
+#define PF_QEMU (1<<0)
+#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;
+
+static inline int runningOnQEMU(void) {
+ return CONFIG_QEMU || (
+ CONFIG_QEMU_HARDWARE && GET_GLOBAL(PlatformRunningOn) & PF_QEMU);
+}
+static inline int runningOnXen(void) {
+ return CONFIG_XEN && GET_GLOBAL(PlatformRunningOn) & PF_XEN;
+}
+static inline int runningOnKVM(void) {
+ return CONFIG_QEMU && GET_GLOBAL(PlatformRunningOn) & PF_KVM;
+}
+
+// Common paravirt ports.
+#define PORT_SMI_CMD 0x00b2
+#define PORT_SMI_STATUS 0x00b3
+#if CONFIG_PARISC
+extern unsigned long PORT_QEMU_CFG_CTL;
+#define PORT_QEMU_CFG_DATA (PORT_QEMU_CFG_CTL + 4)
+#define PORT_QEMU_CFG_DMA_ADDR_HIGH (PORT_QEMU_CFG_CTL + 8)
+#define PORT_QEMU_CFG_DMA_ADDR_LOW (PORT_QEMU_CFG_CTL + 12)
+#else
+#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
+#endif
+
+// 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
+#define QEMU_CFG_DMA_CTL_WRITE 0x10
+
+// QEMU_CFG_DMA ID bit
+#define QEMU_CFG_VERSION_DMA 2
+
+// QEMU debugcon read value
+#define QEMU_DEBUGCON_READBACK 0xe9
+
+int qemu_cfg_enabled(void);
+int qemu_cfg_dma_enabled(void);
+void qemu_preinit(void);
+void qemu_platform_setup(void);
+void qemu_cfg_init(void);
+
+u16 qemu_get_present_cpus_count(void);
+int qemu_cfg_write_file(void *src, struct romfile_s *file, u32 offset, u32 len);
+int qemu_cfg_write_file_simple(void *src, u16 key, u32 offset, u32 len);
+u16 qemu_get_romfile_key(struct romfile_s *file);
+
+#endif
diff --git a/roms/seabios-hppa/src/fw/pciinit.c b/roms/seabios-hppa/src/fw/pciinit.c
new file mode 100644
index 000000000..4c16ea078
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/pciinit.c
@@ -0,0 +1,1226 @@
+// Initialize PCI devices (on emulators)
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "byteorder.h" // le64_to_cpu
+#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/pcidevice.h" // pci_probe_devices
+#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "hw/pci_regs.h" // PCI_COMMAND
+#include "fw/dev-pci.h" // REDHAT_CAP_RESOURCE_RESERVE
+#include "list.h" // struct hlist_node
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "paravirt.h" // RamSize
+#include "romfile.h" // romfile_loadint
+#include "string.h" // memset
+#include "util.h" // pci_setup
+#include "x86.h" // outb
+
+#define PCI_DEVICE_MEM_MIN (1<<12) // 4k == page size
+#define PCI_BRIDGE_MEM_MIN (1<<21) // 2M == hugepage size
+#define PCI_BRIDGE_IO_MIN 0x1000 // mandated by pci bridge spec
+
+#define PCI_ROM_SLOT 6
+#define PCI_NUM_REGIONS 7
+#define PCI_BRIDGE_NUM_REGIONS 2
+
+enum pci_region_type {
+ PCI_REGION_TYPE_IO,
+ PCI_REGION_TYPE_MEM,
+ PCI_REGION_TYPE_PREFMEM,
+ PCI_REGION_TYPE_COUNT,
+};
+
+static const char *region_type_name[] = {
+ [ PCI_REGION_TYPE_IO ] = "io",
+ [ PCI_REGION_TYPE_MEM ] = "mem",
+ [ PCI_REGION_TYPE_PREFMEM ] = "prefmem",
+};
+
+u64 pcimem_start = BUILD_PCIMEM_START;
+u64 pcimem_end = BUILD_PCIMEM_END;
+u64 pcimem64_start = BUILD_PCIMEM64_START;
+u64 pcimem64_end = BUILD_PCIMEM64_END;
+u64 pci_io_low_end = 0xa000;
+
+struct pci_region_entry {
+ struct pci_device *dev;
+ int bar;
+ u64 size;
+ u64 align;
+ int is64;
+ enum pci_region_type type;
+ struct hlist_node node;
+};
+
+struct pci_region {
+ /* pci region assignments */
+ u64 base;
+ struct hlist_head list;
+};
+
+struct pci_bus {
+ struct pci_region r[PCI_REGION_TYPE_COUNT];
+ struct pci_device *bus_dev;
+};
+
+static u32 pci_bar(struct pci_device *pci, int region_num)
+{
+ if (region_num != PCI_ROM_SLOT) {
+ return PCI_BASE_ADDRESS_0 + region_num * 4;
+ }
+
+#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
+ u8 type = pci->header_type & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
+ return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS;
+}
+
+static void
+pci_set_io_region_addr(struct pci_device *pci, int bar, u64 addr, int is64)
+{
+ u32 ofs = pci_bar(pci, bar);
+ pci_config_writel(pci->bdf, ofs, addr);
+ if (is64)
+ pci_config_writel(pci->bdf, ofs + 4, addr >> 32);
+}
+
+
+/****************************************************************
+ * Misc. device init
+ ****************************************************************/
+
+/* host irqs corresponding to PCI irqs A-D */
+const u8 pci_irqs[4] = {
+ 10, 10, 11, 11
+};
+
+static int dummy_pci_slot_get_irq(struct pci_device *pci, int pin)
+{
+ dprintf(1, "pci_slot_get_irq called with unknown routing\n");
+
+ return 0xff; /* PCI defined "unknown" or "no connection" for x86 */
+}
+
+static int (*pci_slot_get_irq)(struct pci_device *pci, int pin) =
+ dummy_pci_slot_get_irq;
+
+// Return the global irq number corresponding to a host bus device irq pin.
+static int piix_pci_slot_get_irq(struct pci_device *pci, int pin)
+{
+ int slot_addend = 0;
+
+ while (pci->parent != NULL) {
+ slot_addend += pci_bdf_to_dev(pci->bdf);
+ pci = pci->parent;
+ }
+ slot_addend += pci_bdf_to_dev(pci->bdf) - 1;
+ return pci_irqs[(pin - 1 + slot_addend) & 3];
+}
+
+static int mch_pci_slot_get_irq(struct pci_device *pci, int pin)
+{
+ int pin_addend = 0;
+ while (pci->parent != NULL) {
+ pin_addend += pci_bdf_to_dev(pci->bdf);
+ pci = pci->parent;
+ }
+ u8 slot = pci_bdf_to_dev(pci->bdf);
+ if (slot <= 24)
+ /* Slots 0-24 rotate slot:pin mapping similar to piix above, but
+ with a different starting index - see q35-acpi-dsdt.dsl */
+ return pci_irqs[(pin - 1 + pin_addend + slot) & 3];
+ /* Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H) */
+ return pci_irqs[(pin - 1 + pin_addend) & 3];
+}
+
+/* PIIX3/PIIX4 PCI to ISA bridge */
+static void piix_isa_bridge_setup(struct pci_device *pci, void *arg)
+{
+ int i, irq;
+ u8 elcr[2];
+
+ elcr[0] = 0x00;
+ elcr[1] = 0x00;
+ for (i = 0; i < 4; i++) {
+ irq = pci_irqs[i];
+ /* set to trigger level */
+ elcr[irq >> 3] |= (1 << (irq & 7));
+ /* activate irq remapping in PIIX */
+ pci_config_writeb(pci->bdf, 0x60 + i, irq);
+ }
+ outb(elcr[0], PIIX_PORT_ELCR1);
+ outb(elcr[1], PIIX_PORT_ELCR2);
+ dprintf(1, "PIIX3/PIIX4 init: elcr=%02x %02x\n", elcr[0], elcr[1]);
+}
+
+static void mch_isa_lpc_setup(u16 bdf)
+{
+ /* pm io base */
+ pci_config_writel(bdf, ICH9_LPC_PMBASE,
+ acpi_pm_base | ICH9_LPC_PMBASE_RTE);
+
+ /* 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);
+}
+
+static int ICH9LpcBDF = -1;
+
+/* ICH9 LPC PCI to ISA bridge */
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */
+static void mch_isa_bridge_setup(struct pci_device *dev, void *arg)
+{
+ u16 bdf = dev->bdf;
+ int i, irq;
+ u8 elcr[2];
+
+ elcr[0] = 0x00;
+ elcr[1] = 0x00;
+
+ for (i = 0; i < 4; i++) {
+ irq = pci_irqs[i];
+ /* set to trigger level */
+ elcr[irq >> 3] |= (1 << (irq & 7));
+
+ /* activate irq remapping in LPC */
+
+ /* PIRQ[A-D] routing */
+ pci_config_writeb(bdf, ICH9_LPC_PIRQA_ROUT + i, irq);
+ /* PIRQ[E-H] routing */
+ pci_config_writeb(bdf, ICH9_LPC_PIRQE_ROUT + i, irq);
+ }
+ outb(elcr[0], ICH9_LPC_PORT_ELCR1);
+ outb(elcr[1], ICH9_LPC_PORT_ELCR2);
+ dprintf(1, "Q35 LPC init: elcr=%02x %02x\n", elcr[0], elcr[1]);
+
+ ICH9LpcBDF = bdf;
+
+ mch_isa_lpc_setup(bdf);
+
+ e820_add(ICH9_LPC_RCBA_ADDR, 16*1024, E820_RESERVED);
+
+ acpi_pm1a_cnt = acpi_pm_base + 0x04;
+ pmtimer_setup(acpi_pm_base + 0x08);
+}
+
+static void storage_ide_setup(struct pci_device *pci, void *arg)
+{
+ /* On parisc, keep PCI IDE IO ports in PCI mem space */
+ if (CONFIG_PARISC)
+ return;
+
+ /* IDE: we map it as in ISA mode */
+ pci_set_io_region_addr(pci, 0, PORT_ATA1_CMD_BASE, 0);
+ pci_set_io_region_addr(pci, 1, PORT_ATA1_CTRL_BASE, 0);
+ pci_set_io_region_addr(pci, 2, PORT_ATA2_CMD_BASE, 0);
+ pci_set_io_region_addr(pci, 3, PORT_ATA2_CTRL_BASE, 0);
+}
+
+/* PIIX3/PIIX4 IDE */
+static void piix_ide_setup(struct pci_device *pci, void *arg)
+{
+ u16 bdf = pci->bdf;
+ pci_config_writew(bdf, 0x40, 0x8000); // enable IDE0
+ pci_config_writew(bdf, 0x42, 0x8000); // enable IDE1
+}
+
+static void pic_ibm_setup(struct pci_device *pci, void *arg)
+{
+ /* PIC, IBM, MPIC & MPIC2 */
+ pci_set_io_region_addr(pci, 0, 0x80800000 + 0x00040000, 0);
+}
+
+static void apple_macio_setup(struct pci_device *pci, void *arg)
+{
+ /* macio bridge */
+ pci_set_io_region_addr(pci, 0, 0x80800000, 0);
+}
+
+static void piix4_pm_config_setup(u16 bdf)
+{
+ // acpi sci is hardwired to 9
+ pci_config_writeb(bdf, PCI_INTERRUPT_LINE, 9);
+
+ pci_config_writel(bdf, PIIX_PMBASE, acpi_pm_base | 1);
+ pci_config_writeb(bdf, PIIX_PMREGMISC, 0x01); /* enable PM io space */
+ pci_config_writel(bdf, PIIX_SMBHSTBASE, (acpi_pm_base + 0x100) | 1);
+ pci_config_writeb(bdf, PIIX_SMBHSTCFG, 0x09); /* enable SMBus io space */
+}
+
+static int PiixPmBDF = -1;
+
+/* PIIX4 Power Management device (for ACPI) */
+static void piix4_pm_setup(struct pci_device *pci, void *arg)
+{
+ PiixPmBDF = pci->bdf;
+ piix4_pm_config_setup(pci->bdf);
+
+ acpi_pm1a_cnt = acpi_pm_base + 0x04;
+ pmtimer_setup(acpi_pm_base + 0x08);
+}
+
+static void ich9_smbus_enable(u16 bdf)
+{
+ /* map smbus into io space */
+ pci_config_writel(bdf, ICH9_SMB_SMB_BASE,
+ (acpi_pm_base + 0x100) | PCI_BASE_ADDRESS_SPACE_IO);
+
+ /* enable SMBus */
+ pci_config_writeb(bdf, ICH9_SMB_HOSTC, ICH9_SMB_HOSTC_HST_EN);
+}
+
+static int ICH9SmbusBDF = -1;
+
+/* ICH9 SMBUS */
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_SMBUS */
+static void ich9_smbus_setup(struct pci_device *dev, void *arg)
+{
+ ICH9SmbusBDF = dev->bdf;
+
+ ich9_smbus_enable(dev->bdf);
+}
+
+static void intel_igd_setup(struct pci_device *dev, void *arg)
+{
+ struct romfile_s *opregion = romfile_find("etc/igd-opregion");
+ u64 bdsm_size = le64_to_cpu(romfile_loadint("etc/igd-bdsm-size", 0));
+
+ /* Apply OpRegion to any Intel VGA device, more than one is undefined */
+ if (opregion && opregion->size) {
+ void *addr = memalign_high(PAGE_SIZE, opregion->size);
+ if (!addr) {
+ warn_noalloc();
+ return;
+ }
+
+ if (opregion->copy(opregion, addr, opregion->size) < 0) {
+ free(addr);
+ return;
+ }
+
+ pci_config_writel(dev->bdf, 0xFC, cpu_to_le32((u32)addr));
+
+ dprintf(1, "Intel IGD OpRegion enabled at 0x%08x, size %dKB, dev %pP\n"
+ , (u32)addr, opregion->size >> 10, dev);
+ }
+
+ /* Apply BDSM only to Intel VGA at 00:02.0 */
+ if (bdsm_size && (dev->bdf == pci_to_bdf(0, 2, 0))) {
+ void *addr = memalign_tmphigh(1024 * 1024, bdsm_size);
+ if (!addr) {
+ warn_noalloc();
+ return;
+ }
+
+ e820_add((u32)addr, bdsm_size, E820_RESERVED);
+
+ pci_config_writel(dev->bdf, 0x5C, cpu_to_le32((u32)addr));
+
+ dprintf(1, "Intel IGD BDSM enabled at 0x%08x, size %lldMB, dev %pP\n"
+ , (u32)addr, bdsm_size >> 20, dev);
+ }
+}
+
+static const struct pci_device_id pci_device_tbl[] = {
+ /* PIIX3/PIIX4 PCI to ISA bridge */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0,
+ piix_isa_bridge_setup),
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
+ piix_isa_bridge_setup),
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC,
+ mch_isa_bridge_setup),
+
+ /* STORAGE IDE */
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1,
+ PCI_CLASS_STORAGE_IDE, piix_ide_setup),
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,
+ PCI_CLASS_STORAGE_IDE, piix_ide_setup),
+ PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE,
+ storage_ide_setup),
+
+ /* PIC, IBM, MPIC & MPIC2 */
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0x0046, PCI_CLASS_SYSTEM_PIC,
+ pic_ibm_setup),
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0xFFFF, PCI_CLASS_SYSTEM_PIC,
+ pic_ibm_setup),
+
+ /* PIIX4 Power Management device (for ACPI) */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+ piix4_pm_setup),
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_SMBUS,
+ ich9_smbus_setup),
+
+ /* 0xff00 */
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0017, 0xff00, apple_macio_setup),
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0022, 0xff00, apple_macio_setup),
+
+ /* Intel IGD OpRegion setup */
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA,
+ intel_igd_setup),
+
+ PCI_DEVICE_END,
+};
+
+static int MCHMmcfgBDF = -1;
+static void mch_mmconfig_setup(u16 bdf);
+
+void pci_resume(void)
+{
+ if (!CONFIG_QEMU) {
+ return;
+ }
+
+ if (PiixPmBDF >= 0) {
+ piix4_pm_config_setup(PiixPmBDF);
+ }
+
+ if (ICH9LpcBDF >= 0) {
+ mch_isa_lpc_setup(ICH9LpcBDF);
+ }
+
+ if (ICH9SmbusBDF >= 0) {
+ ich9_smbus_enable(ICH9SmbusBDF);
+ }
+
+ if(MCHMmcfgBDF >= 0) {
+ mch_mmconfig_setup(MCHMmcfgBDF);
+ }
+}
+
+static void pci_bios_init_device(struct pci_device *pci)
+{
+ dprintf(1, "PCI: init bdf=%pP id=%04x:%04x\n"
+ , pci, pci->vendor, pci->device);
+
+ /* map the interrupt */
+ u16 bdf = pci->bdf;
+ int pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
+ if (pin != 0)
+ pci_config_writeb(bdf, PCI_INTERRUPT_LINE, pci_slot_get_irq(pci, pin));
+
+ pci_init_device(pci_device_tbl, pci, NULL);
+
+ /* 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)
+{
+ struct pci_device *pci;
+ foreachpci(pci) {
+ pci_bios_init_device(pci);
+ }
+}
+
+static void pci_enable_default_vga(void)
+{
+ struct pci_device *pci;
+
+ foreachpci(pci) {
+ if (is_pci_vga(pci)) {
+ dprintf(1, "PCI: Using %pP for primary VGA\n", pci);
+ return;
+ }
+ }
+
+ pci = pci_find_class(PCI_CLASS_DISPLAY_VGA);
+ if (!pci) {
+ dprintf(1, "PCI: No VGA devices found\n");
+ return;
+ }
+
+ dprintf(1, "PCI: Enabling %pP for primary VGA\n", pci);
+
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+ while (pci->parent) {
+ pci = pci->parent;
+
+ dprintf(1, "PCI: Setting VGA enable on bridge %pP\n", pci);
+
+ pci_config_maskw(pci->bdf, PCI_BRIDGE_CONTROL, 0, PCI_BRIDGE_CTL_VGA);
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+ }
+}
+
+/****************************************************************
+ * Platform device initialization
+ ****************************************************************/
+
+static void i440fx_mem_addr_setup(struct pci_device *dev, void *arg)
+{
+ if (RamSize <= 0x80000000)
+ pcimem_start = 0x80000000;
+ else if (RamSize <= 0xc0000000)
+ pcimem_start = 0xc0000000;
+
+ pci_slot_get_irq = piix_pci_slot_get_irq;
+}
+
+static void mch_mmconfig_setup(u16 bdf)
+{
+ u64 addr = Q35_HOST_BRIDGE_PCIEXBAR_ADDR;
+ u32 upper = addr >> 32;
+ u32 lower = (addr & 0xffffffff) | Q35_HOST_BRIDGE_PCIEXBAREN;
+ 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);
+ pci_enable_mmconfig(Q35_HOST_BRIDGE_PCIEXBAR_ADDR, "q35");
+}
+
+static void mch_mem_addr_setup(struct pci_device *dev, void *arg)
+{
+ u64 addr = Q35_HOST_BRIDGE_PCIEXBAR_ADDR;
+ u32 size = Q35_HOST_BRIDGE_PCIEXBAR_SIZE;
+
+ /* setup mmconfig */
+ MCHMmcfgBDF = dev->bdf;
+ mch_mmconfig_setup(dev->bdf);
+ e820_add(addr, size, E820_RESERVED);
+
+ /* setup pci i/o window (above mmconfig) */
+ pcimem_start = addr + size;
+
+ pci_slot_get_irq = mch_pci_slot_get_irq;
+
+ /* setup io address space */
+ if (acpi_pm_base < 0x1000)
+ pci_io_low_end = 0x10000;
+ else
+ pci_io_low_end = acpi_pm_base;
+}
+
+#if CONFIG_PARISC
+static int dino_pci_slot_get_irq(struct pci_device *pci, int pin)
+{
+ int slot = pci_bdf_to_dev(pci->bdf);
+ return slot & 0x03;
+}
+
+static void dino_mem_addr_setup(struct pci_device *dev, void *arg)
+{
+ pcimem_start = 0xf2000000ULL;
+ pcimem_end = 0xff800000ULL;
+
+ /* Setup DINO PCI I/O and mem window */
+
+ outl(DINO_HPA | 1, 0xfffc0020); /* Set Dino Flex (Address) */
+ outl(0x00000080, DINO_HPA + 0x038); /* IO_CONTROL - enable DINO PCI */
+ // outl(0x00000000, DINO_HPA + 0x804); /* Set PAMR */
+ // outl(0x00000000, DINO_HPA + 0x808); /* Set PAPR */
+ outl(0x7ffffffe, DINO_HPA + 0x060); /* Set DINO_IO_ADDR_EN */
+ // outl(0x00000001, DINO_HPA + 0x05c); /* Set IO_FBB_EN */
+ // outl(0x0000006f, DINO_HPA + 0x810); /* Set PCICMD */
+
+ pci_slot_get_irq = dino_pci_slot_get_irq;
+
+ /* setup io address space */
+ pci_io_low_end = 0xa000;
+}
+#endif /* CONFIG_PARISC */
+
+
+static const struct pci_device_id pci_platform_tbl[] = {
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
+ i440fx_mem_addr_setup),
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH,
+ mch_mem_addr_setup),
+ PCI_DEVICE_END
+};
+
+static void pci_bios_init_platform(void)
+{
+ struct pci_device *pci;
+
+ if (CONFIG_X86) {
+ foreachpci(pci) {
+ pci_init_device(pci_platform_tbl, pci, NULL);
+ }
+ }
+
+#if CONFIG_PARISC
+ dino_mem_addr_setup(NULL, NULL);
+#endif
+}
+
+static u8 pci_find_resource_reserve_capability(u16 bdf)
+{
+ u16 device_id;
+
+ if (pci_config_readw(bdf, PCI_VENDOR_ID) != PCI_VENDOR_ID_REDHAT) {
+ dprintf(3, "PCI: This is non-QEMU bridge.\n");
+ return 0;
+ }
+
+ device_id = pci_config_readw(bdf, PCI_DEVICE_ID);
+
+ if (device_id != PCI_DEVICE_ID_REDHAT_ROOT_PORT &&
+ device_id != PCI_DEVICE_ID_REDHAT_BRIDGE) {
+ dprintf(1, "PCI: QEMU resource reserve cap device ID doesn't match.\n");
+ return 0;
+ }
+ u8 cap = 0;
+
+ do {
+ cap = pci_find_capability(bdf, PCI_CAP_ID_VNDR, cap);
+ } while (cap &&
+ pci_config_readb(bdf, cap + PCI_CAP_REDHAT_TYPE_OFFSET) !=
+ REDHAT_CAP_RESOURCE_RESERVE);
+ if (cap) {
+ u8 cap_len = pci_config_readb(bdf, cap + PCI_CAP_FLAGS);
+ if (cap_len < RES_RESERVE_CAP_SIZE) {
+ dprintf(1, "PCI: QEMU resource reserve cap length %d is invalid\n",
+ cap_len);
+ return 0;
+ }
+ } else {
+ dprintf(1, "PCI: QEMU resource reserve cap not found\n");
+ }
+ return cap;
+}
+
+/****************************************************************
+ * Bus initialization
+ ****************************************************************/
+
+static void
+pci_bios_init_bus_rec(int bus, u8 *pci_bus)
+{
+ int bdf;
+ u16 class;
+
+ dprintf(1, "PCI: %s bus = 0x%x\n", __func__, bus);
+
+ /* prevent accidental access to unintended devices */
+ foreachbdf(bdf, bus) {
+ class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
+ if (class == PCI_CLASS_BRIDGE_PCI) {
+ pci_config_writeb(bdf, PCI_SECONDARY_BUS, 255);
+ pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 0);
+ }
+ }
+
+ foreachbdf(bdf, bus) {
+ class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
+ if (class != PCI_CLASS_BRIDGE_PCI) {
+ continue;
+ }
+ dprintf(1, "PCI: %s bdf = 0x%x\n", __func__, bdf);
+
+ u8 pribus = pci_config_readb(bdf, PCI_PRIMARY_BUS);
+ if (pribus != bus) {
+ dprintf(1, "PCI: primary bus = 0x%x -> 0x%x\n", pribus, bus);
+ pci_config_writeb(bdf, PCI_PRIMARY_BUS, bus);
+ } else {
+ dprintf(1, "PCI: primary bus = 0x%x\n", pribus);
+ }
+
+ u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
+ (*pci_bus)++;
+ if (*pci_bus != secbus) {
+ dprintf(1, "PCI: secondary bus = 0x%x -> 0x%x\n",
+ secbus, *pci_bus);
+ secbus = *pci_bus;
+ pci_config_writeb(bdf, PCI_SECONDARY_BUS, secbus);
+ } else {
+ dprintf(1, "PCI: secondary bus = 0x%x\n", secbus);
+ }
+
+ /* set to max for access to all subordinate buses.
+ later set it to accurate value */
+ u8 subbus = pci_config_readb(bdf, PCI_SUBORDINATE_BUS);
+ pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 255);
+
+ pci_bios_init_bus_rec(secbus, pci_bus);
+
+ if (subbus != *pci_bus) {
+ u8 res_bus = *pci_bus;
+ u8 cap = pci_find_resource_reserve_capability(bdf);
+
+ if (cap) {
+ u32 tmp_res_bus = pci_config_readl(bdf,
+ cap + RES_RESERVE_BUS_RES);
+ if (tmp_res_bus != (u32)-1) {
+ res_bus = tmp_res_bus & 0xFF;
+ if ((u8)(res_bus + secbus) < secbus ||
+ (u8)(res_bus + secbus) < res_bus) {
+ dprintf(1, "PCI: bus_reserve value %d is invalid\n",
+ res_bus);
+ res_bus = 0;
+ }
+ if (secbus + res_bus > *pci_bus) {
+ dprintf(1, "PCI: QEMU resource reserve cap: bus = %u\n",
+ res_bus);
+ res_bus = secbus + res_bus;
+ }
+ }
+ }
+ dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n",
+ subbus, res_bus);
+ subbus = res_bus;
+ *pci_bus = res_bus;
+ } else {
+ dprintf(1, "PCI: subordinate bus = 0x%x\n", subbus);
+ }
+ pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, subbus);
+ }
+}
+
+static void
+pci_bios_init_bus(void)
+{
+ u8 extraroots = romfile_loadint("etc/extra-pci-roots", 0);
+ u8 pci_bus = 0;
+
+ pci_bios_init_bus_rec(0 /* host bus */, &pci_bus);
+
+ if (extraroots) {
+ while (pci_bus < 0xff) {
+ pci_bus++;
+ pci_bios_init_bus_rec(pci_bus, &pci_bus);
+ }
+ }
+}
+
+
+/****************************************************************
+ * Bus sizing
+ ****************************************************************/
+
+static void
+pci_bios_get_bar(struct pci_device *pci, int bar,
+ int *ptype, u64 *psize, int *pis64)
+{
+ u32 ofs = pci_bar(pci, bar);
+ u16 bdf = pci->bdf;
+ u32 old = pci_config_readl(bdf, ofs);
+ int is64 = 0, type = PCI_REGION_TYPE_MEM;
+ u64 mask;
+
+ if (bar == PCI_ROM_SLOT) {
+ mask = PCI_ROM_ADDRESS_MASK;
+ pci_config_writel(bdf, ofs, mask);
+ } else {
+ if (old & PCI_BASE_ADDRESS_SPACE_IO) {
+ mask = PCI_BASE_ADDRESS_IO_MASK;
+ type = PCI_REGION_TYPE_IO;
+ } else {
+ mask = PCI_BASE_ADDRESS_MEM_MASK;
+ if (old & PCI_BASE_ADDRESS_MEM_PREFETCH)
+ type = PCI_REGION_TYPE_PREFMEM;
+ is64 = ((old & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
+ == PCI_BASE_ADDRESS_MEM_TYPE_64);
+ }
+ pci_config_writel(bdf, ofs, ~0);
+ }
+ u64 val = pci_config_readl(bdf, ofs);
+ pci_config_writel(bdf, ofs, old);
+ if (is64) {
+ u32 hold = pci_config_readl(bdf, ofs + 4);
+ pci_config_writel(bdf, ofs + 4, ~0);
+ u32 high = pci_config_readl(bdf, ofs + 4);
+ pci_config_writel(bdf, ofs + 4, hold);
+ val |= ((u64)high << 32);
+ mask |= ((u64)0xffffffff << 32);
+ *psize = (~(val & mask)) + 1;
+ } else {
+ *psize = ((~(val & mask)) + 1) & 0xffffffff;
+ }
+ *ptype = type;
+ *pis64 = is64;
+}
+
+static int pci_bios_bridge_region_is64(struct pci_region *r,
+ struct pci_device *pci, int type)
+{
+ if (type != PCI_REGION_TYPE_PREFMEM)
+ return 0;
+ u32 pmem = pci_config_readl(pci->bdf, PCI_PREF_MEMORY_BASE);
+ if (!pmem) {
+ pci_config_writel(pci->bdf, PCI_PREF_MEMORY_BASE, 0xfff0fff0);
+ pmem = pci_config_readl(pci->bdf, PCI_PREF_MEMORY_BASE);
+ pci_config_writel(pci->bdf, PCI_PREF_MEMORY_BASE, 0x0);
+ }
+ if ((pmem & PCI_PREF_RANGE_TYPE_MASK) != PCI_PREF_RANGE_TYPE_64)
+ return 0;
+ struct pci_region_entry *entry;
+ hlist_for_each_entry(entry, &r->list, node) {
+ if (!entry->is64)
+ return 0;
+ }
+ return 1;
+}
+
+static u64 pci_region_align(struct pci_region *r)
+{
+ struct pci_region_entry *entry;
+ hlist_for_each_entry(entry, &r->list, node) {
+ // The first entry in the sorted list has the largest alignment
+ return entry->align;
+ }
+ return 1;
+}
+
+static u64 pci_region_sum(struct pci_region *r)
+{
+ u64 sum = 0;
+ struct pci_region_entry *entry;
+ hlist_for_each_entry(entry, &r->list, node) {
+ sum += entry->size;
+ }
+ return sum;
+}
+
+static void pci_region_migrate_64bit_entries(struct pci_region *from,
+ struct pci_region *to)
+{
+ struct hlist_node *n, **last = &to->list.first;
+ struct pci_region_entry *entry;
+ hlist_for_each_entry_safe(entry, n, &from->list, node) {
+ if (!entry->is64)
+ continue;
+ if (entry->dev->class == PCI_CLASS_SERIAL_USB)
+ continue;
+ // Move from source list to destination list.
+ hlist_del(&entry->node);
+ hlist_add(&entry->node, last);
+ last = &entry->node.next;
+ }
+}
+
+static struct pci_region_entry *
+pci_region_create_entry(struct pci_bus *bus, struct pci_device *dev,
+ int bar, u64 size, u64 align, int type, int is64)
+{
+ struct pci_region_entry *entry = malloc_tmp(sizeof(*entry));
+ if (!entry) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(entry, 0, sizeof(*entry));
+ entry->dev = dev;
+ entry->bar = bar;
+ entry->size = size;
+ entry->align = align;
+ entry->is64 = is64;
+ entry->type = type;
+ // Insert into list in sorted order.
+ struct hlist_node **pprev;
+ struct pci_region_entry *pos;
+ hlist_for_each_entry_pprev(pos, pprev, &bus->r[type].list, node) {
+ if (pos->align < align || (pos->align == align && pos->size < size))
+ break;
+ }
+ hlist_add(&entry->node, pprev);
+ return entry;
+}
+
+static int pci_bus_hotplug_support(struct pci_bus *bus, u8 pcie_cap)
+{
+ u8 shpc_cap;
+
+ if (pcie_cap) {
+ u16 pcie_flags = pci_config_readw(bus->bus_dev->bdf,
+ pcie_cap + PCI_EXP_FLAGS);
+ u8 port_type = ((pcie_flags & PCI_EXP_FLAGS_TYPE) >>
+ (__builtin_ffs(PCI_EXP_FLAGS_TYPE) - 1));
+ u8 downstream_port = (port_type == PCI_EXP_TYPE_DOWNSTREAM) ||
+ (port_type == PCI_EXP_TYPE_ROOT_PORT);
+ /*
+ * PCI Express SPEC, 7.8.2:
+ * Slot Implemented – When Set, this bit indicates that the Link
+ * HwInit associated with this Port is connected to a slot (as
+ * compared to being connected to a system-integrated device or
+ * being disabled).
+ * This bit is valid for Downstream Ports. This bit is undefined
+ * for Upstream Ports.
+ */
+ u16 slot_implemented = pcie_flags & PCI_EXP_FLAGS_SLOT;
+
+ return downstream_port && slot_implemented;
+ }
+
+ shpc_cap = pci_find_capability(bus->bus_dev->bdf, PCI_CAP_ID_SHPC, 0);
+ return !!shpc_cap;
+}
+
+/* Test whether bridge support forwarding of transactions
+ * of a specific type.
+ * Note: disables bridge's window registers as a side effect.
+ */
+static int pci_bridge_has_region(struct pci_device *pci,
+ enum pci_region_type region_type)
+{
+ u8 base;
+
+ switch (region_type) {
+ case PCI_REGION_TYPE_IO:
+ base = PCI_IO_BASE;
+ break;
+ case PCI_REGION_TYPE_PREFMEM:
+ base = PCI_PREF_MEMORY_BASE;
+ break;
+ default:
+ /* Regular memory support is mandatory */
+ return 1;
+ }
+
+ pci_config_writeb(pci->bdf, base, 0xFF);
+
+ return pci_config_readb(pci->bdf, base) != 0;
+}
+
+static int pci_bios_check_devices(struct pci_bus *busses)
+{
+ dprintf(1, "PCI: check devices\n");
+
+ // Calculate resources needed for regular (non-bus) devices.
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->class == PCI_CLASS_BRIDGE_PCI)
+ busses[pci->secondary_bus].bus_dev = pci;
+
+ struct pci_bus *bus = &busses[pci_bdf_to_bus(pci->bdf)];
+ if (!bus->bus_dev)
+ /*
+ * Resources for all root busses go in busses[0]
+ */
+ bus = &busses[0];
+ int i;
+ for (i = 0; i < PCI_NUM_REGIONS; i++) {
+ if ((pci->class == PCI_CLASS_BRIDGE_PCI) &&
+ (i >= PCI_BRIDGE_NUM_REGIONS && i < PCI_ROM_SLOT))
+ continue;
+ int type, is64;
+ u64 size;
+ pci_bios_get_bar(pci, i, &type, &size, &is64);
+ if (size == 0)
+ continue;
+
+ if (type != PCI_REGION_TYPE_IO && size < PCI_DEVICE_MEM_MIN)
+ size = PCI_DEVICE_MEM_MIN;
+ struct pci_region_entry *entry = pci_region_create_entry(
+ bus, pci, i, size, size, type, is64);
+ if (!entry)
+ return -1;
+
+ if (is64)
+ i++;
+ }
+ }
+
+ // Propagate required bus resources to parent busses.
+ int secondary_bus;
+ for (secondary_bus=MaxPCIBus; secondary_bus>0; secondary_bus--) {
+ struct pci_bus *s = &busses[secondary_bus];
+ if (!s->bus_dev)
+ continue;
+ struct pci_bus *parent = &busses[pci_bdf_to_bus(s->bus_dev->bdf)];
+ if (!parent->bus_dev)
+ /*
+ * Resources for all root busses go in busses[0]
+ */
+ parent = &busses[0];
+ int type;
+ u16 bdf = s->bus_dev->bdf;
+ u8 pcie_cap = pci_find_capability(bdf, PCI_CAP_ID_EXP, 0);
+ u8 qemu_cap = pci_find_resource_reserve_capability(bdf);
+
+ 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;
+ if (!pci_bridge_has_region(s->bus_dev, type))
+ continue;
+ u64 size = 0;
+ if (qemu_cap) {
+ u32 tmp_size;
+ u64 tmp_size_64;
+ switch(type) {
+ case PCI_REGION_TYPE_IO:
+ tmp_size_64 = (pci_config_readl(bdf, qemu_cap + RES_RESERVE_IO) |
+ (u64)pci_config_readl(bdf, qemu_cap + RES_RESERVE_IO + 4) << 32);
+ if (tmp_size_64 != (u64)-1) {
+ size = tmp_size_64;
+ }
+ break;
+ case PCI_REGION_TYPE_MEM:
+ tmp_size = pci_config_readl(bdf, qemu_cap + RES_RESERVE_MEM);
+ if (tmp_size != (u32)-1) {
+ size = tmp_size;
+ }
+ break;
+ case PCI_REGION_TYPE_PREFMEM:
+ tmp_size = pci_config_readl(bdf, qemu_cap + RES_RESERVE_PREF_MEM_32);
+ tmp_size_64 = (pci_config_readl(bdf, qemu_cap + RES_RESERVE_PREF_MEM_64) |
+ (u64)pci_config_readl(bdf, qemu_cap + RES_RESERVE_PREF_MEM_64 + 4) << 32);
+ if (tmp_size != (u32)-1 && tmp_size_64 == (u64)-1) {
+ size = tmp_size;
+ } else if (tmp_size == (u32)-1 && tmp_size_64 != (u64)-1) {
+ size = tmp_size_64;
+ } else if (tmp_size != (u32)-1 && tmp_size_64 != (u64)-1) {
+ dprintf(1, "PCI: resource reserve cap PREF32 and PREF64"
+ " conflict\n");
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (pci_region_align(&s->r[type]) > align)
+ align = pci_region_align(&s->r[type]);
+ u64 sum = pci_region_sum(&s->r[type]);
+ int resource_optional = pcie_cap && (type == PCI_REGION_TYPE_IO);
+ if (!sum && hotplug_support && !resource_optional)
+ sum = align; /* reserve min size for hot-plug */
+ if (size > sum) {
+ dprintf(1, "PCI: QEMU resource reserve cap: "
+ "size %08llx type %s\n",
+ size, region_type_name[type]);
+ if (type != PCI_REGION_TYPE_IO) {
+ size = ALIGN(size, align);
+ }
+ } else {
+ size = ALIGN(sum, align);
+ }
+ int is64 = pci_bios_bridge_region_is64(&s->r[type],
+ s->bus_dev, type);
+ // entry->bar is -1 if the entry represents a bridge region
+ struct pci_region_entry *entry = pci_region_create_entry(
+ parent, s->bus_dev, -1, size, align, type, is64);
+ if (!entry)
+ return -1;
+ dprintf(1, "PCI: secondary bus %d size %08llx type %s\n",
+ entry->dev->secondary_bus, size,
+ region_type_name[entry->type]);
+ }
+ }
+ return 0;
+}
+
+
+/****************************************************************
+ * BAR assignment
+ ****************************************************************/
+
+// Setup region bases (given the regions' size and alignment)
+static int pci_bios_init_root_regions_io(struct pci_bus *bus)
+{
+ /*
+ * QEMU I/O address space usage:
+ * 0000 - 0fff legacy isa, pci config, pci root bus, ...
+ * 1000 - 9fff free
+ * a000 - afff hotplug (cpu, pci via acpi, i440fx/piix only)
+ * b000 - bfff power management (PORT_ACPI_PM_BASE)
+ * [ qemu 1.4+ implements pci config registers
+ * properly so guests can place the registers
+ * where they want, on older versions its fixed ]
+ * c000 - ffff free, traditionally used for pci io
+ */
+ struct pci_region *r_io = &bus->r[PCI_REGION_TYPE_IO];
+ u64 sum = pci_region_sum(r_io);
+ if (sum < 0x4000 && !CONFIG_PARISC) {
+ /* traditional region is big enough, use it */
+ r_io->base = 0xc000;
+ } else if (sum < pci_io_low_end - 0x1000) {
+ /* use the larger region at 0x1000 */
+ r_io->base = 0x1000;
+ } else {
+ /* not enouth io address space -> error out */
+ return -1;
+ }
+ dprintf(1, "PCI: IO: %4llx - %4llx\n", r_io->base, r_io->base + sum - 1);
+ return 0;
+}
+
+static int pci_bios_init_root_regions_mem(struct pci_bus *bus)
+{
+ struct pci_region *r_end = &bus->r[PCI_REGION_TYPE_PREFMEM];
+ struct pci_region *r_start = &bus->r[PCI_REGION_TYPE_MEM];
+
+ if (pci_region_align(r_start) < pci_region_align(r_end)) {
+ // Swap regions to improve alignment.
+ r_end = r_start;
+ r_start = &bus->r[PCI_REGION_TYPE_PREFMEM];
+ }
+ u64 sum = pci_region_sum(r_end);
+ u64 align = pci_region_align(r_end);
+ r_end->base = ALIGN_DOWN((pcimem_end - sum), align);
+ sum = pci_region_sum(r_start);
+ align = pci_region_align(r_start);
+ r_start->base = ALIGN_DOWN((r_end->base - sum), align);
+
+ if ((r_start->base < pcimem_start) ||
+ (r_start->base > pcimem_end))
+ // Memory range requested is larger than available.
+ return -1;
+ return 0;
+}
+
+#define PCI_IO_SHIFT 8
+#define PCI_MEMORY_SHIFT 16
+#define PCI_PREF_MEMORY_SHIFT 16
+
+static void
+pci_region_map_one_entry(struct pci_region_entry *entry, u64 addr)
+{
+ if (entry->bar >= 0) {
+ dprintf(1, "PCI: map device bdf=%pP"
+ " bar %d, addr %08llx, size %08llx [%d: %s]\n",
+ entry->dev,
+ entry->bar, addr, entry->size, entry->type, region_type_name[entry->type]);
+
+ pci_set_io_region_addr(entry->dev, entry->bar, addr, entry->is64);
+ return;
+ }
+
+ u16 bdf = entry->dev->bdf;
+ u64 limit = addr + entry->size - 1;
+ if (entry->type == PCI_REGION_TYPE_IO) {
+ pci_config_writeb(bdf, PCI_IO_BASE, addr >> PCI_IO_SHIFT);
+ pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0);
+ pci_config_writeb(bdf, PCI_IO_LIMIT, limit >> PCI_IO_SHIFT);
+ pci_config_writew(bdf, PCI_IO_LIMIT_UPPER16, 0);
+ }
+ if (entry->type == PCI_REGION_TYPE_MEM) {
+ pci_config_writew(bdf, PCI_MEMORY_BASE, addr >> PCI_MEMORY_SHIFT);
+ pci_config_writew(bdf, PCI_MEMORY_LIMIT, limit >> PCI_MEMORY_SHIFT);
+ }
+ if (entry->type == PCI_REGION_TYPE_PREFMEM) {
+ pci_config_writew(bdf, PCI_PREF_MEMORY_BASE, addr >> PCI_PREF_MEMORY_SHIFT);
+ pci_config_writew(bdf, PCI_PREF_MEMORY_LIMIT, limit >> PCI_PREF_MEMORY_SHIFT);
+ pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, addr >> 32);
+ pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, limit >> 32);
+ }
+}
+
+static void pci_region_map_entries(struct pci_bus *busses, struct pci_region *r)
+{
+ struct hlist_node *n;
+ struct pci_region_entry *entry;
+ hlist_for_each_entry_safe(entry, n, &r->list, node) {
+ u64 addr = r->base;
+ r->base += entry->size;
+ if (entry->bar == -1)
+ // Update bus base address if entry is a bridge region
+ busses[entry->dev->secondary_bus].r[entry->type].base = addr;
+ pci_region_map_one_entry(entry, addr);
+ hlist_del(&entry->node);
+ free(entry);
+ }
+}
+
+static void pci_bios_map_devices(struct pci_bus *busses)
+{
+ if (pci_bios_init_root_regions_io(busses))
+ panic("PCI: out of I/O address space\n");
+
+ dprintf(1, "PCI: 32: %016llx - %016llx\n", pcimem_start, pcimem_end);
+ if (pci_bios_init_root_regions_mem(busses)) {
+ struct pci_region r64_mem, r64_pref;
+ r64_mem.list.first = NULL;
+ r64_pref.list.first = NULL;
+ pci_region_migrate_64bit_entries(&busses[0].r[PCI_REGION_TYPE_MEM],
+ &r64_mem);
+ pci_region_migrate_64bit_entries(&busses[0].r[PCI_REGION_TYPE_PREFMEM],
+ &r64_pref);
+
+ if (pci_bios_init_root_regions_mem(busses))
+ panic("PCI: out of 32bit address space\n");
+
+ u64 sum_mem = pci_region_sum(&r64_mem);
+ u64 sum_pref = pci_region_sum(&r64_pref);
+ u64 align_mem = pci_region_align(&r64_mem);
+ u64 align_pref = pci_region_align(&r64_pref);
+
+ r64_mem.base = le64_to_cpu(romfile_loadint("etc/reserved-memory-end", 0));
+ if (r64_mem.base < 0x100000000LL + RamSizeOver4G)
+ r64_mem.base = 0x100000000LL + RamSizeOver4G;
+ r64_mem.base = ALIGN(r64_mem.base, align_mem);
+ r64_mem.base = ALIGN(r64_mem.base, (1LL<<30)); // 1G hugepage
+ r64_pref.base = r64_mem.base + sum_mem;
+ r64_pref.base = ALIGN(r64_pref.base, align_pref);
+ r64_pref.base = ALIGN(r64_pref.base, (1LL<<30)); // 1G hugepage
+ pcimem64_start = r64_mem.base;
+ pcimem64_end = r64_pref.base + sum_pref;
+ pcimem64_end = ALIGN(pcimem64_end, (1LL<<30)); // 1G hugepage
+ dprintf(1, "PCI: 64: %016llx - %016llx\n", pcimem64_start, pcimem64_end);
+
+ pci_region_map_entries(busses, &r64_mem);
+ pci_region_map_entries(busses, &r64_pref);
+ } else {
+ // no bars mapped high -> drop 64bit window (see dsdt)
+ pcimem64_start = 0;
+ }
+ // Map regions on each device.
+ int bus;
+ for (bus = 0; bus<=MaxPCIBus; bus++) {
+ int type;
+ for (type = 0; type < PCI_REGION_TYPE_COUNT; type++)
+ pci_region_map_entries(busses, &busses[bus].r[type]);
+ }
+}
+
+
+/****************************************************************
+ * Main setup code
+ ****************************************************************/
+
+void
+pci_setup(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ dprintf(3, "pci setup\n");
+
+ dprintf(1, "=== PCI bus & bridge init ===\n");
+ if (pci_probe_host() != 0) {
+ return;
+ }
+ pci_bios_init_bus();
+
+ dprintf(1, "=== PCI device probing ===\n");
+ pci_probe_devices();
+
+ pcimem_start = RamSize;
+ pci_bios_init_platform();
+
+ dprintf(1, "=== PCI new allocation pass #1 ===\n");
+ struct pci_bus *busses = malloc_tmp(sizeof(*busses) * (MaxPCIBus + 1));
+ if (!busses) {
+ warn_noalloc();
+ return;
+ }
+ memset(busses, 0, sizeof(*busses) * (MaxPCIBus + 1));
+ if (pci_bios_check_devices(busses))
+ return;
+
+ dprintf(1, "=== PCI new allocation pass #2 ===\n");
+ pci_bios_map_devices(busses);
+
+ pci_bios_init_devices();
+
+ free(busses);
+
+ pci_enable_default_vga();
+}
diff --git a/roms/seabios-hppa/src/fw/pirtable.c b/roms/seabios-hppa/src/fw/pirtable.c
new file mode 100644
index 000000000..bf8c04704
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/pirtable.c
@@ -0,0 +1,103 @@
+// PIR table generation (for emulators)
+// DO NOT ADD NEW FEATURES HERE. (See paravirt.c / biostables.c instead.)
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "output.h" // dprintf
+#include "std/pirtable.h" // struct pir_header
+#include "string.h" // checksum
+#include "util.h" // PirAddr
+
+struct pir_table {
+ struct pir_header pir;
+ struct pir_slot slots[6];
+} PACKED;
+
+static struct pir_table PIR_TABLE = {
+ .pir = {
+ .version = 0x0100,
+ .size = sizeof(struct pir_table),
+ .router_devfunc = 0x08,
+ .compatible_devid = 0x122e8086,
+ },
+ .slots = {
+ {
+ // first slot entry PCI-to-ISA (embedded)
+ .dev = 1<<3,
+ .links = {
+ {.link = 0x60, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x61, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 0, // embedded
+ }, {
+ // second slot entry: 1st PCI slot
+ .dev = 2<<3,
+ .links = {
+ {.link = 0x61, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x60, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 1,
+ }, {
+ // third slot entry: 2nd PCI slot
+ .dev = 3<<3,
+ .links = {
+ {.link = 0x62, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x60, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x61, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 2,
+ }, {
+ // 4th slot entry: 3rd PCI slot
+ .dev = 4<<3,
+ .links = {
+ {.link = 0x63, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x60, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x61, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 3,
+ }, {
+ // 5th slot entry: 4th PCI slot
+ .dev = 5<<3,
+ .links = {
+ {.link = 0x60, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x61, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 4,
+ }, {
+ // 6th slot entry: 5th PCI slot
+ .dev = 6<<3,
+ .links = {
+ {.link = 0x61, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x60, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 5,
+ },
+ }
+};
+
+void
+pirtable_setup(void)
+{
+ if (! CONFIG_PIRTABLE)
+ return;
+
+ dprintf(3, "init PIR table\n");
+
+ PIR_TABLE.pir.signature = PIR_SIGNATURE;
+ PIR_TABLE.pir.checksum -= checksum(&PIR_TABLE, sizeof(PIR_TABLE));
+ copy_pir(&PIR_TABLE);
+}
diff --git a/roms/seabios-hppa/src/fw/q35-acpi-dsdt.dsl b/roms/seabios-hppa/src/fw/q35-acpi-dsdt.dsl
new file mode 100644
index 000000000..5dec54146
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/q35-acpi-dsdt.dsl
@@ -0,0 +1,450 @@
+/*
+ * Bochs/QEMU ACPI DSDT ASL definition
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/*
+ * Copyright (c) 2010 Isaku Yamahata
+ * yamahata at valinux co jp
+ * Based on acpi-dsdt.dsl, but heavily modified for q35 chipset.
+ */
+
+DefinitionBlock (
+ "q35-acpi-dsdt.aml",// Output Filename
+ "DSDT", // Signature
+ 0x01, // DSDT Compliance Revision
+ "BXPC", // OEMID
+ "BXDSDT", // TABLE ID
+ 0x2 // OEM Revision
+ )
+{
+
+#include "acpi-dsdt-dbug.dsl"
+
+ Scope(\_SB) {
+ OperationRegion(PCST, SystemIO, 0xae00, 0x0c)
+ OperationRegion(PCSB, SystemIO, 0xae0c, 0x01)
+ Field(PCSB, AnyAcc, NoLock, WriteAsZeros) {
+ PCIB, 8,
+ }
+ }
+
+
+/****************************************************************
+ * PCI Bus definition
+ ****************************************************************/
+
+ Scope(\_SB) {
+ Device(PCI0) {
+ Name(_HID, EisaId("PNP0A08"))
+ Name(_CID, EisaId("PNP0A03"))
+ Name(_ADR, 0x00)
+ Name(_UID, 1)
+
+ // _OSC: based on sample of ACPI3.0b spec
+ Name(SUPP, 0) // PCI _OSC Support Field value
+ Name(CTRL, 0) // PCI _OSC Control Field value
+ Method(_OSC, 4) {
+ // Create DWORD-addressable fields from the Capabilities Buffer
+ CreateDWordField(Arg3, 0, CDW1)
+
+ // Check for proper UUID
+ If (LEqual(Arg0, ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766"))) {
+ // Create DWORD-addressable fields from the Capabilities Buffer
+ CreateDWordField(Arg3, 4, CDW2)
+ CreateDWordField(Arg3, 8, CDW3)
+
+ // Save Capabilities DWORD2 & 3
+ Store(CDW2, SUPP)
+ Store(CDW3, CTRL)
+
+ // Always allow native PME, AER (no dependencies)
+ // Never allow SHPC (no SHPC controller in this system)
+ And(CTRL, 0x1D, CTRL)
+
+#if 0 // For now, nothing to do
+ If (Not(And(CDW1, 1))) { // Query flag clear?
+ // Disable GPEs for features granted native control.
+ If (And(CTRL, 0x01)) { // Hot plug control granted?
+ Store(0, HPCE) // clear the hot plug SCI enable bit
+ Store(1, HPCS) // clear the hot plug SCI status bit
+ }
+ If (And(CTRL, 0x04)) { // PME control granted?
+ Store(0, PMCE) // clear the PME SCI enable bit
+ Store(1, PMCS) // clear the PME SCI status bit
+ }
+ If (And(CTRL, 0x10)) { // OS restoring PCI Express cap structure?
+ // Set status to not restore PCI Express cap structure
+ // upon resume from S3
+ Store(1, S3CR)
+ }
+ }
+#endif
+ If (LNotEqual(Arg1, One)) {
+ // Unknown revision
+ Or(CDW1, 0x08, CDW1)
+ }
+ If (LNotEqual(CDW3, CTRL)) {
+ // Capabilities bits were masked
+ Or(CDW1, 0x10, CDW1)
+ }
+ // Update DWORD3 in the buffer
+ Store(CTRL, CDW3)
+ } Else {
+ Or(CDW1, 4, CDW1) // Unrecognized UUID
+ }
+ Return (Arg3)
+ }
+ }
+ }
+
+#include "acpi-dsdt-pci-crs.dsl"
+#include "acpi-dsdt-hpet.dsl"
+
+
+/****************************************************************
+ * VGA
+ ****************************************************************/
+
+ Scope(\_SB.PCI0) {
+ Device(VGA) {
+ Name(_ADR, 0x00010000)
+ Method(_S1D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S2D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S3D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ }
+ }
+
+
+/****************************************************************
+ * LPC ISA bridge
+ ****************************************************************/
+
+ Scope(\_SB.PCI0) {
+ /* PCI D31:f0 LPC ISA bridge */
+ Device(ISA) {
+ /* PCI D31:f0 */
+ Name(_ADR, 0x001f0000)
+
+ /* ICH9 PCI to ISA irq remapping */
+ OperationRegion(PIRQ, PCI_Config, 0x60, 0x0C)
+
+ OperationRegion(LPCD, PCI_Config, 0x80, 0x2)
+ Field(LPCD, AnyAcc, NoLock, Preserve) {
+ COMA, 3,
+ , 1,
+ COMB, 3,
+
+ Offset(0x01),
+ LPTD, 2,
+ , 2,
+ FDCD, 2
+ }
+ OperationRegion(LPCE, PCI_Config, 0x82, 0x2)
+ Field(LPCE, AnyAcc, NoLock, Preserve) {
+ CAEN, 1,
+ CBEN, 1,
+ LPEN, 1,
+ FDEN, 1
+ }
+ }
+ }
+
+#include "acpi-dsdt-isa.dsl"
+
+
+/****************************************************************
+ * PCI IRQs
+ ****************************************************************/
+
+ /* Zero => PIC mode, One => APIC Mode */
+ Name(\PICF, Zero)
+ Method(\_PIC, 1, NotSerialized) {
+ Store(Arg0, \PICF)
+ }
+
+ Scope(\_SB) {
+ Scope(PCI0) {
+#define prt_slot_lnk(nr, lnk0, lnk1, lnk2, lnk3) \
+ Package() { nr##ffff, 0, lnk0, 0 }, \
+ Package() { nr##ffff, 1, lnk1, 0 }, \
+ Package() { nr##ffff, 2, lnk2, 0 }, \
+ Package() { nr##ffff, 3, lnk3, 0 }
+
+#define prt_slot_lnkA(nr) prt_slot_lnk(nr, LNKA, LNKB, LNKC, LNKD)
+#define prt_slot_lnkB(nr) prt_slot_lnk(nr, LNKB, LNKC, LNKD, LNKA)
+#define prt_slot_lnkC(nr) prt_slot_lnk(nr, LNKC, LNKD, LNKA, LNKB)
+#define prt_slot_lnkD(nr) prt_slot_lnk(nr, LNKD, LNKA, LNKB, LNKC)
+
+#define prt_slot_lnkE(nr) prt_slot_lnk(nr, LNKE, LNKF, LNKG, LNKH)
+#define prt_slot_lnkF(nr) prt_slot_lnk(nr, LNKF, LNKG, LNKH, LNKE)
+#define prt_slot_lnkG(nr) prt_slot_lnk(nr, LNKG, LNKH, LNKE, LNKF)
+#define prt_slot_lnkH(nr) prt_slot_lnk(nr, LNKH, LNKE, LNKF, LNKG)
+
+ Name(PRTP, package() {
+ prt_slot_lnkE(0x0000),
+ prt_slot_lnkF(0x0001),
+ prt_slot_lnkG(0x0002),
+ prt_slot_lnkH(0x0003),
+ prt_slot_lnkE(0x0004),
+ prt_slot_lnkF(0x0005),
+ prt_slot_lnkG(0x0006),
+ prt_slot_lnkH(0x0007),
+ prt_slot_lnkE(0x0008),
+ prt_slot_lnkF(0x0009),
+ prt_slot_lnkG(0x000a),
+ prt_slot_lnkH(0x000b),
+ prt_slot_lnkE(0x000c),
+ prt_slot_lnkF(0x000d),
+ prt_slot_lnkG(0x000e),
+ prt_slot_lnkH(0x000f),
+ prt_slot_lnkE(0x0010),
+ prt_slot_lnkF(0x0011),
+ prt_slot_lnkG(0x0012),
+ prt_slot_lnkH(0x0013),
+ prt_slot_lnkE(0x0014),
+ prt_slot_lnkF(0x0015),
+ prt_slot_lnkG(0x0016),
+ prt_slot_lnkH(0x0017),
+ prt_slot_lnkE(0x0018),
+
+ /* INTA -> PIRQA for slot 25 - 31
+ see the default value of D<N>IR */
+ prt_slot_lnkA(0x0019),
+ prt_slot_lnkA(0x001a),
+ prt_slot_lnkA(0x001b),
+ prt_slot_lnkA(0x001c),
+ prt_slot_lnkA(0x001d),
+
+ /* PCIe->PCI bridge. use PIRQ[E-H] */
+ prt_slot_lnkE(0x001e),
+
+ prt_slot_lnkA(0x001f)
+ })
+
+#define prt_slot_gsi(nr, gsi0, gsi1, gsi2, gsi3) \
+ Package() { nr##ffff, 0, gsi0, 0 }, \
+ Package() { nr##ffff, 1, gsi1, 0 }, \
+ Package() { nr##ffff, 2, gsi2, 0 }, \
+ Package() { nr##ffff, 3, gsi3, 0 }
+
+#define prt_slot_gsiA(nr) prt_slot_gsi(nr, GSIA, GSIB, GSIC, GSID)
+#define prt_slot_gsiB(nr) prt_slot_gsi(nr, GSIB, GSIC, GSID, GSIA)
+#define prt_slot_gsiC(nr) prt_slot_gsi(nr, GSIC, GSID, GSIA, GSIB)
+#define prt_slot_gsiD(nr) prt_slot_gsi(nr, GSID, GSIA, GSIB, GSIC)
+
+#define prt_slot_gsiE(nr) prt_slot_gsi(nr, GSIE, GSIF, GSIG, GSIH)
+#define prt_slot_gsiF(nr) prt_slot_gsi(nr, GSIF, GSIG, GSIH, GSIE)
+#define prt_slot_gsiG(nr) prt_slot_gsi(nr, GSIG, GSIH, GSIE, GSIF)
+#define prt_slot_gsiH(nr) prt_slot_gsi(nr, GSIH, GSIE, GSIF, GSIG)
+
+ Name(PRTA, package() {
+ prt_slot_gsiE(0x0000),
+ prt_slot_gsiF(0x0001),
+ prt_slot_gsiG(0x0002),
+ prt_slot_gsiH(0x0003),
+ prt_slot_gsiE(0x0004),
+ prt_slot_gsiF(0x0005),
+ prt_slot_gsiG(0x0006),
+ prt_slot_gsiH(0x0007),
+ prt_slot_gsiE(0x0008),
+ prt_slot_gsiF(0x0009),
+ prt_slot_gsiG(0x000a),
+ prt_slot_gsiH(0x000b),
+ prt_slot_gsiE(0x000c),
+ prt_slot_gsiF(0x000d),
+ prt_slot_gsiG(0x000e),
+ prt_slot_gsiH(0x000f),
+ prt_slot_gsiE(0x0010),
+ prt_slot_gsiF(0x0011),
+ prt_slot_gsiG(0x0012),
+ prt_slot_gsiH(0x0013),
+ prt_slot_gsiE(0x0014),
+ prt_slot_gsiF(0x0015),
+ prt_slot_gsiG(0x0016),
+ prt_slot_gsiH(0x0017),
+ prt_slot_gsiE(0x0018),
+
+ /* INTA -> PIRQA for slot 25 - 31, but 30
+ see the default value of D<N>IR */
+ prt_slot_gsiA(0x0019),
+ prt_slot_gsiA(0x001a),
+ prt_slot_gsiA(0x001b),
+ prt_slot_gsiA(0x001c),
+ prt_slot_gsiA(0x001d),
+
+ /* PCIe->PCI bridge. use PIRQ[E-H] */
+ prt_slot_gsiE(0x001e),
+
+ prt_slot_gsiA(0x001f)
+ })
+
+ Method(_PRT, 0, NotSerialized) {
+ /* PCI IRQ routing table, example from ACPI 2.0a specification,
+ section 6.2.8.1 */
+ /* Note: we provide the same info as the PCI routing
+ table of the Bochs BIOS */
+ If (LEqual(\PICF, Zero)) {
+ Return (PRTP)
+ } Else {
+ Return (PRTA)
+ }
+ }
+ }
+
+ Field(PCI0.ISA.PIRQ, ByteAcc, NoLock, Preserve) {
+ PRQA, 8,
+ PRQB, 8,
+ PRQC, 8,
+ PRQD, 8,
+
+ Offset(0x08),
+ PRQE, 8,
+ PRQF, 8,
+ PRQG, 8,
+ PRQH, 8
+ }
+
+ Method(IQST, 1, NotSerialized) {
+ // _STA method - get status
+ If (And(0x80, Arg0)) {
+ Return (0x09)
+ }
+ Return (0x0B)
+ }
+ Method(IQCR, 1, Serialized) {
+ // _CRS method - get current settings
+ Name(PRR0, ResourceTemplate() {
+ Interrupt(, Level, ActiveHigh, Shared) { 0 }
+ })
+ CreateDWordField(PRR0, 0x05, PRRI)
+ Store(And(Arg0, 0x0F), PRRI)
+ Return (PRR0)
+ }
+
+#define define_link(link, uid, reg) \
+ Device(link) { \
+ Name(_HID, EISAID("PNP0C0F")) \
+ Name(_UID, uid) \
+ Name(_PRS, ResourceTemplate() { \
+ Interrupt(, Level, ActiveHigh, Shared) { \
+ 5, 10, 11 \
+ } \
+ }) \
+ Method(_STA, 0, NotSerialized) { \
+ Return (IQST(reg)) \
+ } \
+ Method(_DIS, 0, NotSerialized) { \
+ Or(reg, 0x80, reg) \
+ } \
+ Method(_CRS, 0, NotSerialized) { \
+ Return (IQCR(reg)) \
+ } \
+ Method(_SRS, 1, NotSerialized) { \
+ CreateDWordField(Arg0, 0x05, PRRI) \
+ Store(PRRI, reg) \
+ } \
+ }
+
+ define_link(LNKA, 0, PRQA)
+ define_link(LNKB, 1, PRQB)
+ define_link(LNKC, 2, PRQC)
+ define_link(LNKD, 3, PRQD)
+ define_link(LNKE, 4, PRQE)
+ define_link(LNKF, 5, PRQF)
+ define_link(LNKG, 6, PRQG)
+ define_link(LNKH, 7, PRQH)
+
+#define define_gsi_link(link, uid, gsi) \
+ Device(link) { \
+ Name(_HID, EISAID("PNP0C0F")) \
+ Name(_UID, uid) \
+ Name(_PRS, ResourceTemplate() { \
+ Interrupt(, Level, ActiveHigh, Shared) { \
+ gsi \
+ } \
+ }) \
+ Name(_CRS, ResourceTemplate() { \
+ Interrupt(, Level, ActiveHigh, Shared) { \
+ gsi \
+ } \
+ }) \
+ Method(_SRS, 1, NotSerialized) { \
+ } \
+ }
+
+ define_gsi_link(GSIA, 0, 0x10)
+ define_gsi_link(GSIB, 0, 0x11)
+ define_gsi_link(GSIC, 0, 0x12)
+ define_gsi_link(GSID, 0, 0x13)
+ define_gsi_link(GSIE, 0, 0x14)
+ define_gsi_link(GSIF, 0, 0x15)
+ define_gsi_link(GSIG, 0, 0x16)
+ define_gsi_link(GSIH, 0, 0x17)
+ }
+
+#include "acpi-dsdt-cpu-hotplug.dsl"
+
+
+/****************************************************************
+ * General purpose events
+ ****************************************************************/
+
+ Scope(\_GPE) {
+ Name(_HID, "ACPI0006")
+
+ Method(_L00) {
+ }
+ Method(_L01) {
+ // CPU hotplug event
+ \_SB.PRSC()
+ }
+ Method(_L02) {
+ }
+ Method(_L03) {
+ }
+ Method(_L04) {
+ }
+ Method(_L05) {
+ }
+ Method(_L06) {
+ }
+ Method(_L07) {
+ }
+ Method(_L08) {
+ }
+ Method(_L09) {
+ }
+ Method(_L0A) {
+ }
+ Method(_L0B) {
+ }
+ Method(_L0C) {
+ }
+ Method(_L0D) {
+ }
+ Method(_L0E) {
+ }
+ Method(_L0F) {
+ }
+ }
+}
diff --git a/roms/seabios-hppa/src/fw/romfile_loader.c b/roms/seabios-hppa/src/fw/romfile_loader.c
new file mode 100644
index 000000000..18476e207
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/romfile_loader.c
@@ -0,0 +1,259 @@
+#include "romfile_loader.h"
+#include "byteorder.h" // leXX_to_cpu/cpu_to_leXX
+#include "util.h" // checksum
+#include "string.h" // strcmp
+#include "romfile.h" // struct romfile_s
+#include "malloc.h" // Zone*, _malloc
+#include "list.h" // struct hlist_node
+#include "output.h" // warn_*
+#include "paravirt.h" // qemu_cfg_write_file
+
+struct romfile_loader_file {
+ struct romfile_s *file;
+ void *data;
+};
+struct romfile_loader_files {
+ int nfiles;
+ struct romfile_loader_file files[];
+};
+
+// Data structures for storing "write pointer" entries for possible replay
+struct romfile_wr_pointer_entry {
+ u64 pointer;
+ u32 offset;
+ u16 key;
+ u8 ptr_size;
+ struct hlist_node node;
+};
+static struct hlist_head romfile_pointer_list;
+
+static struct romfile_loader_file *
+romfile_loader_find(const char *name,
+ struct romfile_loader_files *files)
+{
+ int i;
+ if (name[ROMFILE_LOADER_FILESZ - 1])
+ return NULL;
+ for (i = 0; i < files->nfiles; ++i)
+ if (!strcmp(files->files[i].file->name, name))
+ return &files->files[i];
+ return NULL;
+}
+
+// Replay "write pointer" entries back to QEMU
+void romfile_fw_cfg_resume(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ struct romfile_wr_pointer_entry *entry;
+ hlist_for_each_entry(entry, &romfile_pointer_list, node) {
+ qemu_cfg_write_file_simple(&entry->pointer, entry->key,
+ entry->offset, entry->ptr_size);
+ }
+}
+
+static void romfile_loader_allocate(struct romfile_loader_entry_s *entry,
+ struct romfile_loader_files *files)
+{
+ struct zone_s *zone;
+ struct romfile_loader_file *file = &files->files[files->nfiles];
+ void *data;
+ int ret;
+ unsigned alloc_align = le32_to_cpu(entry->alloc.align);
+
+ if (alloc_align & (alloc_align - 1))
+ goto err;
+
+ switch (entry->alloc.zone) {
+ case ROMFILE_LOADER_ALLOC_ZONE_HIGH:
+ zone = &ZoneHigh;
+ break;
+ case ROMFILE_LOADER_ALLOC_ZONE_FSEG:
+ zone = &ZoneFSeg;
+ break;
+ default:
+ goto err;
+ }
+ if (alloc_align < MALLOC_MIN_ALIGN)
+ alloc_align = MALLOC_MIN_ALIGN;
+ if (entry->alloc.file[ROMFILE_LOADER_FILESZ - 1])
+ goto err;
+ file->file = romfile_find(entry->alloc.file);
+ if (!file->file || !file->file->size)
+ return;
+ data = _malloc(zone, file->file->size, alloc_align);
+ if (!data) {
+ warn_noalloc();
+ return;
+ }
+ ret = file->file->copy(file->file, data, file->file->size);
+ if (ret != file->file->size)
+ goto file_err;
+ file->data = data;
+ files->nfiles++;
+ return;
+
+file_err:
+ free(data);
+err:
+ warn_internalerror();
+}
+
+static void romfile_loader_add_pointer(struct romfile_loader_entry_s *entry,
+ struct romfile_loader_files *files)
+{
+ struct romfile_loader_file *dest_file;
+ struct romfile_loader_file *src_file;
+ unsigned offset = le32_to_cpu(entry->pointer.offset);
+ u64 pointer = 0;
+
+ dest_file = romfile_loader_find(entry->pointer.dest_file, files);
+ src_file = romfile_loader_find(entry->pointer.src_file, files);
+
+ if (!dest_file || !src_file || !dest_file->data || !src_file->data ||
+ offset + entry->pointer.size < offset ||
+ offset + entry->pointer.size > dest_file->file->size ||
+ entry->pointer.size < 1 || entry->pointer.size > 8 ||
+ entry->pointer.size & (entry->pointer.size - 1))
+ goto err;
+
+ memcpy(&pointer, dest_file->data + offset, entry->pointer.size);
+ pointer = le64_to_cpu(pointer);
+ pointer += (unsigned long)src_file->data;
+ pointer = cpu_to_le64(pointer);
+ memcpy(dest_file->data + offset, &pointer, entry->pointer.size);
+
+ return;
+err:
+ warn_internalerror();
+}
+
+static void romfile_loader_add_checksum(struct romfile_loader_entry_s *entry,
+ struct romfile_loader_files *files)
+{
+ struct romfile_loader_file *file;
+ unsigned offset = le32_to_cpu(entry->cksum.offset);
+ unsigned start = le32_to_cpu(entry->cksum.start);
+ unsigned len = le32_to_cpu(entry->cksum.length);
+ u8 *data;
+
+ file = romfile_loader_find(entry->cksum.file, files);
+
+ if (!file || !file->data || offset >= file->file->size ||
+ start + len < start || start + len > file->file->size)
+ goto err;
+
+ data = file->data + offset;
+ *data -= checksum(file->data + start, len);
+
+ return;
+err:
+ warn_internalerror();
+}
+
+static void romfile_loader_write_pointer(struct romfile_loader_entry_s *entry,
+ struct romfile_loader_files *files)
+{
+ struct romfile_s *dest_file;
+ struct romfile_loader_file *src_file;
+ unsigned dst_offset = le32_to_cpu(entry->wr_pointer.dst_offset);
+ unsigned src_offset = le32_to_cpu(entry->wr_pointer.src_offset);
+ u64 pointer = 0;
+
+ /* Writing back to a file that may not be loaded in RAM */
+ dest_file = romfile_find(entry->wr_pointer.dest_file);
+ src_file = romfile_loader_find(entry->wr_pointer.src_file, files);
+
+ if (!dest_file || !src_file || !src_file->data ||
+ dst_offset + entry->wr_pointer.size < dst_offset ||
+ dst_offset + entry->wr_pointer.size > dest_file->size ||
+ src_offset >= src_file->file->size ||
+ entry->wr_pointer.size < 1 || entry->wr_pointer.size > 8 ||
+ entry->wr_pointer.size & (entry->wr_pointer.size - 1)) {
+ goto err;
+ }
+
+ pointer = (unsigned long)src_file->data + src_offset;
+ /* Make sure the pointer fits within wr_pointer.size */
+ if ((entry->wr_pointer.size != sizeof(u64)) &&
+ ((pointer >> (entry->wr_pointer.size * 8)) > 0)) {
+ goto err;
+ }
+ pointer = cpu_to_le64(pointer);
+
+ /* Only supported on QEMU */
+ if (qemu_cfg_write_file(&pointer, dest_file, dst_offset,
+ entry->wr_pointer.size) != entry->wr_pointer.size) {
+ goto err;
+ }
+
+ /* Store the info so it can replayed later if necessary */
+ struct romfile_wr_pointer_entry *store = malloc_high(sizeof(*store));
+ if (!store) {
+ warn_noalloc();
+ return;
+ }
+ store->pointer = pointer;
+ store->key = qemu_get_romfile_key(dest_file);
+ store->offset = dst_offset;
+ store->ptr_size = entry->wr_pointer.size;
+ hlist_add_head(&store->node, &romfile_pointer_list);
+
+ return;
+ err:
+ warn_internalerror();
+}
+
+int romfile_loader_execute(const char *name)
+{
+ struct romfile_loader_entry_s *entry;
+ int size, offset = 0, nfiles;
+ struct romfile_loader_files *files;
+ void *data = romfile_loadfile(name, &size);
+ if (!data)
+ return -1;
+
+ if (size % sizeof(*entry)) {
+ warn_internalerror();
+ goto err;
+ }
+
+ /* (over)estimate the number of files to load. */
+ nfiles = size / sizeof(*entry);
+ files = malloc_tmp(sizeof(*files) + nfiles * sizeof(files->files[0]));
+ if (!files) {
+ warn_noalloc();
+ goto err;
+ }
+ files->nfiles = 0;
+
+ for (offset = 0; offset < size; offset += sizeof(*entry)) {
+ entry = data + offset;
+ switch (le32_to_cpu(entry->command)) {
+ case ROMFILE_LOADER_COMMAND_ALLOCATE:
+ romfile_loader_allocate(entry, files);
+ break;
+ case ROMFILE_LOADER_COMMAND_ADD_POINTER:
+ romfile_loader_add_pointer(entry, files);
+ break;
+ case ROMFILE_LOADER_COMMAND_ADD_CHECKSUM:
+ romfile_loader_add_checksum(entry, files);
+ break;
+ case ROMFILE_LOADER_COMMAND_WRITE_POINTER:
+ romfile_loader_write_pointer(entry, files);
+ break;
+ default:
+ /* Skip commands that we don't recognize. */
+ break;
+ }
+ }
+
+ free(files);
+ free(data);
+ return 0;
+
+err:
+ free(data);
+ return -1;
+}
diff --git a/roms/seabios-hppa/src/fw/romfile_loader.h b/roms/seabios-hppa/src/fw/romfile_loader.h
new file mode 100644
index 000000000..fcd4ab236
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/romfile_loader.h
@@ -0,0 +1,91 @@
+#ifndef __ROMFILE_LOADER_H
+#define __ROMFILE_LOADER_H
+
+#include "types.h" // u8
+#include "util.h" // romfile_s
+
+#define ROMFILE_LOADER_FILESZ 56
+
+/* ROM file linker/loader interface. Linker uses little endian format */
+struct romfile_loader_entry_s {
+ u32 command;
+ union {
+ /*
+ * COMMAND_ALLOCATE - allocate a table from @alloc.file
+ * subject to @alloc.align alignment (must be power of 2)
+ * and @alloc.zone (can be HIGH or FSEG) requirements.
+ *
+ * Must appear exactly once for each file, and before
+ * this file is referenced by any other command.
+ */
+ struct {
+ char file[ROMFILE_LOADER_FILESZ];
+ u32 align;
+ u8 zone;
+ } alloc;
+
+ /*
+ * COMMAND_ADD_POINTER - patch the table (originating from
+ * @dest_file) at @pointer.offset, by adding a pointer to the table
+ * originating from @src_file. 1,2,4 or 8 byte unsigned
+ * addition is used depending on @pointer.size.
+ */
+ struct {
+ char dest_file[ROMFILE_LOADER_FILESZ];
+ char src_file[ROMFILE_LOADER_FILESZ];
+ u32 offset;
+ u8 size;
+ } pointer;
+
+ /*
+ * COMMAND_ADD_CHECKSUM - calculate checksum of the range specified by
+ * @cksum.start and @cksum.length fields,
+ * and then add the value at @cksum_offset.
+ * Checksum simply sums -X for each byte X in the range
+ * using 8-bit math.
+ */
+ struct {
+ char file[ROMFILE_LOADER_FILESZ];
+ u32 offset;
+ u32 start;
+ u32 length;
+ } cksum;
+
+ /*
+ * COMMAND_WRITE_POINTER - Write back to a host file via DMA,
+ * @wr_pointer.dest_file at offset @wr_pointer.dst_offset, a pointer
+ * to the table originating from @wr_pointer.src_file at offset
+ * @wr_pointer.src_offset.
+ * 1,2,4 or 8 byte unsigned addition is used depending on
+ * @wr_pointer.size.
+ */
+ struct {
+ char dest_file[ROMFILE_LOADER_FILESZ];
+ char src_file[ROMFILE_LOADER_FILESZ];
+ u32 dst_offset;
+ u32 src_offset;
+ u8 size;
+ } wr_pointer;
+
+ /* padding */
+ char pad[124];
+ };
+};
+
+enum {
+ ROMFILE_LOADER_COMMAND_ALLOCATE = 0x1,
+ ROMFILE_LOADER_COMMAND_ADD_POINTER = 0x2,
+ ROMFILE_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
+ ROMFILE_LOADER_COMMAND_WRITE_POINTER = 0x4,
+};
+
+enum {
+ ROMFILE_LOADER_ALLOC_ZONE_HIGH = 0x1,
+ ROMFILE_LOADER_ALLOC_ZONE_FSEG = 0x2,
+};
+
+int romfile_loader_execute(const char *name);
+
+void romfile_fw_cfg_resume(void);
+
+#endif
diff --git a/roms/seabios-hppa/src/fw/shadow.c b/roms/seabios-hppa/src/fw/shadow.c
new file mode 100644
index 000000000..2ea7205f0
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/shadow.c
@@ -0,0 +1,210 @@
+// Support for enabling/disabling BIOS ram shadowing.
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "dev-q35.h" // PCI_VENDOR_ID_INTEL
+#include "dev-piix.h" // I440FX_PAM0
+#include "hw/pci.h" // pci_config_writeb
+#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "hw/pci_regs.h" // PCI_VENDOR_ID
+#include "malloc.h" // rom_get_last
+#include "output.h" // dprintf
+#include "paravirt.h" // runningOnXen
+#include "string.h" // memset
+#include "util.h" // make_bios_writable
+#include "x86.h" // wbinvd
+
+// On the emulators, the bios at 0xf0000 is also at 0xffff0000
+#define BIOS_SRC_OFFSET 0xfff00000
+
+union pamdata_u {
+ u8 data8[8];
+ u32 data32[2];
+};
+
+// Enable shadowing and copy bios.
+static void
+__make_bios_writable_intel(u16 bdf, u32 pam0)
+{
+ // Read in current PAM settings from pci config space
+ union pamdata_u pamdata;
+ pamdata.data32[0] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4));
+ pamdata.data32[1] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4) + 4);
+ u8 *pam = &pamdata.data8[pam0 & 0x03];
+
+ // Make ram from 0xc0000-0xf0000 writable
+ int i;
+ for (i=0; i<6; i++)
+ pam[i + 1] = 0x33;
+
+ // Make ram from 0xf0000-0x100000 writable
+ int ram_present = pam[0] & 0x10;
+ pam[0] = 0x30;
+
+ // Write PAM settings back to pci config space
+ pci_config_writel(bdf, ALIGN_DOWN(pam0, 4), pamdata.data32[0]);
+ pci_config_writel(bdf, ALIGN_DOWN(pam0, 4) + 4, pamdata.data32[1]);
+
+ if (!ram_present)
+ // Copy bios.
+ memcpy(VSYMBOL(code32flat_start)
+ , VSYMBOL(code32flat_start) + BIOS_SRC_OFFSET
+ , SYMBOL(code32flat_end) - SYMBOL(code32flat_start));
+}
+
+static void
+make_bios_writable_intel(u16 bdf, u32 pam0)
+{
+ int reg = pci_config_readb(bdf, 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 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;
+ func(bdf, pam0);
+ return;
+ }
+ // Ram already present - just enable writes
+ __make_bios_writable_intel(bdf, pam0);
+}
+
+static void
+make_bios_readonly_intel(u16 bdf, u32 pam0)
+{
+ // Flush any pending writes before locking memory.
+ wbinvd();
+
+ // Read in current PAM settings from pci config space
+ union pamdata_u pamdata;
+ pamdata.data32[0] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4));
+ pamdata.data32[1] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4) + 4);
+ u8 *pam = &pamdata.data8[pam0 & 0x03];
+
+ // Write protect roms from 0xc0000-0xf0000
+ u32 romlast = BUILD_BIOS_ADDR, rommax = BUILD_BIOS_ADDR;
+ if (CONFIG_WRITABLE_UPPERMEMORY)
+ romlast = rom_get_last();
+ if (CONFIG_MALLOC_UPPERMEMORY)
+ rommax = rom_get_max();
+ int i;
+ for (i=0; i<6; i++) {
+ u32 mem = BUILD_ROM_START + i * 32*1024;
+ if (romlast < mem + 16*1024 || rommax < mem + 32*1024) {
+ if (romlast >= mem && rommax >= mem + 16*1024)
+ pam[i + 1] = 0x31;
+ break;
+ }
+ pam[i + 1] = 0x11;
+ }
+
+ // Write protect 0xf0000-0x100000
+ pam[0] = 0x10;
+
+ // Write PAM settings back to pci config space
+ pci_config_writel(bdf, ALIGN_DOWN(pam0, 4), pamdata.data32[0]);
+ pci_config_writel(bdf, ALIGN_DOWN(pam0, 4) + 4, pamdata.data32[1]);
+}
+
+static int ShadowBDF = -1;
+
+// Make the 0xc0000-0x100000 area read/writable.
+void
+make_bios_writable(void)
+{
+ if (!CONFIG_QEMU || runningOnXen())
+ return;
+
+ dprintf(3, "enabling shadow ram\n");
+
+ // At this point, statically allocated variables can't be written,
+ // so do this search manually.
+ int bdf;
+ foreachbdf(bdf, 0) {
+ u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
+ u16 vendor = vendev & 0xffff, device = vendev >> 16;
+ if (vendor == PCI_VENDOR_ID_INTEL
+ && device == PCI_DEVICE_ID_INTEL_82441) {
+ make_bios_writable_intel(bdf, I440FX_PAM0);
+ code_mutable_preinit();
+ ShadowBDF = bdf;
+ return;
+ }
+ if (vendor == PCI_VENDOR_ID_INTEL
+ && device == PCI_DEVICE_ID_INTEL_Q35_MCH) {
+ make_bios_writable_intel(bdf, Q35_HOST_BRIDGE_PAM0);
+ code_mutable_preinit();
+ ShadowBDF = bdf;
+ return;
+ }
+ }
+ dprintf(1, "Unable to unlock ram - bridge not found\n");
+}
+
+// Make the BIOS code segment area (0xf0000) read-only.
+void
+make_bios_readonly(void)
+{
+ if (!CONFIG_QEMU || runningOnXen())
+ return;
+ dprintf(3, "locking shadow ram\n");
+
+ if (ShadowBDF < 0) {
+ dprintf(1, "Unable to lock ram - bridge not found\n");
+ return;
+ }
+
+ u16 device = pci_config_readw(ShadowBDF, PCI_DEVICE_ID);
+ if (device == PCI_DEVICE_ID_INTEL_82441)
+ make_bios_readonly_intel(ShadowBDF, I440FX_PAM0);
+ else
+ make_bios_readonly_intel(ShadowBDF, Q35_HOST_BRIDGE_PAM0);
+}
+
+void
+qemu_reboot(void)
+{
+ if (!CONFIG_QEMU || runningOnXen())
+ return;
+ // QEMU doesn't map 0xc0000-0xfffff back to the original rom on a
+ // reset, so do that manually before invoking a hard reset.
+ void *flash = (void*)BIOS_SRC_OFFSET;
+ u32 hrp = (u32)&HaveRunPost;
+ if (readl(flash + hrp)) {
+ // There isn't a pristine copy of the BIOS at 0xffff0000 to copy
+ if (HaveRunPost == 3) {
+ // In a reboot loop. Try to shutdown the machine instead.
+ dprintf(1, "Unable to hard-reboot machine - attempting shutdown.\n");
+ apm_shutdown();
+ }
+ make_bios_writable();
+ HaveRunPost = 3;
+ } else {
+ // Copy the BIOS making sure to only reset HaveRunPost at end
+ make_bios_writable();
+ u32 cstart = SYMBOL(code32flat_start), cend = SYMBOL(code32flat_end);
+ memcpy((void*)cstart, flash + cstart, hrp - cstart);
+ memcpy((void*)hrp + 4, flash + hrp + 4, cend - (hrp + 4));
+ barrier();
+ HaveRunPost = 0;
+ barrier();
+ }
+
+ // Request a QEMU system reset. Do the reset in this function as
+ // the BIOS code was overwritten above and not all BIOS
+ // functionality may be available.
+
+ // Attempt PCI style reset
+ outb(0x02, PORT_PCI_REBOOT);
+ outb(0x06, PORT_PCI_REBOOT);
+
+ // Next try triple faulting the CPU to force a reset
+#if CONFIG_X86
+ asm volatile("int3");
+#endif
+}
diff --git a/roms/seabios-hppa/src/fw/smbios.c b/roms/seabios-hppa/src/fw/smbios.c
new file mode 100644
index 000000000..62a563b23
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/smbios.c
@@ -0,0 +1,589 @@
+// smbios table generation (on emulators)
+// DO NOT ADD NEW FEATURES HERE. (See paravirt.c / biostables.c instead.)
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// 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 "paravirt.h" // RamSize
+#include "romfile.h" // romfile_findprefix
+#include "std/smbios.h" // struct smbios_entry_point
+#include "string.h" // memset
+#include "util.h" // MaxCountCPUs
+#include "x86.h" // cpuid
+
+static void
+smbios_entry_point_setup(u16 max_structure_size,
+ u16 structure_table_length,
+ void *structure_table_address,
+ u16 number_of_structures)
+{
+ void *finaltable;
+ if (structure_table_length <= BUILD_MAX_SMBIOS_FSEG)
+ // Table is small enough for f-seg - allocate there. This
+ // works around a bug in JunOS (at least for small SMBIOS tables).
+ finaltable = malloc_fseg(structure_table_length);
+ else
+ finaltable = malloc_high(structure_table_length);
+ if (!finaltable) {
+ warn_noalloc();
+ return;
+ }
+ memcpy(finaltable, structure_table_address, structure_table_length);
+
+ struct smbios_entry_point ep;
+ memset(&ep, 0, sizeof(ep));
+ ep.signature = SMBIOS_SIGNATURE;
+ ep.length = 0x1f;
+ ep.smbios_major_version = 2;
+ ep.smbios_minor_version = 4;
+ ep.max_structure_size = max_structure_size;
+ memcpy(ep.intermediate_anchor_string, "_DMI_", 5);
+
+ ep.structure_table_length = structure_table_length;
+ ep.structure_table_address = (u32)finaltable;
+ ep.number_of_structures = number_of_structures;
+ ep.smbios_bcd_revision = 0x24;
+
+ ep.checksum -= checksum(&ep, 0x10);
+
+ ep.intermediate_checksum -= checksum((void*)&ep + 0x10, ep.length - 0x10);
+
+ copy_smbios(&ep);
+}
+
+static int
+get_field(int type, int offset, void *dest)
+{
+ char name[128];
+ snprintf(name, sizeof(name), "smbios/field%d-%d", type, offset);
+ struct romfile_s *file = romfile_find(name);
+ if (!file)
+ return 0;
+ file->copy(file, dest, file->size);
+ return file->size;
+}
+
+static int
+get_external(int type, char **p, unsigned *nr_structs,
+ unsigned *max_struct_size, char *end)
+{
+ static u64 used_bitmap[4] = { 0 };
+ char *start = *p;
+
+ /* Check if we've already reported these tables */
+ if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
+ return 1;
+
+ /* Don't introduce spurious end markers */
+ if (type == 127)
+ return 0;
+
+ char prefix[128];
+ snprintf(prefix, sizeof(prefix), "smbios/table%d-", type);
+ struct romfile_s *file = NULL;
+ for (;;) {
+ file = romfile_findprefix(prefix, file);
+ if (!file)
+ break;
+
+ if (end - *p < file->size) {
+ warn_noalloc();
+ break;
+ }
+
+ struct smbios_structure_header *header = (void*)*p;
+ file->copy(file, header, file->size);
+ *p += file->size;
+
+ /* Entries end with a double NULL char, if there's a string at
+ * the end (length is greater than formatted length), the string
+ * terminator provides the first NULL. */
+ *((u8*)*p) = 0;
+ (*p)++;
+ if (header->length >= file->size) {
+ *((u8*)*p) = 0;
+ (*p)++;
+ }
+
+ (*nr_structs)++;
+ if (*p - (char*)header > *max_struct_size)
+ *max_struct_size = *p - (char*)header;
+ }
+
+ if (start == *p)
+ return 0;
+
+ /* Mark that we've reported on this type */
+ used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
+ return 1;
+}
+
+#define load_str_field_with_default(type, field, def) \
+ do { \
+ size = get_field(type, offsetof(struct smbios_type_##type, \
+ field), end); \
+ if (size == 1) { \
+ /* zero-length string, skip to avoid bogus end marker */ \
+ p->field = 0; \
+ } else if (size > 1) { \
+ end += size; \
+ p->field = ++str_index; \
+ } else { \
+ memcpy(end, def, sizeof(def)); \
+ end += sizeof(def); \
+ p->field = ++str_index; \
+ } \
+ } while (0)
+
+#define load_str_field_or_skip(type, field) \
+ do { \
+ size = get_field(type, offsetof(struct smbios_type_##type, \
+ field), end); \
+ if (size > 1) { \
+ end += size; \
+ p->field = ++str_index; \
+ } else { \
+ p->field = 0; \
+ } \
+ } while (0)
+
+#define set_field_with_default(type, field, def) \
+ do { \
+ if (!get_field(type, offsetof(struct smbios_type_##type, \
+ field), &p->field)) { \
+ p->field = def; \
+ } \
+ } while (0)
+
+/* Type 0 -- BIOS Information */
+#define RELEASE_DATE_STR "01/01/2011"
+static void *
+smbios_init_type_0(void *start)
+{
+ struct smbios_type_0 *p = (struct smbios_type_0 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_0);
+ size_t size;
+ int str_index = 0;
+
+ p->header.type = 0;
+ p->header.length = sizeof(struct smbios_type_0);
+ p->header.handle = 0;
+
+ load_str_field_with_default(0, vendor_str, BUILD_APPNAME);
+ load_str_field_with_default(0, bios_version_str, BUILD_APPNAME);
+
+ p->bios_starting_address_segment = 0xe800;
+
+ load_str_field_with_default(0, bios_release_date_str, RELEASE_DATE_STR);
+
+ p->bios_rom_size = 0; /* FIXME */
+
+ if (!get_field(0, offsetof(struct smbios_type_0, bios_characteristics),
+ &p->bios_characteristics)) {
+ memset(p->bios_characteristics, 0, 8);
+ /* BIOS characteristics not supported */
+ p->bios_characteristics[0] = 0x08;
+ }
+
+ if (!get_field(0, offsetof(struct smbios_type_0,
+ bios_characteristics_extension_bytes),
+ &p->bios_characteristics_extension_bytes)) {
+ p->bios_characteristics_extension_bytes[0] = 0;
+ /* Enable targeted content distribution. Needed for SVVP */
+ p->bios_characteristics_extension_bytes[1] = 4;
+ }
+
+ set_field_with_default(0, system_bios_major_release, 1);
+ set_field_with_default(0, system_bios_minor_release, 0);
+ set_field_with_default(0, embedded_controller_major_release, 0xff);
+ set_field_with_default(0, embedded_controller_minor_release, 0xff);
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+/* Type 1 -- System Information */
+static void *
+smbios_init_type_1(void *start)
+{
+ struct smbios_type_1 *p = (struct smbios_type_1 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_1);
+ size_t size;
+ int str_index = 0;
+
+ p->header.type = 1;
+ p->header.length = sizeof(struct smbios_type_1);
+ p->header.handle = 0x100;
+
+ load_str_field_with_default(1, manufacturer_str, BUILD_APPNAME);
+ load_str_field_with_default(1, product_name_str, BUILD_APPNAME);
+ load_str_field_or_skip(1, version_str);
+ load_str_field_or_skip(1, serial_number_str);
+
+ if (!get_field(1, offsetof(struct smbios_type_1, uuid), &p->uuid))
+ memset(p->uuid, 0, 16);
+
+ set_field_with_default(1, wake_up_type, 0x06); /* power switch */
+
+ load_str_field_or_skip(1, sku_number_str);
+ load_str_field_or_skip(1, family_str);
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+/* Type 3 -- System Enclosure */
+static void *
+smbios_init_type_3(void *start)
+{
+ struct smbios_type_3 *p = (struct smbios_type_3 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_3);
+ size_t size;
+ int str_index = 0;
+
+ p->header.type = 3;
+ p->header.length = sizeof(struct smbios_type_3);
+ p->header.handle = 0x300;
+
+ load_str_field_with_default(3, manufacturer_str, BUILD_APPNAME);
+ set_field_with_default(3, type, 0x01); /* other */
+
+ load_str_field_or_skip(3, version_str);
+ load_str_field_or_skip(3, serial_number_str);
+ load_str_field_or_skip(3, asset_tag_number_str);
+
+ set_field_with_default(3, boot_up_state, 0x03); /* safe */
+ set_field_with_default(3, power_supply_state, 0x03); /* safe */
+ set_field_with_default(3, thermal_state, 0x03); /* safe */
+ set_field_with_default(3, security_status, 0x02); /* unknown */
+
+ set_field_with_default(3, oem_defined, 0);
+ set_field_with_default(3, height, 0);
+ set_field_with_default(3, number_of_power_cords, 0);
+ set_field_with_default(3, contained_element_count, 0);
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+/* Type 4 -- Processor Information */
+static void *
+smbios_init_type_4(void *start, unsigned int cpu_number)
+{
+ struct smbios_type_4 *p = (struct smbios_type_4 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_4);
+ size_t size;
+ int str_index = 0;
+ char name[1024];
+
+ p->header.type = 4;
+ p->header.length = sizeof(struct smbios_type_4);
+ p->header.handle = 0x400 + cpu_number;
+
+ size = get_field(4, offsetof(struct smbios_type_4, socket_designation_str),
+ name);
+ if (size)
+ snprintf(name + size - 1, sizeof(name) - size, "%2x", cpu_number);
+ else
+ snprintf(name, sizeof(name), "CPU%2x", cpu_number);
+
+ memcpy(end, name, strlen(name) + 1);
+ end += strlen(name) + 1;
+ p->socket_designation_str = ++str_index;
+
+ set_field_with_default(4, processor_type, 0x03); /* CPU */
+ set_field_with_default(4, processor_family, 0x01); /* other */
+
+ load_str_field_with_default(4, processor_manufacturer_str, BUILD_APPNAME);
+
+ if (!get_field(4, offsetof(struct smbios_type_4, processor_id)
+ , p->processor_id)) {
+ u32 cpuid_signature, ebx, ecx, cpuid_features;
+ cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features);
+ p->processor_id[0] = cpuid_signature;
+ p->processor_id[1] = cpuid_features;
+ }
+
+ load_str_field_or_skip(4, processor_version_str);
+ set_field_with_default(4, voltage, 0);
+ set_field_with_default(4, external_clock, 0);
+
+ set_field_with_default(4, max_speed, 2000);
+ set_field_with_default(4, current_speed, 2000);
+
+ set_field_with_default(4, status, 0x41); /* socket populated, CPU enabled */
+ set_field_with_default(4, processor_upgrade, 0x01); /* other */
+
+ /* cache information structure not provided */
+ p->l1_cache_handle = 0xffff;
+ p->l2_cache_handle = 0xffff;
+ p->l3_cache_handle = 0xffff;
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+/* Type 16 -- Physical Memory Array */
+static void *
+smbios_init_type_16(void *start, u32 memory_size_mb, int nr_mem_devs)
+{
+ struct smbios_type_16 *p = (struct smbios_type_16*)start;
+
+ p->header.type = 16;
+ p->header.length = sizeof(struct smbios_type_16);
+ p->header.handle = 0x1000;
+
+ set_field_with_default(16, location, 0x01); /* other */
+ set_field_with_default(16, use, 0x03); /* system memory */
+ /* Multi-bit ECC to make Microsoft happy */
+ set_field_with_default(16, error_correction, 0x06);
+ /* 0x80000000 = unknown, accept sizes < 2TB - TODO multiple arrays */
+ p->maximum_capacity = memory_size_mb < 2 << 20 ?
+ memory_size_mb << 10 : 0x80000000;
+ p->memory_error_information_handle = 0xfffe; /* none provided */
+ p->number_of_memory_devices = nr_mem_devs;
+
+ start += sizeof(struct smbios_type_16);
+ *((u16 *)start) = 0;
+
+ return start + 2;
+}
+
+/* Type 17 -- Memory Device */
+static void *
+smbios_init_type_17(void *start, u32 size_mb, int instance)
+{
+ struct smbios_type_17 *p = (struct smbios_type_17 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_17);
+ size_t size;
+ int str_index = 0;
+ char name[1024];
+
+ p->header.type = 17;
+ p->header.length = sizeof(struct smbios_type_17);
+ p->header.handle = 0x1100 + instance;
+
+ p->physical_memory_array_handle = 0x1000;
+ set_field_with_default(17, total_width, 64);
+ set_field_with_default(17, data_width, 64);
+/* TODO: should assert in case something is wrong ASSERT((memory_size_mb & ~0x7fff) == 0); */
+ p->size = size_mb;
+ set_field_with_default(17, form_factor, 0x09); /* DIMM */
+ p->device_set = 0;
+
+ size = get_field(17, offsetof(struct smbios_type_17, device_locator_str),
+ name);
+ if (size)
+ snprintf(name + size - 1, sizeof(name) - size, "%d", instance);
+ else
+ snprintf(name, sizeof(name), "DIMM %d", instance);
+
+ memcpy(end, name, strlen(name) + 1);
+ end += strlen(name) + 1;
+ p->device_locator_str = ++str_index;
+
+ load_str_field_or_skip(17, bank_locator_str);
+ set_field_with_default(17, memory_type, 0x07); /* RAM */
+ set_field_with_default(17, type_detail, 0);
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+/* Type 19 -- Memory Array Mapped Address */
+static void *
+smbios_init_type_19(void *start, u32 start_mb, u32 size_mb, int instance)
+{
+ struct smbios_type_19 *p = (struct smbios_type_19 *)start;
+
+ p->header.type = 19;
+ p->header.length = sizeof(struct smbios_type_19);
+ p->header.handle = 0x1300 + instance;
+
+ p->starting_address = start_mb << 10;
+ p->ending_address = p->starting_address + (size_mb << 10) - 1;
+ p->memory_array_handle = 0x1000;
+ p->partition_width = 1;
+
+ start += sizeof(struct smbios_type_19);
+ *((u16 *)start) = 0;
+
+ return start + 2;
+}
+
+/* Type 20 -- Memory Device Mapped Address */
+static void *
+smbios_init_type_20(void *start, u32 start_mb, u32 size_mb, int instance,
+ int dev_handle, int array_handle)
+{
+ struct smbios_type_20 *p = (struct smbios_type_20 *)start;
+
+ p->header.type = 20;
+ p->header.length = sizeof(struct smbios_type_20);
+ p->header.handle = 0x1400 + instance;
+
+ p->starting_address = start_mb << 10;
+ p->ending_address = p->starting_address + (size_mb << 10) - 1;
+ p->memory_device_handle = 0x1100 + dev_handle;
+ p->memory_array_mapped_address_handle = 0x1300 + array_handle;
+ p->partition_row_position = 1;
+ p->interleave_position = 0;
+ p->interleaved_data_depth = 0;
+
+ start += sizeof(struct smbios_type_20);
+
+ *((u16 *)start) = 0;
+ return start+2;
+}
+
+/* Type 32 -- System Boot Information */
+static void *
+smbios_init_type_32(void *start)
+{
+ struct smbios_type_32 *p = (struct smbios_type_32 *)start;
+
+ p->header.type = 32;
+ p->header.length = sizeof(struct smbios_type_32);
+ p->header.handle = 0x2000;
+ memset(p->reserved, 0, 6);
+ set_field_with_default(32, boot_status, 0); /* no errors detected */
+
+ start += sizeof(struct smbios_type_32);
+ *((u16 *)start) = 0;
+
+ return start+2;
+}
+
+/* Type 127 -- End of Table */
+static void *
+smbios_init_type_127(void *start)
+{
+ struct smbios_type_127 *p = (struct smbios_type_127 *)start;
+
+ p->header.type = 127;
+ p->header.length = sizeof(struct smbios_type_127);
+ p->header.handle = 0x7f00;
+
+ start += sizeof(struct smbios_type_127);
+ *((u16 *)start) = 0;
+
+ return start + 2;
+}
+
+#define TEMPSMBIOSSIZE (32 * 1024)
+
+void
+smbios_legacy_setup(void)
+{
+ if (! CONFIG_SMBIOS)
+ return;
+
+ dprintf(3, "init SMBIOS tables\n");
+
+ char *start = malloc_tmphigh(TEMPSMBIOSSIZE);
+ if (! start) {
+ warn_noalloc();
+ return;
+ }
+ memset(start, 0, TEMPSMBIOSSIZE);
+
+ u32 nr_structs = 0, max_struct_size = 0;
+ char *q, *p = start;
+ char *end = start + TEMPSMBIOSSIZE - sizeof(struct smbios_type_127);
+
+#define add_struct(type, args...) \
+ do { \
+ if (!get_external(type, &p, &nr_structs, &max_struct_size, end)) { \
+ q = smbios_init_type_##type(args); \
+ nr_structs++; \
+ if ((q - p) > max_struct_size) \
+ max_struct_size = q - p; \
+ p = q; \
+ } \
+ } while (0)
+
+ add_struct(0, p);
+ add_struct(1, p);
+ add_struct(3, p);
+
+ int cpu_num;
+ for (cpu_num = 1; cpu_num <= MaxCountCPUs; cpu_num++)
+ add_struct(4, p, cpu_num);
+
+ int ram_mb = (RamSize + RamSizeOver4G) >> 20;
+ int nr_mem_devs = (ram_mb + 0x3fff) >> 14;
+ add_struct(16, p, ram_mb, nr_mem_devs);
+
+ int i, j;
+ for (i = 0; i < nr_mem_devs; i++) {
+ u32 dev_mb = ((i == (nr_mem_devs - 1))
+ ? (((ram_mb - 1) & 0x3fff) + 1)
+ : 16384);
+ add_struct(17, p, dev_mb, i);
+ }
+
+ add_struct(19, p, 0, RamSize >> 20, 0);
+ if (RamSizeOver4G)
+ add_struct(19, p, 4096, RamSizeOver4G >> 20, 1);
+
+ add_struct(20, p, 0, RamSize >> 20, 0, 0, 0);
+ if (RamSizeOver4G) {
+ u32 start_mb = 4096;
+ for (j = 1, i = 0; i < nr_mem_devs; i++, j++) {
+ u32 dev_mb = ((i == (nr_mem_devs - 1))
+ ? (((ram_mb - 1) & 0x3fff) + 1)
+ : 16384);
+ if (i == 0)
+ dev_mb -= RamSize >> 20;
+
+ add_struct(20, p, start_mb, dev_mb, j, i, 1);
+ start_mb += dev_mb;
+ }
+ }
+
+ add_struct(32, p);
+ /* Add any remaining provided entries before the end marker */
+ for (i = 0; i < 256; i++)
+ get_external(i, &p, &nr_structs, &max_struct_size, end);
+ add_struct(127, p);
+
+#undef add_struct
+
+ smbios_entry_point_setup(max_struct_size, p - start, start, nr_structs);
+ free(start);
+}
diff --git a/roms/seabios-hppa/src/fw/smm.c b/roms/seabios-hppa/src/fw/smm.c
new file mode 100644
index 000000000..d90e43a9e
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/smm.c
@@ -0,0 +1,269 @@
+// System Management Mode support (on emulators)
+//
+// Copyright (C) 2008-2014 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "dev-q35.h"
+#include "dev-piix.h"
+#include "hw/pci.h" // pci_config_writel
+#include "hw/pcidevice.h" // pci_find_device
+#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "hw/pci_regs.h" // PCI_DEVICE_ID
+#include "output.h" // dprintf
+#include "paravirt.h" // PORT_SMI_STATUS
+#include "stacks.h" // HaveSmmCall32
+#include "string.h" // memcpy
+#include "util.h" // smm_setup
+#include "x86.h" // wbinvd
+
+/*
+ * Check SMM state save area format (bits 0-15) and require support
+ * for SMBASE relocation.
+ */
+#define SMM_REV_MASK 0x0002ffff
+
+#define SMM_REV_I32 0x00020000
+#define SMM_REV_I64 0x00020064
+
+struct smm_state {
+ union {
+ struct {
+ u8 pad_000[0xf8];
+ u32 smm_base;
+ u32 smm_rev;
+ u8 pad_100[0xd0];
+ u32 eax, ecx, edx, ebx, esp, ebp, esi, edi, eip, eflags;
+ u8 pad_1f8[0x08];
+ } i32;
+ struct {
+ u8 pad_000[0xfc];
+ u32 smm_rev;
+ u32 smm_base;
+ u8 pad_104[0x6c];
+ u64 rflags, rip, r15, r14, r13, r12, r11, r10, r9, r8;
+ u64 rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax;
+ } i64;
+ };
+};
+
+struct smm_layout {
+ struct smm_state backup1;
+ struct smm_state backup2;
+ u32 backup_a20;
+ u8 stack[0x8000 - sizeof(struct smm_state)*2 - sizeof(u32)];
+ u64 codeentry;
+ u8 pad_8008[0x7df8];
+ struct smm_state cpu;
+};
+
+void VISIBLE32FLAT
+handle_smi(u16 cs)
+{
+ if (!CONFIG_USE_SMM)
+ 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
+ if (rev == SMM_REV_I32) {
+ smm->cpu.i32.smm_base = BUILD_SMM_ADDR;
+ } else if (rev == SMM_REV_I64) {
+ smm->cpu.i64.smm_base = BUILD_SMM_ADDR;
+ } else {
+ warn_internalerror();
+ return;
+ }
+ // indicate to smm_relocate_and_restore() that the SMM code was executed
+ outb(0x00, PORT_SMI_STATUS);
+
+ if (CONFIG_CALL32_SMM) {
+ // Backup current cpu state for SMM trampolining
+ struct smm_layout *newsmm = (void*)BUILD_SMM_ADDR;
+ memcpy(&newsmm->backup1, &smm->cpu, sizeof(newsmm->backup1));
+ memcpy(&newsmm->backup2, &smm->cpu, sizeof(newsmm->backup2));
+ HaveSmmCall32 = 1;
+ }
+
+ return;
+ }
+
+ if (CONFIG_CALL32_SMM && cmd == CALL32SMM_CMDID) {
+ if (rev == SMM_REV_I32) {
+ u32 regs[8];
+ memcpy(regs, &smm->cpu.i32.eax, sizeof(regs));
+ if (smm->cpu.i32.ecx == CALL32SMM_ENTERID) {
+ dprintf(9, "smm cpu call pc=%x esp=%x\n", regs[3], regs[4]);
+ memcpy(&smm->backup2, &smm->cpu, sizeof(smm->backup2));
+ memcpy(&smm->cpu, &smm->backup1, sizeof(smm->cpu));
+ memcpy(&smm->cpu.i32.eax, regs, sizeof(regs));
+ smm->cpu.i32.eip = regs[3];
+ // Enable a20 and backup its previous state
+ smm->backup_a20 = set_a20(1);
+ } else if (smm->cpu.i32.ecx == CALL32SMM_RETURNID) {
+ dprintf(9, "smm cpu ret %x esp=%x\n", regs[3], regs[4]);
+ memcpy(&smm->cpu, &smm->backup2, sizeof(smm->cpu));
+ memcpy(&smm->cpu.i32.eax, regs, sizeof(regs));
+ if (!smm->backup_a20)
+ set_a20(0);
+ smm->cpu.i32.eip = regs[3];
+ }
+ } 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) {
+ memcpy(&smm->backup2, &smm->cpu, sizeof(smm->backup2));
+ memcpy(&smm->cpu, &smm->backup1, sizeof(smm->cpu));
+ memcpy(&smm->cpu.i64.rdi, regs, sizeof(regs));
+ smm->cpu.i64.rip = (u32)regs[4];
+ // Enable a20 and backup its previous state
+ smm->backup_a20 = set_a20(1);
+ } else if ((u32)smm->cpu.i64.rcx == CALL32SMM_RETURNID) {
+ memcpy(&smm->cpu, &smm->backup2, sizeof(smm->cpu));
+ memcpy(&smm->cpu.i64.rdi, regs, sizeof(regs));
+ if (!smm->backup_a20)
+ set_a20(0);
+ smm->cpu.i64.rip = (u32)regs[4];
+ }
+ }
+ }
+}
+
+extern void entry_smi(void);
+// movw %cs, %ax; ljmpw $SEG_BIOS, $(entry_smi - BUILD_BIOS_ADDR)
+#define SMI_INSN (0xeac88c | ((u64)SEG_BIOS<<40) \
+ | ((u64)((u32)entry_smi - BUILD_BIOS_ADDR) << 24))
+
+static void
+smm_save_and_copy(void)
+{
+ // save original memory content
+ struct smm_layout *initsmm = (void*)BUILD_SMM_INIT_ADDR;
+ struct smm_layout *smm = (void*)BUILD_SMM_ADDR;
+ memcpy(&smm->cpu, &initsmm->cpu, sizeof(smm->cpu));
+ memcpy(&smm->codeentry, &initsmm->codeentry, sizeof(smm->codeentry));
+
+ // Setup code entry point.
+ initsmm->codeentry = SMI_INSN;
+}
+
+static void
+smm_relocate_and_restore(void)
+{
+ /* init APM status port */
+ outb(0x01, PORT_SMI_STATUS);
+
+ /* raise an SMI interrupt */
+ outb(0x00, PORT_SMI_CMD);
+
+ /* wait until SMM code executed */
+ while (inb(PORT_SMI_STATUS) != 0x00)
+ ;
+
+ /* restore original memory content */
+ struct smm_layout *initsmm = (void*)BUILD_SMM_INIT_ADDR;
+ struct smm_layout *smm = (void*)BUILD_SMM_ADDR;
+ memcpy(&initsmm->cpu, &smm->cpu, sizeof(initsmm->cpu));
+ memcpy(&initsmm->codeentry, &smm->codeentry, sizeof(initsmm->codeentry));
+
+ // Setup code entry point.
+ smm->codeentry = SMI_INSN;
+ wbinvd();
+}
+
+// This code is hardcoded for PIIX4 Power Management device.
+static void piix4_apmc_smm_setup(int isabdf, int i440_bdf)
+{
+ /* check if SMM init is already done */
+ u32 value = pci_config_readl(isabdf, PIIX_DEVACTB);
+ if (value & PIIX_DEVACTB_APMC_EN)
+ return;
+
+ /* enable the SMM memory window */
+ pci_config_writeb(i440_bdf, I440FX_SMRAM, 0x02 | 0x48);
+
+ smm_save_and_copy();
+
+ /* enable SMI generation when writing to the APMC register */
+ pci_config_writel(isabdf, PIIX_DEVACTB, value | PIIX_DEVACTB_APMC_EN);
+
+ /* enable SMI generation */
+ value = inl(acpi_pm_base + PIIX_PMIO_GLBCTL);
+ outl(value | PIIX_PMIO_GLBCTL_SMI_EN, acpi_pm_base + PIIX_PMIO_GLBCTL);
+
+ smm_relocate_and_restore();
+
+ /* close the SMM memory window and enable normal SMM */
+ pci_config_writeb(i440_bdf, I440FX_SMRAM, 0x02 | 0x08);
+}
+
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */
+void ich9_lpc_apmc_smm_setup(int isabdf, int mch_bdf)
+{
+ /* check if SMM init is already done */
+ u32 value = inl(acpi_pm_base + ICH9_PMIO_SMI_EN);
+ if (value & ICH9_PMIO_SMI_EN_APMC_EN)
+ return;
+
+ /* enable the SMM memory window */
+ pci_config_writeb(mch_bdf, Q35_HOST_BRIDGE_SMRAM, 0x02 | 0x48);
+
+ smm_save_and_copy();
+
+ /* enable SMI generation when writing to the APMC register */
+ outl(value | ICH9_PMIO_SMI_EN_APMC_EN | ICH9_PMIO_SMI_EN_GLB_SMI_EN,
+ acpi_pm_base + ICH9_PMIO_SMI_EN);
+
+ /* lock SMI generation */
+ value = pci_config_readw(isabdf, ICH9_LPC_GEN_PMCON_1);
+ pci_config_writel(isabdf, ICH9_LPC_GEN_PMCON_1,
+ value | ICH9_LPC_GEN_PMCON_1_SMI_LOCK);
+
+ smm_relocate_and_restore();
+
+ /* close the SMM memory window and enable normal SMM */
+ pci_config_writeb(mch_bdf, Q35_HOST_BRIDGE_SMRAM, 0x02 | 0x08);
+}
+
+static int SMMISADeviceBDF = -1, SMMPMDeviceBDF = -1;
+
+void
+smm_device_setup(void)
+{
+ if (!CONFIG_USE_SMM)
+ return;
+
+ struct pci_device *isapci, *pmpci;
+ isapci = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3);
+ pmpci = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441);
+ if (isapci && pmpci) {
+ SMMISADeviceBDF = isapci->bdf;
+ SMMPMDeviceBDF = pmpci->bdf;
+ return;
+ }
+ isapci = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC);
+ pmpci = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH);
+ if (isapci && pmpci) {
+ SMMISADeviceBDF = isapci->bdf;
+ SMMPMDeviceBDF = pmpci->bdf;
+ }
+}
+
+void
+smm_setup(void)
+{
+ if (!CONFIG_USE_SMM || SMMISADeviceBDF < 0)
+ return;
+
+ dprintf(3, "init smm\n");
+ u16 device = pci_config_readw(SMMISADeviceBDF, PCI_DEVICE_ID);
+ if (device == PCI_DEVICE_ID_INTEL_82371AB_3)
+ piix4_apmc_smm_setup(SMMISADeviceBDF, SMMPMDeviceBDF);
+ else
+ ich9_lpc_apmc_smm_setup(SMMISADeviceBDF, SMMPMDeviceBDF);
+}
diff --git a/roms/seabios-hppa/src/fw/smp.c b/roms/seabios-hppa/src/fw/smp.c
new file mode 100644
index 000000000..46d1da178
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/smp.c
@@ -0,0 +1,194 @@
+// QEMU multi-CPU initialization code
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "hw/rtc.h" // CMOS_BIOS_SMP_COUNT
+#include "output.h" // dprintf
+#include "romfile.h" // romfile_loadint
+#include "stacks.h" // yield
+#include "util.h" // smp_setup, msr_feature_control_setup
+#include "x86.h" // wrmsr
+#include "paravirt.h" // qemu_*_present_cpus_count
+
+#define APIC_ICR_LOW ((u8*)BUILD_APIC_ADDR + 0x300)
+#define APIC_SVR ((u8*)BUILD_APIC_ADDR + 0x0F0)
+#define APIC_LINT0 ((u8*)BUILD_APIC_ADDR + 0x350)
+#define APIC_LINT1 ((u8*)BUILD_APIC_ADDR + 0x360)
+
+#define APIC_ENABLED 0x0100
+#define MSR_IA32_APIC_BASE 0x01B
+#define MSR_LOCAL_APIC_ID 0x802
+#define MSR_IA32_APICBASE_EXTD (1ULL << 10) /* Enable x2APIC mode */
+
+static struct { u32 index; u64 val; } smp_msr[32];
+static u32 smp_msr_count;
+
+void
+wrmsr_smp(u32 index, u64 val)
+{
+ wrmsr(index, val);
+ if (smp_msr_count >= ARRAY_SIZE(smp_msr)) {
+ warn_noalloc();
+ return;
+ }
+ smp_msr[smp_msr_count].index = index;
+ smp_msr[smp_msr_count].val = val;
+ smp_msr_count++;
+}
+
+static void
+smp_write_msrs(void)
+{
+ // MTRR and MSR_IA32_FEATURE_CONTROL setup
+ int i;
+ for (i=0; i<smp_msr_count; i++)
+ wrmsr(smp_msr[i].index, smp_msr[i].val);
+}
+
+u32 MaxCountCPUs;
+static u32 CountCPUs;
+// 256 bits for the found APIC IDs
+static u32 FoundAPICIDs[256/32];
+
+int apic_id_is_present(u8 apic_id)
+{
+ return !!(FoundAPICIDs[apic_id/32] & (1ul << (apic_id % 32)));
+}
+
+static int
+apic_id_init(void)
+{
+ u32 eax, ebx, ecx, cpuid_features;
+ cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+ u32 apic_id = ebx>>24;
+ if (MaxCountCPUs < 256) { // xAPIC mode
+ // Track found apic id for use in legacy internal bios tables
+ FoundAPICIDs[apic_id/32] |= 1 << (apic_id % 32);
+ } else if (ecx & CPUID_X2APIC) {
+ // switch to x2APIC mode
+ u64 apic_base = rdmsr(MSR_IA32_APIC_BASE);
+ wrmsr(MSR_IA32_APIC_BASE, apic_base | MSR_IA32_APICBASE_EXTD);
+ apic_id = rdmsr(MSR_LOCAL_APIC_ID);
+ } else {
+ // x2APIC is masked by CPUID
+ apic_id = -1;
+ }
+ return apic_id;
+}
+
+void VISIBLE32FLAT
+handle_smp(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ // Track this CPU and detect the apic_id
+ int apic_id = apic_id_init();
+ dprintf(DEBUG_HDL_smp, "handle_smp: apic_id=0x%x\n", apic_id);
+
+ smp_write_msrs();
+
+ CountCPUs++;
+}
+
+// Atomic lock for shared stack across processors.
+u32 SMPLock __VISIBLE;
+u32 SMPStack __VISIBLE;
+
+// find and initialize the CPUs by launching a SIPI to them
+static void
+smp_scan(void)
+{
+ ASSERT32FLAT();
+ u32 eax, ebx, ecx, cpuid_features;
+ cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+ if (eax < 1 || !(cpuid_features & CPUID_APIC)) {
+ // No apic - only the main cpu is present.
+ dprintf(1, "No apic - only the main cpu is present.\n");
+ CountCPUs= 1;
+ return;
+ }
+
+ // mark the BSP initial APIC ID as found, too:
+ CountCPUs = 1;
+
+ // Setup jump trampoline to counter code.
+ u64 old = *(u64*)BUILD_AP_BOOT_ADDR;
+ // ljmpw $SEG_BIOS, $(entry_smp - BUILD_BIOS_ADDR)
+ extern void entry_smp(void);
+ u64 new = (0xea | ((u64)SEG_BIOS<<24)
+ | (((u32)entry_smp - BUILD_BIOS_ADDR) << 8));
+ *(u64*)BUILD_AP_BOOT_ADDR = new;
+
+ // enable local APIC
+ u32 val = readl(APIC_SVR);
+ writel(APIC_SVR, val | APIC_ENABLED);
+
+ /* Set LINT0 as Ext_INT, level triggered */
+ writel(APIC_LINT0, 0x8700);
+
+ /* Set LINT1 as NMI, level triggered */
+ writel(APIC_LINT1, 0x8400);
+
+ // Init the lock.
+ writel(&SMPLock, 1);
+
+ // broadcast SIPI
+ barrier();
+ writel(APIC_ICR_LOW, 0x000C4500);
+ u32 sipi_vector = BUILD_AP_BOOT_ADDR >> 12;
+ writel(APIC_ICR_LOW, 0x000C4600 | sipi_vector);
+
+ // switch to x2APIC mode after sending SIPI so that
+ // x2APIC and xAPIC mode could share AP wake up code
+ apic_id_init();
+
+ // Wait for other CPUs to process the SIPI.
+ u16 expected_cpus_count = qemu_get_present_cpus_count();
+ while (expected_cpus_count != CountCPUs)
+ asm volatile(
+ // Release lock and allow other processors to use the stack.
+ " movl %%esp, %1\n"
+ " movl $0, %0\n"
+ // Reacquire lock and take back ownership of stack.
+ "1:rep ; nop\n"
+ " lock btsl $0, %0\n"
+ " jc 1b\n"
+ : "+m" (SMPLock), "+m" (SMPStack)
+ : : "cc", "memory");
+ yield();
+
+ // Restore memory.
+ *(u64*)BUILD_AP_BOOT_ADDR = old;
+
+ dprintf(1, "Found %d cpu(s) max supported %d cpu(s)\n", CountCPUs,
+ MaxCountCPUs);
+}
+
+void
+smp_setup(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ MaxCountCPUs = romfile_loadint("etc/max-cpus", 0);
+ u16 smp_count = qemu_get_present_cpus_count();
+ if (MaxCountCPUs < smp_count)
+ MaxCountCPUs = smp_count;
+
+ smp_scan();
+}
+
+void
+smp_resume(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ smp_write_msrs();
+ smp_scan();
+}
diff --git a/roms/seabios-hppa/src/fw/ssdt-misc.dsl b/roms/seabios-hppa/src/fw/ssdt-misc.dsl
new file mode 100644
index 000000000..d1d2c9e34
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/ssdt-misc.dsl
@@ -0,0 +1,104 @@
+ACPI_EXTRACT_ALL_CODE ssdp_misc_aml
+
+DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSU", 0x1)
+{
+
+/****************************************************************
+ * PCI memory ranges
+ ****************************************************************/
+
+ Scope(\) {
+ ACPI_EXTRACT_NAME_DWORD_CONST acpi_pci32_start
+ Name(P0S, 0x12345678)
+ ACPI_EXTRACT_NAME_DWORD_CONST acpi_pci32_end
+ Name(P0E, 0x12345678)
+ ACPI_EXTRACT_NAME_BYTE_CONST acpi_pci64_valid
+ Name(P1V, 0x12)
+ ACPI_EXTRACT_NAME_BUFFER8 acpi_pci64_start
+ Name(P1S, Buffer() { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 })
+ ACPI_EXTRACT_NAME_BUFFER8 acpi_pci64_end
+ Name(P1E, Buffer() { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 })
+ ACPI_EXTRACT_NAME_BUFFER8 acpi_pci64_length
+ Name(P1L, Buffer() { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 })
+ }
+
+
+/****************************************************************
+ * Suspend
+ ****************************************************************/
+
+ Scope(\) {
+ /*
+ * S3 (suspend-to-ram), S4 (suspend-to-disk) and S5 (power-off) type codes:
+ * must match piix4 emulation.
+ */
+
+ ACPI_EXTRACT_NAME_STRING acpi_s3_name
+ Name(_S3, Package(0x04) {
+ One, /* PM1a_CNT.SLP_TYP */
+ One, /* PM1b_CNT.SLP_TYP */
+ Zero, /* reserved */
+ Zero /* reserved */
+ })
+ ACPI_EXTRACT_NAME_STRING acpi_s4_name
+ ACPI_EXTRACT_PKG_START acpi_s4_pkg
+ Name(_S4, Package(0x04) {
+ 0x2, /* PM1a_CNT.SLP_TYP */
+ 0x2, /* PM1b_CNT.SLP_TYP */
+ Zero, /* reserved */
+ Zero /* reserved */
+ })
+ Name(_S5, Package(0x04) {
+ Zero, /* PM1a_CNT.SLP_TYP */
+ Zero, /* PM1b_CNT.SLP_TYP */
+ Zero, /* reserved */
+ Zero /* reserved */
+ })
+ }
+
+ External(\_SB.PCI0, DeviceObj)
+ External(\_SB.PCI0.ISA, DeviceObj)
+
+ Scope(\_SB.PCI0.ISA) {
+ Device(PEVT) {
+ Name(_HID, "QEMU0001")
+ /* PEST will be patched to be Zero if no such device */
+ ACPI_EXTRACT_NAME_WORD_CONST ssdt_isa_pest
+ Name(PEST, 0xFFFF)
+ OperationRegion(PEOR, SystemIO, PEST, 0x01)
+ Field(PEOR, ByteAcc, NoLock, Preserve) {
+ PEPT, 8,
+ }
+
+ Method(_STA, 0, NotSerialized) {
+ Store(PEST, Local0)
+ If (LEqual(Local0, Zero)) {
+ Return (0x00)
+ } Else {
+ Return (0x0F)
+ }
+ }
+
+ Method(RDPT, 0, NotSerialized) {
+ Store(PEPT, Local0)
+ Return (Local0)
+ }
+
+ Method(WRPT, 1, NotSerialized) {
+ Store(Arg0, PEPT)
+ }
+
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x00, 0x00, 0x01, 0x01, IO)
+ })
+
+ CreateWordField(_CRS, IO._MIN, IOMN)
+ CreateWordField(_CRS, IO._MAX, IOMX)
+
+ Method(_INI, 0, NotSerialized) {
+ Store(PEST, IOMN)
+ Store(PEST, IOMX)
+ }
+ }
+ }
+}
diff --git a/roms/seabios-hppa/src/fw/ssdt-misc.hex b/roms/seabios-hppa/src/fw/ssdt-misc.hex
new file mode 100644
index 000000000..6eb1c6dfe
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/ssdt-misc.hex
@@ -0,0 +1,88 @@
+/* DO NOT EDIT! This is an autogenerated file. See scripts/acpi_extract.py. */
+static unsigned char acpi_pci64_length[] = {
+ 0x6f
+};
+
+static unsigned char acpi_s4_pkg[] = {
+ 0x8f
+};
+
+static unsigned char acpi_s3_name[] = {
+ 0x7c
+};
+
+static unsigned char acpi_pci32_start[] = {
+ 0x2f
+};
+
+static unsigned char acpi_pci64_valid[] = {
+ 0x43
+};
+
+static unsigned char ssdp_misc_aml[] = {
+ 0x53, 0x53, 0x44, 0x54, 0x62, 0x01, 0x00, 0x00,
+ 0x01, 0x7f, 0x42, 0x58, 0x50, 0x43, 0x00, 0x00,
+ 0x42, 0x58, 0x53, 0x53, 0x44, 0x54, 0x53, 0x55,
+ 0x01, 0x00, 0x00, 0x00, 0x49, 0x4e, 0x54, 0x4c,
+ 0x18, 0x08, 0x15, 0x20, 0x10, 0x42, 0x05, 0x5c,
+ 0x00, 0x08, 0x50, 0x30, 0x53, 0x5f, 0x0c, 0x78,
+ 0x56, 0x34, 0x12, 0x08, 0x50, 0x30, 0x45, 0x5f,
+ 0x0c, 0x78, 0x56, 0x34, 0x12, 0x08, 0x50, 0x31,
+ 0x56, 0x5f, 0x0a, 0x12, 0x08, 0x50, 0x31, 0x53,
+ 0x5f, 0x11, 0x0b, 0x0a, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x50, 0x31,
+ 0x45, 0x5f, 0x11, 0x0b, 0x0a, 0x08, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x50,
+ 0x31, 0x4c, 0x5f, 0x11, 0x0b, 0x0a, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x29, 0x5c, 0x00, 0x08, 0x5f, 0x53, 0x33, 0x5f,
+ 0x12, 0x06, 0x04, 0x01, 0x01, 0x00, 0x00, 0x08,
+ 0x5f, 0x53, 0x34, 0x5f, 0x12, 0x08, 0x04, 0x0a,
+ 0x02, 0x0a, 0x02, 0x00, 0x00, 0x08, 0x5f, 0x53,
+ 0x35, 0x5f, 0x12, 0x06, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x40, 0x0c, 0x5c, 0x2f, 0x03, 0x5f,
+ 0x53, 0x42, 0x5f, 0x50, 0x43, 0x49, 0x30, 0x49,
+ 0x53, 0x41, 0x5f, 0x5b, 0x82, 0x4d, 0x0a, 0x50,
+ 0x45, 0x56, 0x54, 0x08, 0x5f, 0x48, 0x49, 0x44,
+ 0x0d, 0x51, 0x45, 0x4d, 0x55, 0x30, 0x30, 0x30,
+ 0x31, 0x00, 0x08, 0x50, 0x45, 0x53, 0x54, 0x0b,
+ 0xff, 0xff, 0x5b, 0x80, 0x50, 0x45, 0x4f, 0x52,
+ 0x01, 0x50, 0x45, 0x53, 0x54, 0x01, 0x5b, 0x81,
+ 0x0b, 0x50, 0x45, 0x4f, 0x52, 0x01, 0x50, 0x45,
+ 0x50, 0x54, 0x08, 0x14, 0x18, 0x5f, 0x53, 0x54,
+ 0x41, 0x00, 0x70, 0x50, 0x45, 0x53, 0x54, 0x60,
+ 0xa0, 0x06, 0x93, 0x60, 0x00, 0xa4, 0x00, 0xa1,
+ 0x04, 0xa4, 0x0a, 0x0f, 0x14, 0x0e, 0x52, 0x44,
+ 0x50, 0x54, 0x00, 0x70, 0x50, 0x45, 0x50, 0x54,
+ 0x60, 0xa4, 0x60, 0x14, 0x0c, 0x57, 0x52, 0x50,
+ 0x54, 0x01, 0x70, 0x68, 0x50, 0x45, 0x50, 0x54,
+ 0x08, 0x5f, 0x43, 0x52, 0x53, 0x11, 0x0d, 0x0a,
+ 0x0a, 0x47, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x79, 0x00, 0x8b, 0x5f, 0x43, 0x52, 0x53,
+ 0x0a, 0x02, 0x49, 0x4f, 0x4d, 0x4e, 0x8b, 0x5f,
+ 0x43, 0x52, 0x53, 0x0a, 0x04, 0x49, 0x4f, 0x4d,
+ 0x58, 0x14, 0x18, 0x5f, 0x49, 0x4e, 0x49, 0x00,
+ 0x70, 0x50, 0x45, 0x53, 0x54, 0x49, 0x4f, 0x4d,
+ 0x4e, 0x70, 0x50, 0x45, 0x53, 0x54, 0x49, 0x4f,
+ 0x4d, 0x58
+};
+
+static unsigned char ssdt_isa_pest[] = {
+ 0xd0
+};
+
+static unsigned char acpi_s4_name[] = {
+ 0x88
+};
+
+static unsigned char acpi_pci64_start[] = {
+ 0x4d
+};
+
+static unsigned char acpi_pci64_end[] = {
+ 0x5e
+};
+
+static unsigned char acpi_pci32_end[] = {
+ 0x39
+};
diff --git a/roms/seabios-hppa/src/fw/ssdt-pcihp.dsl b/roms/seabios-hppa/src/fw/ssdt-pcihp.dsl
new file mode 100644
index 000000000..518a5ebfb
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/ssdt-pcihp.dsl
@@ -0,0 +1,36 @@
+ACPI_EXTRACT_ALL_CODE ssdp_pcihp_aml
+
+DefinitionBlock ("ssdt-pcihp.aml", "SSDT", 0x01, "BXPC", "BXSSDTPC", 0x1)
+{
+
+/****************************************************************
+ * PCI hotplug
+ ****************************************************************/
+
+ /* Objects supplied by DSDT */
+ External(\_SB.PCI0, DeviceObj)
+ External(\_SB.PCI0.PCEJ, MethodObj)
+
+ Scope(\_SB.PCI0) {
+
+ /* Bulk generated PCI hotplug devices */
+ ACPI_EXTRACT_DEVICE_START ssdt_pcihp_start
+ ACPI_EXTRACT_DEVICE_END ssdt_pcihp_end
+ ACPI_EXTRACT_DEVICE_STRING ssdt_pcihp_name
+
+ // Method _EJ0 can be patched by BIOS to EJ0_
+ // at runtime, if the slot is detected to not support hotplug.
+ // Extract the offset of the address dword and the
+ // _EJ0 name to allow this patching.
+ Device(SAA) {
+ ACPI_EXTRACT_NAME_BYTE_CONST ssdt_pcihp_id
+ Name(_SUN, 0xAA)
+ ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pcihp_adr
+ Name(_ADR, 0xAA0000)
+ ACPI_EXTRACT_METHOD_STRING ssdt_pcihp_ej0
+ Method(_EJ0, 1) {
+ PCEJ(_SUN)
+ }
+ }
+ }
+}
diff --git a/roms/seabios-hppa/src/fw/ssdt-pcihp.hex b/roms/seabios-hppa/src/fw/ssdt-pcihp.hex
new file mode 100644
index 000000000..79b67f7a4
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/ssdt-pcihp.hex
@@ -0,0 +1,38 @@
+/* DO NOT EDIT! This is an autogenerated file. See scripts/acpi_extract.py. */
+static unsigned char ssdt_pcihp_name[] = {
+ 0x33
+};
+
+static unsigned char ssdt_pcihp_adr[] = {
+ 0x44
+};
+
+static unsigned char ssdt_pcihp_end[] = {
+ 0x57
+};
+
+static unsigned char ssdp_pcihp_aml[] = {
+ 0x53, 0x53, 0x44, 0x54, 0x57, 0x00, 0x00, 0x00,
+ 0x01, 0x27, 0x42, 0x58, 0x50, 0x43, 0x00, 0x00,
+ 0x42, 0x58, 0x53, 0x53, 0x44, 0x54, 0x50, 0x43,
+ 0x01, 0x00, 0x00, 0x00, 0x49, 0x4e, 0x54, 0x4c,
+ 0x18, 0x08, 0x15, 0x20, 0x10, 0x32, 0x5c, 0x2e,
+ 0x5f, 0x53, 0x42, 0x5f, 0x50, 0x43, 0x49, 0x30,
+ 0x5b, 0x82, 0x25, 0x53, 0x41, 0x41, 0x5f, 0x08,
+ 0x5f, 0x53, 0x55, 0x4e, 0x0a, 0xaa, 0x08, 0x5f,
+ 0x41, 0x44, 0x52, 0x0c, 0x00, 0x00, 0xaa, 0x00,
+ 0x14, 0x0e, 0x5f, 0x45, 0x4a, 0x30, 0x01, 0x50,
+ 0x43, 0x45, 0x4a, 0x5f, 0x53, 0x55, 0x4e
+};
+
+static unsigned char ssdt_pcihp_start[] = {
+ 0x30
+};
+
+static unsigned char ssdt_pcihp_id[] = {
+ 0x3d
+};
+
+static unsigned char ssdt_pcihp_ej0[] = {
+ 0x4a
+};
diff --git a/roms/seabios-hppa/src/fw/ssdt-proc.dsl b/roms/seabios-hppa/src/fw/ssdt-proc.dsl
new file mode 100644
index 000000000..407d61ead
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/ssdt-proc.dsl
@@ -0,0 +1,48 @@
+/* This file is the basis for the ssdt table generated in src/acpi.c.
+ * It defines the contents of the per-cpu Processor() object. At
+ * runtime, a dynamically generated SSDT will contain one copy of this
+ * AML snippet for every possible cpu in the system. The objects will
+ * be placed in the \_SB_ namespace.
+ *
+ * In addition to the aml code generated from this file, the
+ * src/acpi.c file creates a NTFY method with an entry for each cpu:
+ * Method(NTFY, 2) {
+ * If (LEqual(Arg0, 0x00)) { Notify(CP00, Arg1) }
+ * If (LEqual(Arg0, 0x01)) { Notify(CP01, Arg1) }
+ * ...
+ * }
+ * and a CPON array with the list of active and inactive cpus:
+ * Name(CPON, Package() { One, One, ..., Zero, Zero, ... })
+ */
+
+ACPI_EXTRACT_ALL_CODE ssdp_proc_aml
+
+DefinitionBlock ("ssdt-proc.aml", "SSDT", 0x01, "BXPC", "BXSSDT", 0x1)
+{
+ ACPI_EXTRACT_PROCESSOR_START ssdt_proc_start
+ ACPI_EXTRACT_PROCESSOR_END ssdt_proc_end
+ ACPI_EXTRACT_PROCESSOR_STRING ssdt_proc_name
+ Processor(CPAA, 0xAA, 0x0000b010, 0x06) {
+ ACPI_EXTRACT_NAME_BYTE_CONST ssdt_proc_id
+ Name(ID, 0xAA)
+/*
+ * The src/acpi.c code requires the above ACP_EXTRACT tags so that it can update
+ * CPAA and 0xAA with the appropriate CPU id (see
+ * SD_OFFSET_CPUHEX/CPUID1/CPUID2). Don't change the above without
+ * also updating the C code.
+ */
+ Name(_HID, "ACPI0007")
+ External(CPMA, MethodObj)
+ External(CPST, MethodObj)
+ External(CPEJ, MethodObj)
+ Method(_MAT, 0) {
+ Return (CPMA(ID))
+ }
+ Method(_STA, 0) {
+ Return (CPST(ID))
+ }
+ Method(_EJ0, 1, NotSerialized) {
+ CPEJ(ID, Arg0)
+ }
+ }
+}
diff --git a/roms/seabios-hppa/src/fw/ssdt-proc.hex b/roms/seabios-hppa/src/fw/ssdt-proc.hex
new file mode 100644
index 000000000..b6a57784f
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/ssdt-proc.hex
@@ -0,0 +1,35 @@
+/* DO NOT EDIT! This is an autogenerated file. See scripts/acpi_extract.py. */
+static unsigned char ssdt_proc_name[] = {
+ 0x28
+};
+
+static unsigned char ssdp_proc_aml[] = {
+ 0x53, 0x53, 0x44, 0x54, 0x78, 0x00, 0x00, 0x00,
+ 0x01, 0xbb, 0x42, 0x58, 0x50, 0x43, 0x00, 0x00,
+ 0x42, 0x58, 0x53, 0x53, 0x44, 0x54, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x49, 0x4e, 0x54, 0x4c,
+ 0x18, 0x08, 0x15, 0x20, 0x5b, 0x83, 0x42, 0x05,
+ 0x43, 0x50, 0x41, 0x41, 0xaa, 0x10, 0xb0, 0x00,
+ 0x00, 0x06, 0x08, 0x49, 0x44, 0x5f, 0x5f, 0x0a,
+ 0xaa, 0x08, 0x5f, 0x48, 0x49, 0x44, 0x0d, 0x41,
+ 0x43, 0x50, 0x49, 0x30, 0x30, 0x30, 0x37, 0x00,
+ 0x14, 0x0f, 0x5f, 0x4d, 0x41, 0x54, 0x00, 0xa4,
+ 0x43, 0x50, 0x4d, 0x41, 0x49, 0x44, 0x5f, 0x5f,
+ 0x14, 0x0f, 0x5f, 0x53, 0x54, 0x41, 0x00, 0xa4,
+ 0x43, 0x50, 0x53, 0x54, 0x49, 0x44, 0x5f, 0x5f,
+ 0x14, 0x0f, 0x5f, 0x45, 0x4a, 0x30, 0x01, 0x43,
+ 0x50, 0x45, 0x4a, 0x49, 0x44, 0x5f, 0x5f, 0x68,
+
+};
+
+static unsigned char ssdt_proc_id[] = {
+ 0x38
+};
+
+static unsigned char ssdt_proc_end[] = {
+ 0x78
+};
+
+static unsigned char ssdt_proc_start[] = {
+ 0x24
+};
diff --git a/roms/seabios-hppa/src/fw/xen.c b/roms/seabios-hppa/src/fw/xen.c
new file mode 100644
index 000000000..a215b9ea9
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/xen.c
@@ -0,0 +1,149 @@
+// Xen HVM support
+//
+// Copyright (C) 2011 Citrix Systems.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_XEN
+#include "e820map.h" // e820_add
+#include "hw/serialio.h" // DebugOutputPort
+#include "malloc.h" // memalign_high
+#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" // xen_extraversion_t
+
+#define INFO_PHYSICAL_ADDRESS 0x00001000
+
+u32 xen_cpuid_base = 0;
+unsigned long xen_hypercall_page = 0;
+
+struct xen_seabios_info {
+ char signature[14]; /* XenHVMSeaBIOS\0 */
+ u8 length; /* Length of this struct */
+ u8 checksum; /* Set such that the sum over bytes 0..length == 0 */
+ /*
+ * Physical address of an array of tables_nr elements.
+ *
+ * Each element is a 32 bit value contianing the physical address
+ * of a BIOS table.
+ */
+ u32 tables;
+ u32 tables_nr;
+ /*
+ * Physical address of the e820 table, contains e820_nr entries.
+ */
+ u32 e820;
+ u32 e820_nr;
+} PACKED;
+
+static void validate_info(struct xen_seabios_info *t)
+{
+ if ( memcmp(t->signature, "XenHVMSeaBIOS", 14) )
+ panic("Bad Xen info signature\n");
+
+ if ( t->length < sizeof(struct xen_seabios_info) )
+ panic("Bad Xen info length\n");
+
+ if (checksum(t, t->length) != 0)
+ panic("Bad Xen info checksum\n");
+}
+
+void xen_preinit(void)
+{
+ u32 base, eax, ebx, ecx, edx;
+ char signature[13];
+
+ if (!CONFIG_XEN)
+ return;
+
+ for (base = 0x40000000; base < 0x40010000; base += 0x100) {
+ cpuid(base, &eax, &ebx, &ecx, &edx);
+ memcpy(signature + 0, &ebx, 4);
+ memcpy(signature + 4, &ecx, 4);
+ memcpy(signature + 8, &edx, 4);
+ signature[12] = 0;
+
+ dprintf(9, "Found hypervisor signature \"%s\" at %x\n",
+ signature, base);
+ if (strcmp(signature, "XenVMMXenVMM") == 0) {
+ /* Set debug_io_port first, so the following messages work. */
+ code_mutable_preinit();
+ DebugOutputPort = 0xe9;
+ debug_banner();
+ dprintf(1, "\nFound Xen hypervisor signature at %x\n", base);
+ if ((eax - base) < 2)
+ panic("Insufficient Xen cpuid leaves. eax=%x at base %x\n",
+ eax, base);
+ xen_cpuid_base = base;
+ break;
+ }
+ }
+ if (!xen_cpuid_base) {
+ dprintf(1, "No Xen hypervisor found.\n");
+ return;
+ }
+ PlatformRunningOn = PF_QEMU|PF_XEN;
+}
+
+static int hypercall_xen_version( int cmd, void *arg)
+{
+ return _hypercall2(int, xen_version, cmd, arg);
+}
+
+/* Fill in hypercall transfer pages. */
+void xen_hypercall_setup(void)
+{
+ u32 eax, ebx, ecx, edx;
+ xen_extraversion_t extraversion;
+ unsigned long i;
+
+ if (!runningOnXen())
+ return;
+
+ cpuid(xen_cpuid_base + 2, &eax, &ebx, &ecx, &edx);
+
+ xen_hypercall_page = (unsigned long)memalign_high(PAGE_SIZE, eax*PAGE_SIZE);
+ if (!xen_hypercall_page)
+ panic("unable to allocate Xen hypercall page\n");
+
+ dprintf(1, "Allocated Xen hypercall page at %lx\n", xen_hypercall_page);
+ for ( i = 0; i < eax; i++ )
+ wrmsr(ebx, xen_hypercall_page + (i << 12) + i);
+
+ /* Print version information. */
+ cpuid(xen_cpuid_base + 1, &eax, &ebx, &ecx, &edx);
+ hypercall_xen_version(XENVER_extraversion, extraversion);
+ dprintf(1, "Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
+}
+
+void xen_biostable_setup(void)
+{
+ struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS;
+ void **tables = (void*)info->tables;
+ int i;
+
+ dprintf(1, "xen: copy BIOS tables...\n");
+ for (i=0; i<info->tables_nr; i++)
+ copy_table(tables[i]);
+
+ find_acpi_features();
+}
+
+void xen_ramsize_preinit(void)
+{
+ int i;
+ struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS;
+ struct e820entry *e820 = (struct e820entry *)info->e820;
+ validate_info(info);
+
+ dprintf(1, "xen: copy e820...\n");
+
+ for (i = 0; i < info->e820_nr; i++) {
+ struct e820entry *e = &e820[i];
+ e820_add(e->start, e->size, e->type);
+ }
+}
diff --git a/roms/seabios-hppa/src/fw/xen.h b/roms/seabios-hppa/src/fw/xen.h
new file mode 100644
index 000000000..f00f8407d
--- /dev/null
+++ b/roms/seabios-hppa/src/fw/xen.h
@@ -0,0 +1,125 @@
+#ifndef __XEN_H
+#define __XEN_H
+
+void xen_preinit(void);
+void xen_ramsize_preinit(void);
+void xen_hypercall_setup(void);
+void xen_biostable_setup(void);
+
+extern unsigned long xen_hypercall_page;
+
+#define _hypercall0(type, name) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res) \
+ : "0" (__hentry) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall1(type, name, a1) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1) \
+ : "0" (__hentry), "1" ((long)(a1)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall2(type, name, a1, a2) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall3(type, name, a1, a2, a3) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2, __ign3; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall4(type, name, a1, a2, a3, a4) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2, __ign3, __ign4; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)), \
+ "5" ((long)(a5)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+/******************************************************************************
+ *
+ * The following interface definitions are taken from Xen and have the
+ * following license:
+ *
+ * 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 THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* xen.h */
+
+#define __HYPERVISOR_xen_version 17
+
+/* version.h */
+
+/* arg == xen_extraversion_t. */
+#define XENVER_extraversion 1
+typedef char xen_extraversion_t[16];
+#define XEN_EXTRAVERSION_LEN (sizeof(xen_extraversion_t))
+
+#endif
diff --git a/roms/seabios-hppa/src/gen-defs.h b/roms/seabios-hppa/src/gen-defs.h
new file mode 100644
index 000000000..dabf64cd9
--- /dev/null
+++ b/roms/seabios-hppa/src/gen-defs.h
@@ -0,0 +1,19 @@
+// Tool for building defintions accessible from assembler code. This
+// is based on code from the Linux Kernel.
+#ifndef __GEN_DEFS_H
+#define __GEN_DEFS_H
+
+
+#define DEFINE(sym, val) \
+ asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() \
+ asm volatile("\n->" : : )
+
+#define OFFSET(sym, str, mem) \
+ DEFINE(sym, offsetof(struct str, mem))
+
+#define COMMENT(x) \
+ asm volatile("\n->#" x)
+
+#endif // gen-defs.h
diff --git a/roms/seabios-hppa/src/hw/ahci.c b/roms/seabios-hppa/src/hw/ahci.c
new file mode 100644
index 000000000..d45b4307e
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/ahci.c
@@ -0,0 +1,699 @@
+// Low level AHCI disk access
+//
+// Copyright (C) 2010 Gerd Hoffmann <kraxel@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "ahci.h" // CDB_CMD_READ_10
+#include "ata.h" // ATA_CB_STAT
+#include "biosvar.h" // GET_GLOBAL
+#include "blockcmd.h" // CDB_CMD_READ_10
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "pci.h" // pci_config_readb
+#include "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER
+#include "pci_regs.h" // PCI_INTERRUPT_LINE
+#include "stacks.h" // yield
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // timer_calc
+#include "x86.h" // inb
+
+#define AHCI_REQUEST_TIMEOUT 32000 // 32 seconds max for IDE ops
+#define AHCI_RESET_TIMEOUT 500 // 500 miliseconds
+#define AHCI_LINK_TIMEOUT 10 // 10 miliseconds
+
+// prepare sata command fis
+static void sata_prep_simple(struct sata_cmd_fis *fis, u8 command)
+{
+ memset_fl(fis, 0, sizeof(*fis));
+ fis->command = command;
+}
+
+static void sata_prep_readwrite(struct sata_cmd_fis *fis,
+ struct disk_op_s *op, int iswrite)
+{
+ u64 lba = op->lba;
+ u8 command;
+
+ memset_fl(fis, 0, sizeof(*fis));
+
+ if (op->count >= (1<<8) || lba + op->count >= (1<<28)) {
+ fis->sector_count2 = op->count >> 8;
+ fis->lba_low2 = lba >> 24;
+ fis->lba_mid2 = lba >> 32;
+ fis->lba_high2 = lba >> 40;
+ lba &= 0xffffff;
+ command = (iswrite ? ATA_CMD_WRITE_DMA_EXT
+ : ATA_CMD_READ_DMA_EXT);
+ } else {
+ command = (iswrite ? ATA_CMD_WRITE_DMA
+ : ATA_CMD_READ_DMA);
+ }
+ fis->feature = 1; /* dma */
+ fis->command = command;
+ fis->sector_count = op->count;
+ fis->lba_low = lba;
+ fis->lba_mid = lba >> 8;
+ fis->lba_high = lba >> 16;
+ fis->device = ((lba >> 24) & 0xf) | ATA_CB_DH_LBA;
+}
+
+static void sata_prep_atapi(struct sata_cmd_fis *fis, u16 blocksize)
+{
+ memset_fl(fis, 0, sizeof(*fis));
+ fis->command = ATA_CMD_PACKET;
+ fis->feature = 1; /* dma */
+ fis->lba_mid = blocksize;
+ fis->lba_high = blocksize >> 8;
+}
+
+// ahci register access helpers
+static u32 ahci_ctrl_readl(struct ahci_ctrl_s *ctrl, u32 reg)
+{
+ return readl(ctrl->iobase + reg);
+}
+
+static void ahci_ctrl_writel(struct ahci_ctrl_s *ctrl, u32 reg, u32 val)
+{
+ writel(ctrl->iobase + reg, val);
+}
+
+static u32 ahci_port_to_ctrl(u32 pnr, u32 port_reg)
+{
+ u32 ctrl_reg = 0x100;
+ ctrl_reg += pnr * 0x80;
+ ctrl_reg += port_reg;
+ return ctrl_reg;
+}
+
+static u32 ahci_port_readl(struct ahci_ctrl_s *ctrl, u32 pnr, u32 reg)
+{
+ u32 ctrl_reg = ahci_port_to_ctrl(pnr, reg);
+ return ahci_ctrl_readl(ctrl, ctrl_reg);
+}
+
+static void ahci_port_writel(struct ahci_ctrl_s *ctrl, u32 pnr, u32 reg, u32 val)
+{
+ u32 ctrl_reg = ahci_port_to_ctrl(pnr, reg);
+ ahci_ctrl_writel(ctrl, ctrl_reg, val);
+}
+
+// submit ahci command + wait for result
+static int ahci_command(struct ahci_port_s *port_gf, int iswrite, int isatapi,
+ void *buffer, u32 bsize)
+{
+ u32 val, status, success, flags, intbits, error;
+ struct ahci_ctrl_s *ctrl = port_gf->ctrl;
+ struct ahci_cmd_s *cmd = port_gf->cmd;
+ struct ahci_fis_s *fis = port_gf->fis;
+ struct ahci_list_s *list = port_gf->list;
+ u32 pnr = port_gf->pnr;
+
+ cmd->fis.reg = 0x27;
+ cmd->fis.pmp_type = 1 << 7; /* cmd fis */
+ cmd->prdt[0].base = (u32)buffer;
+ cmd->prdt[0].baseu = 0;
+ cmd->prdt[0].flags = bsize-1;
+
+ flags = ((1 << 16) | /* one prd entry */
+ (iswrite ? (1 << 6) : 0) |
+ (isatapi ? (1 << 5) : 0) |
+ (5 << 0)); /* fis length (dwords) */
+ list[0].flags = flags;
+ list[0].bytes = 0;
+ list[0].base = (u32)(cmd);
+ list[0].baseu = 0;
+
+ dprintf(8, "AHCI/%d: send cmd ...\n", pnr);
+ intbits = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
+ if (intbits)
+ ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, intbits);
+ ahci_port_writel(ctrl, pnr, PORT_CMD_ISSUE, 1);
+
+ u32 end = timer_calc(AHCI_REQUEST_TIMEOUT);
+ do {
+ for (;;) {
+ intbits = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
+ if (intbits) {
+ ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, intbits);
+ if (intbits & 0x02) {
+ status = GET_LOWFLAT(fis->psfis[2]);
+ error = GET_LOWFLAT(fis->psfis[3]);
+ break;
+ }
+ if (intbits & 0x01) {
+ status = GET_LOWFLAT(fis->rfis[2]);
+ error = GET_LOWFLAT(fis->rfis[3]);
+ break;
+ }
+ }
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+ dprintf(8, "AHCI/%d: ... intbits 0x%x, status 0x%x ...\n",
+ pnr, intbits, status);
+ } while (status & ATA_CB_STAT_BSY);
+
+ success = (0x00 == (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DF |
+ ATA_CB_STAT_ERR)) &&
+ ATA_CB_STAT_RDY == (status & (ATA_CB_STAT_RDY)));
+ if (success) {
+ dprintf(8, "AHCI/%d: ... finished, status 0x%x, OK\n", pnr,
+ status);
+ } else {
+ dprintf(2, "AHCI/%d: ... finished, status 0x%x, ERROR 0x%x\n", pnr,
+ status, error);
+
+ // non-queued error recovery (AHCI 1.3 section 6.2.2.1)
+ // Clears PxCMD.ST to 0 to reset the PxCI register
+ val = ahci_port_readl(ctrl, pnr, PORT_CMD);
+ ahci_port_writel(ctrl, pnr, PORT_CMD, val & ~PORT_CMD_START);
+
+ // waits for PxCMD.CR to clear to 0
+ while (1) {
+ val = ahci_port_readl(ctrl, pnr, PORT_CMD);
+ if ((val & PORT_CMD_LIST_ON) == 0)
+ break;
+ yield();
+ }
+
+ // Clears any error bits in PxSERR to enable capturing new errors
+ val = ahci_port_readl(ctrl, pnr, PORT_SCR_ERR);
+ ahci_port_writel(ctrl, pnr, PORT_SCR_ERR, val);
+
+ // Clears status bits in PxIS as appropriate
+ val = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
+ ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, val);
+
+ // If PxTFD.STS.BSY or PxTFD.STS.DRQ is set to 1, issue
+ // a COMRESET to the device to put it in an idle state
+ val = ahci_port_readl(ctrl, pnr, PORT_TFDATA);
+ if (val & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ)) {
+ dprintf(2, "AHCI/%d: issue comreset\n", pnr);
+ val = ahci_port_readl(ctrl, pnr, PORT_SCR_CTL);
+ // set Device Detection Initialization (DET) to 1 for 1 ms for comreset
+ ahci_port_writel(ctrl, pnr, PORT_SCR_CTL, val | 1);
+ mdelay (1);
+ ahci_port_writel(ctrl, pnr, PORT_SCR_CTL, val);
+ }
+
+ // Sets PxCMD.ST to 1 to enable issuing new commands
+ val = ahci_port_readl(ctrl, pnr, PORT_CMD);
+ ahci_port_writel(ctrl, pnr, PORT_CMD, val | PORT_CMD_START);
+ }
+ return success ? 0 : -1;
+}
+
+#define CDROM_CDB_SIZE 12
+
+int ahci_atapi_process_op(struct disk_op_s *op)
+{
+ if (! CONFIG_AHCI)
+ return 0;
+
+ struct ahci_port_s *port_gf = container_of(
+ op->drive_fl, struct ahci_port_s, drive);
+ struct ahci_cmd_s *cmd = port_gf->cmd;
+
+ 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);
+ 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;
+}
+
+// read/write count blocks from a harddrive, op->buf_fl must be word aligned
+static int
+ahci_disk_readwrite_aligned(struct disk_op_s *op, int iswrite)
+{
+ struct ahci_port_s *port_gf = container_of(
+ op->drive_fl, struct ahci_port_s, drive);
+ struct ahci_cmd_s *cmd = port_gf->cmd;
+ int rc;
+
+ sata_prep_readwrite(&cmd->fis, op, iswrite);
+ rc = ahci_command(port_gf, iswrite, 0, op->buf_fl,
+ op->count * DISK_SECTOR_SIZE);
+ dprintf(8, "ahci disk %s, lba %6x, count %3x, buf %p, rc %d\n",
+ iswrite ? "write" : "read", (u32)op->lba, op->count, op->buf_fl, rc);
+ if (rc < 0)
+ return DISK_RET_EBADTRACK;
+ return DISK_RET_SUCCESS;
+}
+
+// read/write count blocks from a harddrive.
+static int
+ahci_disk_readwrite(struct disk_op_s *op, int iswrite)
+{
+ // if caller's buffer is word aligned, use it directly
+ if (((u32) op->buf_fl & 1) == 0)
+ return ahci_disk_readwrite_aligned(op, iswrite);
+
+ // Use a word aligned buffer for AHCI I/O
+ int rc;
+ struct disk_op_s localop = *op;
+ u8 *alignedbuf_fl = bounce_buf_fl;
+ u8 *position = op->buf_fl;
+
+ localop.buf_fl = alignedbuf_fl;
+ localop.count = 1;
+
+ if (iswrite) {
+ u16 block;
+ for (block = 0; block < op->count; block++) {
+ memcpy_fl (alignedbuf_fl, position, DISK_SECTOR_SIZE);
+ rc = ahci_disk_readwrite_aligned (&localop, 1);
+ if (rc)
+ return rc;
+ position += DISK_SECTOR_SIZE;
+ localop.lba++;
+ }
+ } else { // read
+ u16 block;
+ for (block = 0; block < op->count; block++) {
+ rc = ahci_disk_readwrite_aligned (&localop, 0);
+ if (rc)
+ return rc;
+ memcpy_fl (position, alignedbuf_fl, DISK_SECTOR_SIZE);
+ position += DISK_SECTOR_SIZE;
+ localop.lba++;
+ }
+ }
+ return DISK_RET_SUCCESS;
+}
+
+// command demuxer
+int
+ahci_process_op(struct disk_op_s *op)
+{
+ if (!CONFIG_AHCI)
+ return 0;
+ switch (op->command) {
+ case CMD_READ:
+ return ahci_disk_readwrite(op, 0);
+ case CMD_WRITE:
+ return ahci_disk_readwrite(op, 1);
+ default:
+ return default_process_op(op);
+ }
+}
+
+static void
+ahci_port_reset(struct ahci_ctrl_s *ctrl, u32 pnr)
+{
+ u32 val;
+
+ /* disable FIS + CMD */
+ u32 end = timer_calc(AHCI_RESET_TIMEOUT);
+ for (;;) {
+ val = ahci_port_readl(ctrl, pnr, PORT_CMD);
+ if (!(val & (PORT_CMD_FIS_RX | PORT_CMD_START |
+ PORT_CMD_FIS_ON | PORT_CMD_LIST_ON)))
+ break;
+ val &= ~(PORT_CMD_FIS_RX | PORT_CMD_START);
+ ahci_port_writel(ctrl, pnr, PORT_CMD, val);
+ if (timer_check(end)) {
+ warn_timeout();
+ break;
+ }
+ yield();
+ }
+
+ /* disable + clear IRQs */
+ ahci_port_writel(ctrl, pnr, PORT_IRQ_MASK, 0);
+ val = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
+ if (val)
+ ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, val);
+}
+
+static struct ahci_port_s*
+ahci_port_alloc(struct ahci_ctrl_s *ctrl, u32 pnr)
+{
+ struct ahci_port_s *port = malloc_tmp(sizeof(*port));
+
+ if (!port) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(port, 0, sizeof(*port));
+ port->pnr = pnr;
+ port->ctrl = ctrl;
+ port->list = memalign_tmp(1024, 1024);
+ port->fis = memalign_tmp(256, 256);
+ port->cmd = memalign_tmp(256, 256);
+ if (port->list == NULL || port->fis == NULL || port->cmd == NULL) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(port->list, 0, 1024);
+ memset(port->fis, 0, 256);
+ memset(port->cmd, 0, 256);
+
+ ahci_port_writel(ctrl, pnr, PORT_LST_ADDR, (u32)port->list);
+ ahci_port_writel(ctrl, pnr, PORT_FIS_ADDR, (u32)port->fis);
+ if (ctrl->caps & HOST_CAP_64) {
+ ahci_port_writel(ctrl, pnr, PORT_LST_ADDR_HI, 0);
+ ahci_port_writel(ctrl, pnr, PORT_FIS_ADDR_HI, 0);
+ }
+
+ return port;
+}
+
+static void ahci_port_release(struct ahci_port_s *port)
+{
+ ahci_port_reset(port->ctrl, port->pnr);
+ free(port->list);
+ free(port->fis);
+ free(port->cmd);
+ free(port);
+}
+
+static struct ahci_port_s* ahci_port_realloc(struct ahci_port_s *port)
+{
+ struct ahci_port_s *tmp;
+ u32 cmd;
+
+ tmp = malloc_fseg(sizeof(*port));
+ if (!tmp) {
+ warn_noalloc();
+ ahci_port_release(port);
+ return NULL;
+ }
+ *tmp = *port;
+ free(port);
+ port = tmp;
+
+ ahci_port_reset(port->ctrl, port->pnr);
+
+ free(port->list);
+ free(port->fis);
+ free(port->cmd);
+ 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);
+
+ cmd = ahci_port_readl(port->ctrl, port->pnr, PORT_CMD);
+ cmd |= (PORT_CMD_FIS_RX|PORT_CMD_START);
+ ahci_port_writel(port->ctrl, port->pnr, PORT_CMD, cmd);
+
+ return port;
+}
+
+#define MAXMODEL 40
+
+/* See ahci spec chapter 10.1 "Software Initialization of HBA" */
+static int ahci_port_setup(struct ahci_port_s *port)
+{
+ struct ahci_ctrl_s *ctrl = port->ctrl;
+ u32 pnr = port->pnr;
+ char model[MAXMODEL+1];
+ u16 buffer[256];
+ u32 cmd, stat, err, tf;
+ int rc;
+
+ /* enable FIS recv */
+ cmd = ahci_port_readl(ctrl, pnr, PORT_CMD);
+ cmd |= PORT_CMD_FIS_RX;
+ ahci_port_writel(ctrl, pnr, PORT_CMD, cmd);
+
+ /* spin up */
+ cmd |= PORT_CMD_SPIN_UP;
+ ahci_port_writel(ctrl, pnr, PORT_CMD, cmd);
+ u32 end = timer_calc(AHCI_LINK_TIMEOUT);
+ for (;;) {
+ stat = ahci_port_readl(ctrl, pnr, PORT_SCR_STAT);
+ if ((stat & 0x07) == 0x03) {
+ dprintf(2, "AHCI/%d: link up\n", port->pnr);
+ break;
+ }
+ if (timer_check(end)) {
+ dprintf(2, "AHCI/%d: link down\n", port->pnr);
+ return -1;
+ }
+ yield();
+ }
+
+ /* clear error status */
+ err = ahci_port_readl(ctrl, pnr, PORT_SCR_ERR);
+ if (err)
+ ahci_port_writel(ctrl, pnr, PORT_SCR_ERR, err);
+
+ /* wait for device becoming ready */
+ end = timer_calc(AHCI_REQUEST_TIMEOUT);
+ for (;;) {
+ tf = ahci_port_readl(ctrl, pnr, PORT_TFDATA);
+ if (!(tf & (ATA_CB_STAT_BSY |
+ ATA_CB_STAT_DRQ)))
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ dprintf(1, "AHCI/%d: device not ready (tf 0x%x)\n", port->pnr, tf);
+ return -1;
+ }
+ yield();
+ }
+
+ /* start device */
+ cmd |= PORT_CMD_START;
+ ahci_port_writel(ctrl, pnr, PORT_CMD, cmd);
+
+ sata_prep_simple(&port->cmd->fis, ATA_CMD_IDENTIFY_PACKET_DEVICE);
+ rc = ahci_command(port, 0, 0, buffer, sizeof(buffer));
+ if (rc == 0) {
+ port->atapi = 1;
+ } else {
+ port->atapi = 0;
+ sata_prep_simple(&port->cmd->fis, ATA_CMD_IDENTIFY_DEVICE);
+ rc = ahci_command(port, 0, 0, buffer, sizeof(buffer));
+ if (rc < 0)
+ return -1;
+ }
+
+ port->drive.cntl_id = pnr;
+ port->drive.removable = (buffer[0] & 0x80) ? 1 : 0;
+
+ if (!port->atapi) {
+ // found disk (ata)
+ port->drive.type = DTYPE_AHCI;
+ port->drive.blksize = DISK_SECTOR_SIZE;
+ port->drive.pchs.cylinder = buffer[1];
+ port->drive.pchs.head = buffer[3];
+ port->drive.pchs.sector = buffer[6];
+
+ u64 sectors;
+ if (buffer[83] & (1 << 10)) // word 83 - lba48 support
+ sectors = *(u64*)&buffer[100]; // word 100-103
+ else
+ sectors = *(u32*)&buffer[60]; // word 60 and word 61
+ port->drive.sectors = sectors;
+ u64 adjsize = sectors >> 11;
+ char adjprefix = 'M';
+ if (adjsize >= (1 << 16)) {
+ adjsize >>= 10;
+ adjprefix = 'G';
+ }
+ port->desc = znprintf(MAXDESCSIZE
+ , "AHCI/%d: %s ATA-%d Hard-Disk (%u %ciBytes)"
+ , port->pnr
+ , ata_extract_model(model, MAXMODEL, buffer)
+ , ata_extract_version(buffer)
+ , (u32)adjsize, adjprefix);
+ port->prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0);
+
+ s8 multi_dma = -1;
+ s8 pio_mode = -1;
+ s8 udma_mode = -1;
+ // If bit 2 in word 53 is set, udma information is valid in word 88.
+ if (buffer[53] & 0x04) {
+ udma_mode = 6;
+ while ((udma_mode >= 0) &&
+ !((buffer[88] & 0x7f) & ( 1 << udma_mode ))) {
+ udma_mode--;
+ }
+ }
+ // If bit 1 in word 53 is set, multiword-dma and advanced pio modes
+ // are available in words 63 and 64.
+ if (buffer[53] & 0x02) {
+ pio_mode = 4;
+ multi_dma = 3;
+ while ((multi_dma >= 0) &&
+ !((buffer[63] & 0x7) & ( 1 << multi_dma ))) {
+ multi_dma--;
+ }
+ while ((pio_mode >= 3) &&
+ !((buffer[64] & 0x3) & ( 1 << ( pio_mode - 3 ) ))) {
+ pio_mode--;
+ }
+ }
+ dprintf(2, "AHCI/%d: supported modes: udma %d, multi-dma %d, pio %d\n",
+ port->pnr, udma_mode, multi_dma, pio_mode);
+
+ sata_prep_simple(&port->cmd->fis, ATA_CMD_SET_FEATURES);
+ port->cmd->fis.feature = ATA_SET_FEATRUE_TRANSFER_MODE;
+ // Select used mode. UDMA first, then Multi-DMA followed by
+ // advanced PIO modes 3 or 4. If non, set default PIO.
+ if (udma_mode >= 0) {
+ dprintf(1, "AHCI/%d: Set transfer mode to UDMA-%d\n",
+ port->pnr, udma_mode);
+ port->cmd->fis.sector_count = ATA_TRANSFER_MODE_ULTRA_DMA
+ | udma_mode;
+ } else if (multi_dma >= 0) {
+ dprintf(1, "AHCI/%d: Set transfer mode to Multi-DMA-%d\n",
+ port->pnr, multi_dma);
+ port->cmd->fis.sector_count = ATA_TRANSFER_MODE_MULTIWORD_DMA
+ | multi_dma;
+ } else if (pio_mode >= 3) {
+ dprintf(1, "AHCI/%d: Set transfer mode to PIO-%d\n",
+ port->pnr, pio_mode);
+ port->cmd->fis.sector_count = ATA_TRANSFER_MODE_PIO_FLOW_CTRL
+ | pio_mode;
+ } else {
+ dprintf(1, "AHCI/%d: Set transfer mode to default PIO\n",
+ port->pnr);
+ port->cmd->fis.sector_count = ATA_TRANSFER_MODE_DEFAULT_PIO;
+ }
+ rc = ahci_command(port, 1, 0, 0, 0);
+ if (rc < 0) {
+ dprintf(1, "AHCI/%d: Set transfer mode failed.\n", port->pnr);
+ }
+ } else {
+ // found cdrom (atapi)
+ port->drive.type = DTYPE_AHCI_ATAPI;
+ port->drive.blksize = CDROM_SECTOR_SIZE;
+ port->drive.sectors = (u64)-1;
+ u8 iscd = ((buffer[0] >> 8) & 0x1f) == 0x05;
+ if (!iscd) {
+ dprintf(1, "AHCI/%d: atapi device isn't a cdrom\n", port->pnr);
+ return -1;
+ }
+ port->desc = znprintf(MAXDESCSIZE
+ , "DVD/CD [AHCI/%d: %s ATAPI-%d DVD/CD]"
+ , port->pnr
+ , ata_extract_model(model, MAXMODEL, buffer)
+ , ata_extract_version(buffer));
+ port->prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0);
+ }
+ boot_lchs_find_ata_device(ctrl->pci_tmp, pnr, 0, &(port->drive.lchs));
+ return 0;
+}
+
+// Detect any drives attached to a given controller.
+static void
+ahci_port_detect(void *data)
+{
+ struct ahci_port_s *port = data;
+ int rc;
+
+ dprintf(2, "AHCI/%d: probing\n", port->pnr);
+ ahci_port_reset(port->ctrl, port->pnr);
+ rc = ahci_port_setup(port);
+ if (rc < 0)
+ ahci_port_release(port);
+ else {
+ port = ahci_port_realloc(port);
+ if (port == NULL)
+ return;
+ dprintf(1, "AHCI/%d: registering: \"%s\"\n", port->pnr, port->desc);
+ if (!port->atapi) {
+ // Register with bcv system.
+ boot_add_hd(&port->drive, port->desc, port->prio);
+ } else {
+ // fill cdidmap
+ boot_add_cd(&port->drive, port->desc, port->prio);
+ }
+ }
+}
+
+// Initialize an ata controller and detect its drives.
+static void
+ahci_controller_setup(struct pci_device *pci)
+{
+ struct ahci_port_s *port;
+ u32 val, pnr, max;
+
+ if (create_bounce_buf() < 0)
+ return;
+
+ void *iobase = pci_enable_membar(pci, PCI_BASE_ADDRESS_5);
+ if (!iobase)
+ return;
+
+ struct ahci_ctrl_s *ctrl = malloc_fseg(sizeof(*ctrl));
+ if (!ctrl) {
+ warn_noalloc();
+ return;
+ }
+
+ ctrl->pci_tmp = pci;
+ ctrl->iobase = iobase;
+ ctrl->irq = pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE);
+ dprintf(1, "AHCI controller at %pP, iobase %p, irq %d\n"
+ , pci, ctrl->iobase, ctrl->irq);
+
+ pci_enable_busmaster(pci);
+
+ val = ahci_ctrl_readl(ctrl, HOST_CTL);
+ ahci_ctrl_writel(ctrl, HOST_CTL, val | HOST_CTL_AHCI_EN);
+
+ ctrl->caps = ahci_ctrl_readl(ctrl, HOST_CAP);
+ ctrl->ports = ahci_ctrl_readl(ctrl, HOST_PORTS_IMPL);
+ dprintf(2, "AHCI: cap 0x%x, ports_impl 0x%x\n",
+ ctrl->caps, ctrl->ports);
+
+ max = 0x1f;
+ for (pnr = 0; pnr <= max; pnr++) {
+ if (!(ctrl->ports & (1 << pnr)))
+ continue;
+ port = ahci_port_alloc(ctrl, pnr);
+ if (port == NULL)
+ continue;
+ run_thread(ahci_port_detect, port);
+ }
+}
+
+// Locate and init ahci controllers.
+static void
+ahci_scan(void)
+{
+ // Scan PCI bus for ATA adapters
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->class != PCI_CLASS_STORAGE_SATA)
+ continue;
+ if (pci->prog_if != 1 /* AHCI rev 1 */)
+ continue;
+ ahci_controller_setup(pci);
+ }
+}
+
+void
+ahci_setup(void)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_AHCI)
+ return;
+
+ dprintf(3, "init ahci\n");
+ ahci_scan();
+}
diff --git a/roms/seabios-hppa/src/hw/ahci.h b/roms/seabios-hppa/src/hw/ahci.h
new file mode 100644
index 000000000..5c4f6e181
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/ahci.h
@@ -0,0 +1,201 @@
+#ifndef __AHCI_H
+#define __AHCI_H
+
+#include "block.h" // struct drive_s
+#include "types.h" // u32
+
+struct sata_cmd_fis {
+ u8 reg;
+ u8 pmp_type;
+ u8 command;
+ u8 feature;
+
+ u8 lba_low;
+ u8 lba_mid;
+ u8 lba_high;
+ u8 device;
+
+ u8 lba_low2;
+ u8 lba_mid2;
+ u8 lba_high2;
+ u8 feature2;
+
+ u8 sector_count;
+ u8 sector_count2;
+ u8 res_1;
+ u8 control;
+
+ u8 res_2[64 - 16];
+};
+
+struct ahci_ctrl_s {
+ struct pci_device *pci_tmp;
+ u8 irq;
+ void *iobase;
+ u32 caps;
+ u32 ports;
+};
+
+struct ahci_cmd_s {
+ struct sata_cmd_fis fis;
+ u8 atapi[0x20];
+ u8 res[0x20];
+ struct {
+ u32 base;
+ u32 baseu;
+ u32 res;
+ u32 flags;
+ } prdt[];
+};
+
+/* command list */
+struct ahci_list_s {
+ u32 flags;
+ u32 bytes;
+ u32 base;
+ u32 baseu;
+ u32 res[4];
+};
+
+struct ahci_fis_s {
+ u8 dsfis[0x1c]; /* dma setup */
+ u8 res_1[0x04];
+ u8 psfis[0x14]; /* pio setup */
+ u8 res_2[0x0c];
+ u8 rfis[0x14]; /* d2h register */
+ u8 res_3[0x04];
+ u8 sdbfis[0x08]; /* set device bits */
+ u8 ufis[0x40]; /* unknown */
+ u8 res_4[0x60];
+};
+
+struct ahci_port_s {
+ struct drive_s drive;
+ struct ahci_ctrl_s *ctrl;
+ struct ahci_list_s *list;
+ struct ahci_fis_s *fis;
+ struct ahci_cmd_s *cmd;
+ u32 pnr;
+ u32 atapi;
+ char *desc;
+ int prio;
+};
+
+void ahci_setup(void);
+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)
+#define AHCI_CMD_WRITE (1 << 6)
+#define AHCI_CMD_PREFETCH (1 << 7)
+#define AHCI_CMD_RESET (1 << 8)
+#define AHCI_CMD_CLR_BUSY (1 << 10)
+
+#define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */
+#define RX_FIS_SDB 0x58 /* offset of SDB FIS data */
+#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */
+
+/* global controller registers */
+#define HOST_CAP 0x00 /* host capabilities */
+#define HOST_CTL 0x04 /* global host control */
+#define HOST_IRQ_STAT 0x08 /* interrupt status */
+#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */
+#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */
+
+/* HOST_CTL bits */
+#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
+#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */
+#define HOST_CTL_AHCI_EN (1 << 31) /* AHCI enabled */
+
+/* HOST_CAP bits */
+#define HOST_CAP_SSC (1 << 14) /* Slumber capable */
+#define HOST_CAP_AHCI (1 << 18) /* AHCI only */
+#define HOST_CAP_CLO (1 << 24) /* Command List Override support */
+#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */
+#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */
+#define HOST_CAP_64 (1 << 31) /* PCI DAC (64-bit DMA) support */
+
+/* registers for each SATA port */
+#define PORT_LST_ADDR 0x00 /* command list DMA addr */
+#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */
+#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */
+#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */
+#define PORT_IRQ_STAT 0x10 /* interrupt status */
+#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */
+#define PORT_CMD 0x18 /* port command */
+#define PORT_TFDATA 0x20 /* taskfile data */
+#define PORT_SIG 0x24 /* device TF signature */
+#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */
+#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */
+#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */
+#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */
+#define PORT_CMD_ISSUE 0x38 /* command issue */
+#define PORT_RESERVED 0x3c /* reserved */
+
+/* PORT_IRQ_{STAT,MASK} bits */
+#define PORT_IRQ_COLD_PRES (1 << 31) /* cold presence detect */
+#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
+#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */
+#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
+#define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */
+#define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */
+#define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */
+#define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */
+
+#define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */
+#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */
+#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */
+#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */
+#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */
+#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */
+#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */
+#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */
+#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */
+
+#define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \
+ PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \
+ PORT_IRQ_UNK_FIS)
+#define PORT_IRQ_ERROR (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | \
+ PORT_IRQ_HBUS_DATA_ERR)
+#define DEF_PORT_IRQ (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | \
+ PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | \
+ PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS)
+
+/* PORT_CMD bits */
+#define PORT_CMD_ATAPI (1 << 24) /* Device is ATAPI */
+#define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */
+#define PORT_CMD_FIS_ON (1 << 14) /* FIS DMA engine running */
+#define PORT_CMD_FIS_RX (1 << 4) /* Enable FIS receive DMA engine */
+#define PORT_CMD_CLO (1 << 3) /* Command list override */
+#define PORT_CMD_POWER_ON (1 << 2) /* Power up device */
+#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */
+#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */
+
+#define PORT_CMD_ICC_MASK (0xf << 28) /* i/f ICC state mask */
+#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */
+#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */
+#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */
+
+#define PORT_IRQ_STAT_DHRS (1 << 0) /* Device to Host Register FIS */
+#define PORT_IRQ_STAT_PSS (1 << 1) /* PIO Setup FIS */
+#define PORT_IRQ_STAT_DSS (1 << 2) /* DMA Setup FIS */
+#define PORT_IRQ_STAT_SDBS (1 << 3) /* Set Device Bits */
+#define PORT_IRQ_STAT_UFS (1 << 4) /* Unknown FIS */
+#define PORT_IRQ_STAT_DPS (1 << 5) /* Descriptor Processed */
+#define PORT_IRQ_STAT_PCS (1 << 6) /* Port Connect Change Status */
+#define PORT_IRQ_STAT_DMPS (1 << 7) /* Device Mechanical Presence
+ Status */
+#define PORT_IRQ_STAT_PRCS (1 << 22) /* File Ready Status */
+#define PORT_IRQ_STAT_IPMS (1 << 23) /* Incorrect Port Multiplier
+ Status */
+#define PORT_IRQ_STAT_OFS (1 << 24) /* Overflow Status */
+#define PORT_IRQ_STAT_INFS (1 << 26) /* Interface Non-Fatal Error
+ Status */
+#define PORT_IRQ_STAT_IFS (1 << 27) /* Interface Fatal Error */
+#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */
+#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */
+#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */
+#define PORT_IRQ_STAT_CPDS (1 << 31) /* Code Port Detect Status */
+
+#endif // ahci.h
diff --git a/roms/seabios-hppa/src/hw/ata.c b/roms/seabios-hppa/src/hw/ata.c
new file mode 100644
index 000000000..56163602b
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/ata.c
@@ -0,0 +1,1054 @@
+// Low level ATA disk access
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "ata.h" // ATA_CB_STAT
+#include "biosvar.h" // GET_GLOBALFLAT
+#include "block.h" // struct drive_s
+#include "blockcmd.h" // CDB_CMD_READ_10
+#include "byteorder.h" // be16_to_cpu
+#include "malloc.h" // malloc_fseg
+#include "output.h" // dprintf
+#include "pci.h" // pci_config_readb
+#include "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER
+#include "pci_regs.h" // PCI_INTERRUPT_LINE
+#include "pic.h" // enable_hwirq
+#include "stacks.h" // yield
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // timer_calc
+#include "x86.h" // inb
+
+#define IDE_TIMEOUT 32000 //32 seconds max for IDE ops
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Wait for the specified ide state
+static inline int
+await_ide(u8 mask, u8 flags, portaddr_t base, u16 timeout)
+{
+ u32 end = timer_calc(timeout);
+ for (;;) {
+ u8 status = inb(base+ATA_CB_STAT);
+ if ((status & mask) == flags)
+ return status;
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+}
+
+// Wait for the device to be not-busy.
+static int
+await_not_bsy(portaddr_t base)
+{
+ return await_ide(ATA_CB_STAT_BSY, 0, base, IDE_TIMEOUT);
+}
+
+// Wait for the device to be ready.
+static int
+await_rdy(portaddr_t base)
+{
+ return await_ide(ATA_CB_STAT_RDY, ATA_CB_STAT_RDY, base, IDE_TIMEOUT);
+}
+
+// Wait for ide state - pauses for one ata cycle first.
+static inline int
+pause_await_not_bsy(portaddr_t iobase1, portaddr_t iobase2)
+{
+ // Wait one PIO transfer cycle.
+ inb(iobase2 + ATA_CB_ASTAT);
+
+ return await_not_bsy(iobase1);
+}
+
+// Wait for ide state - pause for 400ns first.
+static inline int
+ndelay_await_not_bsy(portaddr_t iobase1)
+{
+ ndelay(400);
+ return await_not_bsy(iobase1);
+}
+
+// Reset a drive
+static void
+ata_reset(struct atadrive_s *adrive_gf)
+{
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ u8 slave = GET_GLOBALFLAT(adrive_gf->slave);
+ portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ portaddr_t iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+
+ dprintf(6, "ata_reset drive=%p\n", &adrive_gf->drive);
+ // Pulse SRST
+ outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST, iobase2+ATA_CB_DC);
+ udelay(5);
+ outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2+ATA_CB_DC);
+ msleep(2);
+
+ // wait for device to become not busy.
+ int status = await_not_bsy(iobase1);
+ if (status < 0)
+ goto done;
+ if (slave) {
+ // Change device.
+ u32 end = timer_calc(IDE_TIMEOUT);
+ for (;;) {
+ outb(ATA_CB_DH_DEV1, iobase1 + ATA_CB_DH);
+ status = ndelay_await_not_bsy(iobase1);
+ if (status < 0)
+ goto done;
+ if (inb(iobase1 + ATA_CB_DH) == ATA_CB_DH_DEV1)
+ break;
+ // Change drive request failed to take effect - retry.
+ if (timer_check(end)) {
+ warn_timeout();
+ goto done;
+ }
+ }
+ } else {
+ // QEMU doesn't reset dh on reset, so set it explicitly.
+ outb(ATA_CB_DH_DEV0, iobase1 + ATA_CB_DH);
+ }
+
+ // On a user-reset request, wait for RDY if it is an ATA device.
+ u8 type=GET_GLOBALFLAT(adrive_gf->drive.type);
+ if (type == DTYPE_ATA)
+ status = await_rdy(iobase1);
+
+done:
+ // Enable interrupts
+ outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
+
+ dprintf(6, "ata_reset exit status=%x\n", status);
+}
+
+// Check for drive RDY for 16bit interface command.
+static int
+isready(struct atadrive_s *adrive_gf)
+{
+ // Read the status from controller
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u8 status = inb(iobase1 + ATA_CB_STAT);
+ if ((status & (ATA_CB_STAT_BSY|ATA_CB_STAT_RDY)) == ATA_CB_STAT_RDY)
+ return DISK_RET_SUCCESS;
+ return DISK_RET_ENOTREADY;
+}
+
+
+/****************************************************************
+ * ATA send command
+ ****************************************************************/
+
+struct ata_pio_command {
+ u8 feature;
+ u8 sector_count;
+ u8 lba_low;
+ u8 lba_mid;
+ u8 lba_high;
+ u8 device;
+ u8 command;
+
+ u8 feature2;
+ u8 sector_count2;
+ u8 lba_low2;
+ u8 lba_mid2;
+ u8 lba_high2;
+};
+
+// Send an ata command to the drive.
+static int
+send_cmd(struct atadrive_s *adrive_gf, struct ata_pio_command *cmd)
+{
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ u8 slave = GET_GLOBALFLAT(adrive_gf->slave);
+ portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+
+ // Select device
+ int status = await_not_bsy(iobase1);
+ if (status < 0)
+ return status;
+ u8 newdh = ((cmd->device & ~ATA_CB_DH_DEV1)
+ | (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0));
+ u8 olddh = inb(iobase1 + ATA_CB_DH);
+ outb(newdh, iobase1 + ATA_CB_DH);
+ if ((olddh ^ newdh) & (1<<4)) {
+ // Was a device change - wait for device to become not busy.
+ status = ndelay_await_not_bsy(iobase1);
+ if (status < 0)
+ return status;
+ }
+
+ // Check for ATA_CMD_(READ|WRITE)_(SECTORS|DMA)_EXT commands.
+ if ((cmd->command & ~0x11) == ATA_CMD_READ_SECTORS_EXT) {
+ outb(cmd->feature2, iobase1 + ATA_CB_FR);
+ outb(cmd->sector_count2, iobase1 + ATA_CB_SC);
+ outb(cmd->lba_low2, iobase1 + ATA_CB_SN);
+ outb(cmd->lba_mid2, iobase1 + ATA_CB_CL);
+ outb(cmd->lba_high2, iobase1 + ATA_CB_CH);
+ }
+ outb(cmd->feature, iobase1 + ATA_CB_FR);
+ outb(cmd->sector_count, iobase1 + ATA_CB_SC);
+ outb(cmd->lba_low, iobase1 + ATA_CB_SN);
+ outb(cmd->lba_mid, iobase1 + ATA_CB_CL);
+ outb(cmd->lba_high, iobase1 + ATA_CB_CH);
+ outb(cmd->command, iobase1 + ATA_CB_CMD);
+
+ return 0;
+}
+
+// Wait for data after calling 'send_cmd'.
+static int
+ata_wait_data(portaddr_t iobase1)
+{
+ int status = ndelay_await_not_bsy(iobase1);
+ if (status < 0)
+ return status;
+
+ if (status & ATA_CB_STAT_ERR) {
+ dprintf(6, "send_cmd : read error (status=%02x err=%02x)\n"
+ , status, inb(iobase1 + ATA_CB_ERR));
+ return -4;
+ }
+ if (!(status & ATA_CB_STAT_DRQ)) {
+ dprintf(6, "send_cmd : DRQ not set (status %02x)\n", status);
+ return -5;
+ }
+
+ return 0;
+}
+
+// Send an ata command that does not transfer any further data.
+int
+ata_cmd_nondata(struct atadrive_s *adrive_gf, struct ata_pio_command *cmd)
+{
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ portaddr_t iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+
+ // Disable interrupts
+ outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC);
+
+ int ret = send_cmd(adrive_gf, cmd);
+ if (ret)
+ goto fail;
+ ret = ndelay_await_not_bsy(iobase1);
+ if (ret < 0)
+ goto fail;
+
+ if (ret & ATA_CB_STAT_ERR) {
+ dprintf(6, "nondata cmd : read error (status=%02x err=%02x)\n"
+ , ret, inb(iobase1 + ATA_CB_ERR));
+ ret = -4;
+ goto fail;
+ }
+ if (ret & ATA_CB_STAT_DRQ) {
+ dprintf(6, "nondata cmd : DRQ set (status %02x)\n", ret);
+ ret = -5;
+ goto fail;
+ }
+
+fail:
+ // Enable interrupts
+ outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
+
+ return ret;
+}
+
+
+/****************************************************************
+ * ATA PIO transfers
+ ****************************************************************/
+
+// Transfer 'op->count' blocks (of 'blocksize' bytes) to/from drive
+// 'op->drive_fl'.
+static int
+ata_pio_transfer(struct disk_op_s *op, int iswrite, int blocksize)
+{
+ dprintf(16, "ata_pio_transfer id=%p write=%d count=%d bs=%d buf=%p\n"
+ , op->drive_fl, iswrite, op->count, blocksize, op->buf_fl);
+
+ struct atadrive_s *adrive_gf = container_of(
+ op->drive_fl, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ portaddr_t iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+ int count = op->count;
+ void *buf_fl = op->buf_fl;
+ int status;
+ for (;;) {
+ if (iswrite) {
+ // Write data to controller
+ dprintf(16, "Write sector id=%p dest=%p\n", op->drive_fl, buf_fl);
+ if (CONFIG_ATA_PIO32)
+ outsl_fl(iobase1, buf_fl, blocksize / 4);
+ else
+ outsw_fl(iobase1, buf_fl, blocksize / 2);
+ } else {
+ // Read data from controller
+ dprintf(16, "Read sector id=%p dest=%p\n", op->drive_fl, buf_fl);
+ if (CONFIG_ATA_PIO32)
+ insl_fl(iobase1, buf_fl, blocksize / 4);
+ else
+ insw_fl(iobase1, buf_fl, blocksize / 2);
+ }
+ buf_fl += blocksize;
+
+ status = pause_await_not_bsy(iobase1, iobase2);
+ if (status < 0) {
+ // Error
+ op->count -= count;
+ return status;
+ }
+
+ count--;
+ if (!count)
+ break;
+ status &= (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR);
+ if (status != ATA_CB_STAT_DRQ) {
+ dprintf(6, "ata_pio_transfer : more sectors left (status %02x)\n"
+ , status);
+ op->count -= count;
+ return -6;
+ }
+ }
+
+ status &= (ATA_CB_STAT_BSY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ
+ | ATA_CB_STAT_ERR);
+ if (!iswrite)
+ status &= ~ATA_CB_STAT_DF;
+ if (status != 0) {
+ dprintf(6, "ata_pio_transfer : no sectors left (status %02x)\n", status);
+ return -7;
+ }
+
+ return 0;
+}
+
+
+/****************************************************************
+ * ATA DMA transfers
+ ****************************************************************/
+
+#define BM_CMD 0
+#define BM_CMD_MEMWRITE 0x08
+#define BM_CMD_START 0x01
+#define BM_STATUS 2
+#define BM_STATUS_IRQ 0x04
+#define BM_STATUS_ERROR 0x02
+#define BM_STATUS_ACTIVE 0x01
+#define BM_TABLE 4
+
+struct sff_dma_prd {
+ u32 buf_fl;
+ u32 count;
+};
+
+// Check if DMA available and setup transfer if so.
+static int
+ata_try_dma(struct disk_op_s *op, int iswrite, int blocksize)
+{
+ if (! CONFIG_ATA_DMA)
+ return -1;
+ ASSERT16(); // behind ATA_DMA, needed on parisc to boot via ata
+ u32 dest = (u32)op->buf_fl;
+ if (dest & 1)
+ // Need minimum alignment of 1.
+ return -1;
+ struct atadrive_s *adrive_gf = container_of(
+ op->drive_fl, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ portaddr_t iomaster = GET_GLOBALFLAT(chan_gf->iomaster);
+ if (! iomaster)
+ return -1;
+ u32 bytes = op->count * blocksize;
+ if (! bytes)
+ return -1;
+
+ // Build PRD dma structure.
+ struct sff_dma_prd *dma = MAKE_FLATPTR(SEG_LOW, ExtraStack);
+ struct sff_dma_prd *origdma = dma;
+ while (bytes) {
+ if (dma >= &origdma[16])
+ // Too many descriptors..
+ return -1;
+ u32 count = bytes;
+ u32 max = 0x10000 - (dest & 0xffff);
+ if (count > max)
+ count = max;
+
+ SET_LOWFLAT(dma->buf_fl, dest);
+ bytes -= count;
+ if (!bytes)
+ // Last descriptor.
+ count |= 1<<31;
+ dprintf(16, "dma@%p: %08x %08x\n", dma, dest, count);
+ dest += count;
+ SET_LOWFLAT(dma->count, count);
+ dma++;
+ }
+
+ // Program bus-master controller.
+ outl((u32)origdma, iomaster + BM_TABLE);
+ u8 oldcmd = inb(iomaster + BM_CMD) & ~(BM_CMD_MEMWRITE|BM_CMD_START);
+ outb(oldcmd | (iswrite ? 0x00 : BM_CMD_MEMWRITE), iomaster + BM_CMD);
+ outb(BM_STATUS_ERROR|BM_STATUS_IRQ, iomaster + BM_STATUS);
+
+ return 0;
+}
+
+// Transfer data using DMA.
+static int
+ata_dma_transfer(struct disk_op_s *op)
+{
+ if (! CONFIG_ATA_DMA)
+ return -1;
+ dprintf(16, "ata_dma_transfer id=%p buf=%p\n", op->drive_fl, op->buf_fl);
+
+ struct atadrive_s *adrive_gf = container_of(
+ op->drive_fl, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ portaddr_t iomaster = GET_GLOBALFLAT(chan_gf->iomaster);
+
+ // Start bus-master controller.
+ u8 oldcmd = inb(iomaster + BM_CMD);
+ outb(oldcmd | BM_CMD_START, iomaster + BM_CMD);
+
+ u32 end = timer_calc(IDE_TIMEOUT);
+ u8 status;
+ for (;;) {
+ status = inb(iomaster + BM_STATUS);
+ if (status & BM_STATUS_IRQ)
+ break;
+ // Transfer in progress
+ if (timer_check(end)) {
+ // Timeout.
+ warn_timeout();
+ break;
+ }
+ yield();
+ }
+ outb(oldcmd & ~BM_CMD_START, iomaster + BM_CMD);
+
+ portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ portaddr_t iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+ int idestatus = pause_await_not_bsy(iobase1, iobase2);
+
+ if ((status & (BM_STATUS_IRQ|BM_STATUS_ACTIVE)) == BM_STATUS_IRQ
+ && idestatus >= 0x00
+ && (idestatus & (ATA_CB_STAT_BSY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ
+ | ATA_CB_STAT_ERR)) == 0x00)
+ // Success.
+ return 0;
+
+ dprintf(6, "IDE DMA error (dma=%x ide=%x/%x/%x)\n", status, idestatus
+ , inb(iobase2 + ATA_CB_ASTAT), inb(iobase1 + ATA_CB_ERR));
+ return -1;
+}
+
+
+/****************************************************************
+ * ATA hard drive functions
+ ****************************************************************/
+
+// Transfer data to harddrive using PIO protocol.
+static int
+ata_pio_cmd_data(struct disk_op_s *op, int iswrite, struct ata_pio_command *cmd)
+{
+ struct atadrive_s *adrive_gf = container_of(
+ op->drive_fl, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ portaddr_t iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+
+ // Disable interrupts
+ outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC);
+
+ int ret = send_cmd(adrive_gf, cmd);
+ if (ret)
+ goto fail;
+ ret = ata_wait_data(iobase1);
+ if (ret)
+ goto fail;
+ ret = ata_pio_transfer(op, iswrite, DISK_SECTOR_SIZE);
+
+fail:
+ // Enable interrupts
+ outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
+ return ret;
+}
+
+// Transfer data to harddrive using DMA protocol.
+static int
+ata_dma_cmd_data(struct disk_op_s *op, struct ata_pio_command *cmd)
+{
+ if (! CONFIG_ATA_DMA)
+ return -1;
+ struct atadrive_s *adrive_gf = container_of(
+ op->drive_fl, struct atadrive_s, drive);
+ int ret = send_cmd(adrive_gf, cmd);
+ if (ret)
+ return ret;
+ return ata_dma_transfer(op);
+}
+
+// Read/write count blocks from a harddrive.
+static int
+ata_readwrite(struct disk_op_s *op, int iswrite)
+{
+ u64 lba = op->lba;
+
+ int usepio = ata_try_dma(op, iswrite, DISK_SECTOR_SIZE);
+
+ struct ata_pio_command cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ if (op->count >= (1<<8) || lba + op->count >= (1<<28)) {
+ cmd.sector_count2 = op->count >> 8;
+ cmd.lba_low2 = lba >> 24;
+ cmd.lba_mid2 = lba >> 32;
+ cmd.lba_high2 = lba >> 40;
+ lba &= 0xffffff;
+
+ if (usepio)
+ cmd.command = (iswrite ? ATA_CMD_WRITE_SECTORS_EXT
+ : ATA_CMD_READ_SECTORS_EXT);
+ else
+ cmd.command = (iswrite ? ATA_CMD_WRITE_DMA_EXT
+ : ATA_CMD_READ_DMA_EXT);
+ } else {
+ if (usepio)
+ cmd.command = (iswrite ? ATA_CMD_WRITE_SECTORS
+ : ATA_CMD_READ_SECTORS);
+ else
+ cmd.command = (iswrite ? ATA_CMD_WRITE_DMA
+ : ATA_CMD_READ_DMA);
+ }
+
+ cmd.sector_count = op->count;
+ cmd.lba_low = lba;
+ cmd.lba_mid = lba >> 8;
+ cmd.lba_high = lba >> 16;
+ cmd.device = ((lba >> 24) & 0xf) | ATA_CB_DH_LBA;
+
+ int ret;
+ if (usepio)
+ ret = ata_pio_cmd_data(op, iswrite, &cmd);
+ else
+ ret = ata_dma_cmd_data(op, &cmd);
+ if (ret)
+ return DISK_RET_EBADTRACK;
+ return DISK_RET_SUCCESS;
+}
+
+// 16bit command demuxer for ATA harddrives.
+int
+ata_process_op(struct disk_op_s *op)
+{
+ if (!CONFIG_ATA)
+ return 0;
+
+ struct atadrive_s *adrive_gf = container_of(
+ op->drive_fl, struct atadrive_s, drive);
+ switch (op->command) {
+ case CMD_READ:
+ return ata_readwrite(op, 0);
+ case CMD_WRITE:
+ return ata_readwrite(op, 1);
+ case CMD_RESET:
+ ata_reset(adrive_gf);
+ return DISK_RET_SUCCESS;
+ case CMD_ISREADY:
+ return isready(adrive_gf);
+ default:
+ return default_process_op(op);
+ }
+}
+
+
+/****************************************************************
+ * ATAPI functions
+ ****************************************************************/
+
+#define CDROM_CDB_SIZE 12
+
+// Low-level atapi command transmit function.
+int
+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_fl, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ portaddr_t iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ portaddr_t iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+
+ struct ata_pio_command cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.lba_mid = blocksize;
+ cmd.lba_high = blocksize >> 8;
+ cmd.command = ATA_CMD_PACKET;
+
+ // Disable interrupts
+ outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC);
+
+ int ret = send_cmd(adrive_gf, &cmd);
+ if (ret)
+ goto fail;
+ ret = ata_wait_data(iobase1);
+ if (ret)
+ goto fail;
+
+ // Send command to device
+ outsw_fl(iobase1, MAKE_FLATPTR(GET_SEG(SS), cdbcmd), CDROM_CDB_SIZE / 2);
+
+ int status = pause_await_not_bsy(iobase1, iobase2);
+ if (status < 0) {
+ ret = status;
+ goto fail;
+ }
+
+ if (status & ATA_CB_STAT_ERR) {
+ u8 err = inb(iobase1 + ATA_CB_ERR);
+ // skip "Not Ready"
+ if (err != 0x20)
+ dprintf(6, "send_atapi_cmd : read error (status=%02x err=%02x)\n"
+ , status, err);
+ ret = -2;
+ goto fail;
+ }
+ if (blocksize) {
+ if (!(status & ATA_CB_STAT_DRQ)) {
+ dprintf(6, "send_atapi_cmd : DRQ not set (status %02x)\n", status);
+ ret = -3;
+ goto fail;
+ }
+
+ ret = ata_pio_transfer(op, 0, blocksize);
+ }
+
+fail:
+ // Enable interrupts
+ outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
+ if (ret)
+ return DISK_RET_EBADTRACK;
+ return DISK_RET_SUCCESS;
+}
+
+
+/****************************************************************
+ * ATA detect and init
+ ****************************************************************/
+
+// Send an identify device or identify device packet command.
+static int
+send_ata_identity(struct atadrive_s *adrive, u16 *buffer, int command)
+{
+ memset(buffer, 0, DISK_SECTOR_SIZE);
+
+ struct disk_op_s dop;
+ memset(&dop, 0, sizeof(dop));
+ dop.drive_fl = &adrive->drive;
+ dop.count = 1;
+ dop.lba = 1;
+ dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer);
+
+ struct ata_pio_command cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.command = command;
+
+ return ata_pio_cmd_data(&dop, 0, &cmd);
+}
+
+// Extract the ATA/ATAPI version info.
+int
+ata_extract_version(u16 *buffer)
+{
+ // Extract ATA/ATAPI version.
+ u16 ataversion = buffer[80];
+ u8 version;
+ for (version=15; version>0; version--)
+ if (ataversion & (1<<version))
+ break;
+ return version;
+}
+
+#define MAXMODEL 40
+
+// Extract the ATA/ATAPI model info.
+char *
+ata_extract_model(char *model, u32 size, u16 *buffer)
+{
+ // Read model name
+ int i;
+ for (i=0; i<size/2; i++)
+ *(u16*)&model[i*2] = cpu_to_le16(be16_to_cpu(buffer[27+i]));
+ model[size] = 0x00;
+ nullTrailingSpace(model);
+ return model;
+}
+
+// Common init code between ata and atapi
+static struct atadrive_s *
+init_atadrive(struct atadrive_s *dummy, u16 *buffer)
+{
+ struct atadrive_s *adrive = malloc_fseg(sizeof(*adrive));
+ if (!adrive) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(adrive, 0, sizeof(*adrive));
+ adrive->chan_gf = dummy->chan_gf;
+ adrive->slave = dummy->slave;
+ adrive->drive.cntl_id = adrive->chan_gf->ataid * 2 + dummy->slave;
+ adrive->drive.removable = le16_to_cpu((buffer[0]) & 0x80) ? 1 : 0;
+ return adrive;
+}
+
+// Detect if the given drive is an atapi - initialize it if so.
+static struct atadrive_s *
+init_drive_atapi(struct atadrive_s *dummy, u16 *buffer)
+{
+ // Send an IDENTIFY_DEVICE_PACKET command to device
+ int ret = send_ata_identity(dummy, buffer, ATA_CMD_IDENTIFY_PACKET_DEVICE);
+ if (ret)
+ return NULL;
+
+ // Success - setup as ATAPI.
+ struct atadrive_s *adrive = init_atadrive(dummy, buffer);
+ if (!adrive)
+ return NULL;
+ adrive->drive.type = DTYPE_ATA_ATAPI;
+ adrive->drive.blksize = CDROM_SECTOR_SIZE;
+ adrive->drive.sectors = (u64)-1;
+ u8 iscd = ((le16_to_cpu(buffer[0]) >> 8) & 0x1f) == 0x05;
+ char model[MAXMODEL+1];
+ char *desc = znprintf(MAXDESCSIZE
+ , "DVD/CD [ata%d-%d: %s ATAPI-%d %s]"
+ , adrive->chan_gf->ataid, adrive->slave
+ , ata_extract_model(model, MAXMODEL, buffer)
+ , ata_extract_version(buffer)
+ , (iscd ? "DVD/CD" : "Device"));
+ dprintf(1, "%s\n", desc);
+
+ // fill cdidmap
+ if (iscd) {
+ int prio = bootprio_find_ata_device(adrive->chan_gf->pci_tmp,
+ adrive->chan_gf->chanid,
+ adrive->slave);
+ boot_lchs_find_ata_device(adrive->chan_gf->pci_tmp,
+ adrive->chan_gf->chanid,
+ adrive->slave,
+ &(adrive->drive.lchs));
+ boot_add_cd(&adrive->drive, desc, prio);
+ }
+
+ return adrive;
+}
+
+// Detect if the given drive is a regular ata drive - initialize it if so.
+static struct atadrive_s *
+init_drive_ata(struct atadrive_s *dummy, u16 *buffer)
+{
+ // Send an IDENTIFY_DEVICE command to device
+ int ret = send_ata_identity(dummy, buffer, ATA_CMD_IDENTIFY_DEVICE);
+ if (ret)
+ return NULL;
+
+ // Success - setup as ATA.
+ struct atadrive_s *adrive = init_atadrive(dummy, buffer);
+ if (!adrive)
+ return NULL;
+ adrive->drive.type = DTYPE_ATA;
+ adrive->drive.blksize = DISK_SECTOR_SIZE;
+
+ adrive->drive.pchs.cylinder = le16_to_cpu(buffer[1]);
+ adrive->drive.pchs.head = le16_to_cpu(buffer[3]);
+ adrive->drive.pchs.sector = le16_to_cpu(buffer[6]);
+
+ u64 sectors;
+ if (le16_to_cpu(buffer[83]) & (1 << 10)) // word 83 - lba48 support
+ sectors = le64_to_cpu(*(u64*)&buffer[100]); // word 100-103
+ else
+ sectors = le32_to_cpu(*(u32*)&buffer[60]); // word 60 and word 61
+ adrive->drive.sectors = sectors;
+ u64 adjsize = sectors >> 11;
+ char adjprefix = 'M';
+ if (adjsize >= (1 << 16)) {
+ adjsize >>= 10;
+ adjprefix = 'G';
+ }
+ char model[MAXMODEL+1];
+ char *desc = znprintf(MAXDESCSIZE
+ , "ata%d-%d: %s ATA-%d Hard-Disk (%u %ciBytes)"
+ , adrive->chan_gf->ataid, adrive->slave
+ , ata_extract_model(model, MAXMODEL, buffer)
+ , ata_extract_version(buffer)
+ , (u32)adjsize, adjprefix);
+ dprintf(1, "%s\n", desc);
+
+ int prio = bootprio_find_ata_device(adrive->chan_gf->pci_tmp,
+ adrive->chan_gf->chanid,
+ adrive->slave);
+ boot_lchs_find_ata_device(adrive->chan_gf->pci_tmp,
+ adrive->chan_gf->chanid,
+ adrive->slave,
+ &(adrive->drive.lchs));
+ // Register with bcv system.
+ boot_add_hd(&adrive->drive, desc, prio);
+
+ return adrive;
+}
+
+static u32 SpinupEnd;
+
+// Wait for non-busy status and check for "floating bus" condition.
+static int
+powerup_await_non_bsy(portaddr_t base)
+{
+ u8 orstatus = 0;
+ u8 status;
+ for (;;) {
+ status = inb(base+ATA_CB_STAT);
+ if (!(status & ATA_CB_STAT_BSY))
+ break;
+ orstatus |= status;
+ if (orstatus == 0xff) {
+ dprintf(4, "powerup IDE floating\n");
+ return orstatus;
+ }
+ if (timer_check(SpinupEnd)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+ dprintf(6, "powerup iobase=%x st=%x\n", base, status);
+ return status;
+}
+
+// Detect any drives attached to a given controller.
+static void
+ata_detect(void *data)
+{
+ struct ata_channel_s *chan_gf = data;
+ struct atadrive_s dummy;
+ memset(&dummy, 0, sizeof(dummy));
+ dummy.chan_gf = chan_gf;
+ // Device detection
+ int didreset = 0;
+ u8 slave;
+ for (slave=0; slave<=1; slave++) {
+ // Wait for not-bsy.
+ portaddr_t iobase1 = chan_gf->iobase1;
+ int status = powerup_await_non_bsy(iobase1);
+ if (status < 0)
+ continue;
+ u8 newdh = slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0;
+ outb(newdh, iobase1+ATA_CB_DH);
+ ndelay(400);
+ status = powerup_await_non_bsy(iobase1);
+ if (status < 0)
+ continue;
+
+ // Check if ioport registers look valid.
+ outb(newdh, iobase1+ATA_CB_DH);
+ u8 dh = inb(iobase1+ATA_CB_DH);
+ outb(0x55, iobase1+ATA_CB_SC);
+ outb(0xaa, iobase1+ATA_CB_SN);
+ 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->ataid, slave, sc, sn, dh);
+ if (sc != 0x55 || sn != 0xaa || dh != newdh)
+ continue;
+
+ // Prepare new drive.
+ dummy.slave = slave;
+
+ // reset the channel
+ if (!didreset) {
+ ata_reset(&dummy);
+ didreset = 1;
+ }
+
+ // check for ATAPI
+ u16 buffer[256];
+ struct atadrive_s *adrive = init_drive_atapi(&dummy, buffer);
+ if (!adrive) {
+ // Didn't find an ATAPI drive - look for ATA drive.
+ u8 st = inb(iobase1+ATA_CB_STAT);
+ if (!st)
+ // Status not set - can't be a valid drive.
+ continue;
+
+ // Wait for RDY.
+ int ret = await_rdy(iobase1);
+ if (ret < 0)
+ continue;
+
+ // check for ATA.
+ adrive = init_drive_ata(&dummy, buffer);
+ if (!adrive)
+ // No ATA drive found
+ continue;
+ }
+
+ u16 resetresult = le16_to_cpu(buffer[93]);
+ dprintf(6, "ata_detect resetresult=%04x\n", resetresult);
+ if (!slave && (resetresult & 0xdf61) == 0x4041)
+ // resetresult looks valid and device 0 is responding to
+ // device 1 requests - device 1 must not be present - skip
+ // detection.
+ break;
+ }
+}
+
+// Initialize an ata controller and detect its drives.
+static void
+init_controller(struct pci_device *pci, int chanid, int irq
+ , u32 port1, u32 port2, u32 master)
+{
+ static int ataid = 0;
+ struct ata_channel_s *chan_gf = malloc_fseg(sizeof(*chan_gf));
+ if (!chan_gf) {
+ warn_noalloc();
+ return;
+ }
+ 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;
+ chan_gf->iobase1 = port1;
+ chan_gf->iobase2 = port2;
+ chan_gf->iomaster = master;
+ dprintf(1, "ATA controller %d at %x/%x/%x (irq %d dev %x)\n"
+ , ataid, port1, port2, master, irq, chan_gf->pci_bdf);
+ run_thread(ata_detect, chan_gf);
+}
+
+#define IRQ_ATA1 14
+#define IRQ_ATA2 15
+
+// Handle controllers on an ATA PCI device.
+static void
+init_pciata(struct pci_device *pci, u8 prog_if)
+{
+ u8 pciirq = pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE);
+ int master = 0;
+ if (CONFIG_ATA_DMA && prog_if & 0x80) {
+ // Check for bus-mastering.
+ u32 bar = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_4);
+ if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
+ master = pci_enable_iobar(pci, PCI_BASE_ADDRESS_4);
+ pci_enable_busmaster(pci);
+ }
+ }
+
+ u32 port1, port2, irq;
+ if (prog_if & 1) {
+ port1 = pci_enable_iobar(pci, PCI_BASE_ADDRESS_0);
+ port2 = pci_enable_iobar(pci, PCI_BASE_ADDRESS_1);
+ if (!port1 || !port2)
+ return;
+ irq = pciirq;
+ } else {
+ port1 = PORT_ATA1_CMD_BASE;
+ port2 = PORT_ATA1_CTRL_BASE;
+ irq = IRQ_ATA1;
+ }
+ init_controller(pci, 0, irq, port1, port2, master);
+
+ if (prog_if & 4) {
+ port1 = pci_enable_iobar(pci, PCI_BASE_ADDRESS_2);
+ port2 = pci_enable_iobar(pci, PCI_BASE_ADDRESS_3);
+ if (!port1 || !port2)
+ return;
+ irq = pciirq;
+ } else {
+ port1 = PORT_ATA2_CMD_BASE;
+ port2 = PORT_ATA2_CTRL_BASE;
+ irq = IRQ_ATA2;
+ }
+ init_controller(pci, 1, irq, port1, port2, master ? master + 8 : 0);
+}
+
+static void
+found_genericata(struct pci_device *pci, void *arg)
+{
+ init_pciata(pci, pci->prog_if);
+}
+
+static void
+found_compatibleahci(struct pci_device *pci, void *arg)
+{
+ if (CONFIG_AHCI)
+ // Already handled directly via native ahci interface.
+ return;
+ init_pciata(pci, 0x8f);
+}
+
+static const struct pci_device_id pci_ata_tbl[] = {
+ PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE
+ , found_genericata),
+ PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4391, found_compatibleahci),
+ PCI_DEVICE_END,
+};
+
+// Locate and init ata controllers.
+static void
+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, 0, IRQ_ATA1
+ , PORT_ATA1_CMD_BASE, PORT_ATA1_CTRL_BASE, 0);
+ init_controller(NULL, 1, IRQ_ATA2
+ , PORT_ATA2_CMD_BASE, PORT_ATA2_CTRL_BASE, 0);
+ return;
+ }
+
+ // Scan PCI bus for ATA adapters
+ struct pci_device *pci;
+ foreachpci(pci) {
+ pci_init_device(pci_ata_tbl, pci, NULL);
+ }
+}
+
+void
+ata_setup(void)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_ATA)
+ return;
+
+ dprintf(3, "init hard drives\n");
+
+ SpinupEnd = timer_calc(IDE_TIMEOUT);
+ ata_scan();
+
+ SET_BDA(disk_control_byte, 0xc0);
+
+ enable_hwirq(14, FUNC16(entry_76));
+}
diff --git a/roms/seabios-hppa/src/hw/ata.h b/roms/seabios-hppa/src/hw/ata.h
new file mode 100644
index 000000000..dff209a0b
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/ata.h
@@ -0,0 +1,171 @@
+#ifndef __ATA_H
+#define __ATA_H
+
+#include "block.h" // struct drive_s
+#include "config.h" // CONFIG_MAX_ATA_INTERFACES
+#include "types.h" // u8
+
+struct ata_channel_s {
+ portaddr_t iobase1;
+ portaddr_t iobase2;
+ portaddr_t iomaster;
+ u8 irq;
+ u8 chanid;
+ u8 ataid;
+ int pci_bdf;
+ struct pci_device *pci_tmp;
+};
+
+struct atadrive_s {
+ struct drive_s drive;
+ struct ata_channel_s *chan_gf;
+ u8 slave;
+};
+
+// ata.c
+char *ata_extract_model(char *model, u32 size, u16 *buffer);
+int ata_extract_version(u16 *buffer);
+int ata_process_op(struct disk_op_s *op);
+int ata_atapi_process_op(struct disk_op_s *op);
+void ata_setup(void);
+
+#if CONFIG_X86
+#define PORT_ATA2_CMD_BASE 0x0170
+#define PORT_ATA1_CMD_BASE 0x01f0
+#define PORT_ATA2_CTRL_BASE 0x0374
+#define PORT_ATA1_CTRL_BASE 0x03f4
+#elif CONFIG_PARISC
+#include "parisc/hppa_hardware.h"
+#define PORT_ATA2_CMD_BASE (IDE_HPA+0x0170)
+#define PORT_ATA1_CMD_BASE (IDE_HPA+0x01f0)
+#define PORT_ATA2_CTRL_BASE (IDE_HPA+0x0374)
+#define PORT_ATA1_CTRL_BASE (IDE_HPA+0x03f4)
+#endif
+
+// Global defines -- ATA register and register bits.
+// command block & control block regs
+#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
+#define ATA_CB_ERR 1 // error in pio_base_addr1+1
+#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
+#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
+#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
+#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
+#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
+#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
+#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
+#define ATA_CB_CMD 7 // command out pio_base_addr1+7
+
+#define ATA_CB_ASTAT 2 // alternate status in pio_base_addr2+2
+#define ATA_CB_DC 2 // device control out pio_base_addr2+2
+#define ATA_CB_DA 3 // device address in pio_base_addr2+3
+
+#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
+#define ATA_CB_ER_BBK 0x80 // ATA bad block
+#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
+#define ATA_CB_ER_MC 0x20 // ATA media change
+#define ATA_CB_ER_IDNF 0x10 // ATA id not found
+#define ATA_CB_ER_MCR 0x08 // ATA media change request
+#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
+#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
+#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
+
+#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
+#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
+#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
+#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
+#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
+
+// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
+#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
+#define ATA_CB_SC_P_REL 0x04 // ATAPI release
+#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
+#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
+
+// bits 7-4 of the device/head (CB_DH) reg
+#define ATA_CB_DH_DEV0 0xa0 // select device 0
+#define ATA_CB_DH_DEV1 0xb0 // select device 1
+#define ATA_CB_DH_LBA 0x40 // use LBA
+
+// status reg (CB_STAT and CB_ASTAT) bits
+#define ATA_CB_STAT_BSY 0x80 // busy
+#define ATA_CB_STAT_RDY 0x40 // ready
+#define ATA_CB_STAT_DF 0x20 // device fault
+#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
+#define ATA_CB_STAT_SKC 0x10 // seek complete
+#define ATA_CB_STAT_SERV 0x10 // service
+#define ATA_CB_STAT_DRQ 0x08 // data request
+#define ATA_CB_STAT_CORR 0x04 // corrected
+#define ATA_CB_STAT_IDX 0x02 // index
+#define ATA_CB_STAT_ERR 0x01 // error (ATA)
+#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
+
+// device control reg (CB_DC) bits
+#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
+#define ATA_CB_DC_SRST 0x04 // soft reset
+#define ATA_CB_DC_NIEN 0x02 // disable interrupts
+
+// Most mandtory and optional ATA commands (from ATA-3),
+#define ATA_CMD_NOP 0x00
+#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
+#define ATA_CMD_DEVICE_RESET 0x08
+#define ATA_CMD_RECALIBRATE 0x10
+#define ATA_CMD_READ_SECTORS 0x20
+#define ATA_CMD_READ_SECTORS_EXT 0x24
+#define ATA_CMD_READ_DMA_EXT 0x25
+#define ATA_CMD_READ_DMA_QUEUED_EXT 0x26
+#define ATA_CMD_READ_NATIVE_MAX_ADDRESS_EXT 0x27
+#define ATA_CMD_READ_MULTIPLE_EXT 0x29
+#define ATA_CMD_READ_LOG_EXT 0x2F
+#define ATA_CMD_WRITE_SECTORS 0x30
+#define ATA_CMD_WRITE_SECTORS_EXT 0x34
+#define ATA_CMD_WRITE_DMA_EXT 0x35
+#define ATA_CMD_WRITE_DMA_QUEUED_EXT 0x36
+#define ATA_CMD_SET_MAX_ADDRESS_EXT 0x37
+#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
+#define ATA_CMD_WRITE_MULTIPLE_EXT 0x39
+#define ATA_CMD_WRITE_VERIFY 0x3C
+#define ATA_CMD_WRITE_LOG_EXT 0x3F
+#define ATA_CMD_READ_VERIFY_SECTORS 0x40
+#define ATA_CMD_READ_VERIFY_SECTORS_EXT 0x42
+#define ATA_CMD_FORMAT_TRACK 0x50
+#define ATA_CMD_SEEK 0x70
+#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
+#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
+#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
+#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
+#define ATA_CMD_IDLE_IMMEDIATE2 0x95
+#define ATA_CMD_STANDBY2 0x96
+#define ATA_CMD_IDLE2 0x97
+#define ATA_CMD_CHECK_POWER_MODE2 0x98
+#define ATA_CMD_SLEEP2 0x99
+#define ATA_CMD_PACKET 0xA0
+#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
+#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
+#define ATA_CMD_READ_MULTIPLE 0xC4
+#define ATA_CMD_WRITE_MULTIPLE 0xC5
+#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
+#define ATA_CMD_READ_DMA_QUEUED 0xC7
+#define ATA_CMD_READ_DMA 0xC8
+#define ATA_CMD_WRITE_DMA 0xCA
+#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
+#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
+#define ATA_CMD_STANDBY_IMMEDIATE 0xE0
+#define ATA_CMD_IDLE_IMMEDIATE 0xE1
+#define ATA_CMD_STANDBY 0xE2
+#define ATA_CMD_IDLE 0xE3
+#define ATA_CMD_READ_BUFFER 0xE4
+#define ATA_CMD_CHECK_POWER_MODE 0xE5
+#define ATA_CMD_SLEEP 0xE6
+#define ATA_CMD_FLUSH_CACHE 0xE7
+#define ATA_CMD_WRITE_BUFFER 0xE8
+#define ATA_CMD_IDENTIFY_DEVICE 0xEC
+#define ATA_CMD_SET_FEATURES 0xEF
+#define ATA_CMD_READ_NATIVE_MAX_ADDRESS 0xF8
+#define ATA_CMD_SET_MAX 0xF9
+
+#define ATA_SET_FEATRUE_TRANSFER_MODE 0x03
+#define ATA_TRANSFER_MODE_ULTRA_DMA 0x40
+#define ATA_TRANSFER_MODE_MULTIWORD_DMA 0x20
+#define ATA_TRANSFER_MODE_PIO_FLOW_CTRL 0x08
+#define ATA_TRANSFER_MODE_DEFAULT_PIO 0x00
+#endif // ata.h
diff --git a/roms/seabios-hppa/src/hw/blockcmd.c b/roms/seabios-hppa/src/hw/blockcmd.c
new file mode 100644
index 000000000..89f16a8b5
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/blockcmd.c
@@ -0,0 +1,381 @@
+// Support for several common scsi like command data block requests
+//
+// Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "block.h" // struct disk_op_s
+#include "blockcmd.h" // struct cdb_request_sense
+#include "byteorder.h" // be32_to_cpu
+#include "farptr.h" // GET_FLATPTR
+#include "output.h" // dprintf
+#include "std/disk.h" // DISK_RET_EPARAM
+#include "string.h" // memset
+#include "util.h" // timer_calc
+#include "malloc.h"
+
+
+/****************************************************************
+ * Low level command requests
+ ****************************************************************/
+
+static int
+cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data)
+{
+ struct cdb_request_sense cmd;
+ 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;
+ op->cdbcmd = &cmd;
+ op->blocksize = sizeof(*data);
+ return process_op(op);
+}
+
+// Request SENSE
+static int
+cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data)
+{
+ struct cdb_request_sense cmd;
+ 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;
+ op->cdbcmd = &cmd;
+ op->blocksize = sizeof(*data);
+ return process_op(op);
+}
+
+// Test unit ready
+static int
+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;
+ op->cdbcmd = &cmd;
+ op->blocksize = 0;
+ return process_op(op);
+}
+
+// Request capacity
+static int
+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;
+ op->cdbcmd = &cmd;
+ op->blocksize = sizeof(*data);
+ return process_op(op);
+}
+
+// Mode sense, geometry page.
+static int
+cdb_mode_sense_geom(struct disk_op_s *op, struct cdbres_mode_sense_geom *data)
+{
+ struct cdb_mode_sense cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.command = CDB_CMD_MODE_SENSE;
+ 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;
+ op->cdbcmd = &cmd;
+ op->blocksize = sizeof(*data);
+ return process_op(op);
+}
+
+
+/****************************************************************
+ * Main SCSI commands
+ ****************************************************************/
+
+// 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:
+ case CMD_WRITE: ;
+ // PA-RISC: Beware alignment: do not write u64 to unaligned address.
+ struct cdb_rwdata_10 cmd;
+ memset(cdbcmd, 0, maxcdb);
+ memset(&cmd, 0, sizeof(cmd));
+ 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);
+ memcpy(cdbcmd, &cmd, sizeof(cmd));
+ return GET_FLATPTR(op->drive_fl->blksize);
+ case CMD_SCSI:
+ if (MODESEGMENT)
+ return -1;
+ memcpy(cdbcmd, op->cdbcmd, maxcdb);
+ return op->blocksize;
+ default:
+ 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 || (
+ !MODESEGMENT && 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)
+{
+ ASSERT32FLAT();
+ dprintf(6, "scsi_is_ready (drive=%p)\n", op->drive_fl);
+
+ /* Retry TEST UNIT READY for 5 seconds unless MEDIUM NOT PRESENT is
+ * reported by the device 3 times. If the device reports "IN PROGRESS",
+ * 30 seconds is added. */
+ int tries = 3;
+ int in_progress = 0;
+ u32 end = timer_calc(5000);
+ for (;;) {
+ if (timer_check(end)) {
+ dprintf(1, "test unit ready failed\n");
+ return -1;
+ }
+
+ int ret = cdb_test_unit_ready(op);
+ if (!ret)
+ // Success
+ break;
+
+ struct cdbres_request_sense sense;
+ ret = cdb_get_sense(op, &sense);
+ if (ret)
+ // Error - retry.
+ continue;
+
+ // Sense succeeded.
+ if (sense.asc == 0x3a) { /* MEDIUM NOT PRESENT */
+ tries--;
+ dprintf(1, "Device reports MEDIUM NOT PRESENT - %d tries left\n",
+ tries);
+ if (!tries)
+ return -1;
+ }
+
+ if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) {
+ /* IN PROGRESS OF BECOMING READY */
+ dprintf(1, "Waiting for device to detect medium... ");
+ /* Allow 30 seconds more */
+ end = timer_calc(30000);
+ in_progress = 1;
+ }
+ }
+ return 0;
+}
+
+#define CDB_CMD_REPORT_LUNS 0xA0
+
+struct cdb_report_luns {
+ u8 command;
+ u8 reserved_01[5];
+ u32 length;
+ u8 pad[6];
+} PACKED;
+
+struct scsi_lun {
+ u16 lun[4];
+};
+
+struct cdbres_report_luns {
+ u32 length;
+ u32 reserved;
+ struct scsi_lun luns[];
+};
+
+static u64 scsilun2u64(struct scsi_lun *scsi_lun)
+{
+ int i;
+ u64 ret = 0;
+ for (i = 0; i < ARRAY_SIZE(scsi_lun->lun); i++)
+ ret |= be16_to_cpu(scsi_lun->lun[i]) << (16 * i);
+ return ret;
+}
+
+// Issue REPORT LUNS on a temporary drive and iterate reported luns calling
+// @add_lun for each
+int scsi_rep_luns_scan(struct drive_s *tmp_drive, scsi_add_lun add_lun)
+{
+ int ret = -1;
+ /* start with the smallest possible buffer, otherwise some devices in QEMU
+ * may (incorrectly) error out on returning less data than fits in it */
+ u32 maxluns = 1;
+ u32 nluns, i;
+ struct cdb_report_luns cdb = {
+ .command = CDB_CMD_REPORT_LUNS,
+ };
+ struct disk_op_s op = {
+ .drive_fl = tmp_drive,
+ .command = CMD_SCSI,
+ .count = 1,
+ .cdbcmd = &cdb,
+ };
+ struct cdbres_report_luns *resp;
+
+ ASSERT32FLAT();
+
+ while (1) {
+ op.blocksize = sizeof(struct cdbres_report_luns) +
+ maxluns * sizeof(struct scsi_lun);
+ op.buf_fl = malloc_tmp(op.blocksize);
+ if (!op.buf_fl) {
+ warn_noalloc();
+ return -1;
+ }
+
+ cdb.length = cpu_to_be32(op.blocksize);
+ if (process_op(&op) != DISK_RET_SUCCESS)
+ goto out;
+
+ resp = op.buf_fl;
+ nluns = be32_to_cpu(resp->length) / sizeof(struct scsi_lun);
+ if (nluns <= maxluns)
+ break;
+
+ free(op.buf_fl);
+ maxluns = nluns;
+ }
+
+ for (i = 0, ret = 0; i < nluns; i++) {
+ u64 lun = scsilun2u64(&resp->luns[i]);
+ if (lun >> 32)
+ continue;
+ ret += !add_lun((u32)lun, tmp_drive);
+ }
+out:
+ free(op.buf_fl);
+ return ret;
+}
+
+// Iterate LUNs on the target and call @add_lun for each
+int scsi_sequential_scan(struct drive_s *tmp_drive, u32 maxluns,
+ scsi_add_lun add_lun)
+{
+ int ret;
+ u32 lun;
+
+ for (lun = 0, ret = 0; lun < maxluns; lun++)
+ ret += !add_lun(lun, tmp_drive);
+ return ret;
+}
+
+// Validate drive, find block size / sector count, and register drive.
+int
+scsi_drive_setup(struct drive_s *drive, const char *s, int prio, u8 target, u8 lun)
+{
+ ASSERT32FLAT();
+ drive->target = target;
+ drive->lun = lun;
+ struct disk_op_s dop;
+ memset(&dop, 0, sizeof(dop));
+ dop.drive_fl = drive;
+ struct cdbres_inquiry data;
+ int ret = cdb_get_inquiry(&dop, &data);
+ if (ret)
+ return ret;
+ char vendor[sizeof(data.vendor)+1], product[sizeof(data.product)+1];
+ char rev[sizeof(data.rev)+1];
+ strtcpy(vendor, data.vendor, sizeof(vendor));
+ nullTrailingSpace(vendor);
+ strtcpy(product, data.product, sizeof(product));
+ nullTrailingSpace(product);
+ strtcpy(rev, data.rev, sizeof(rev));
+ nullTrailingSpace(rev);
+ int pdt = data.pdt & 0x1f;
+ int removable = !!(data.removable & 0x80);
+ dprintf(1, "%s vendor='%s' product='%s' rev='%s' type=%d removable=%d\n"
+ , s, vendor, product, rev, pdt, removable);
+ drive->removable = removable;
+
+ if (pdt == SCSI_TYPE_CDROM) {
+ drive->blksize = CDROM_SECTOR_SIZE;
+ drive->sectors = (u64)-1;
+
+ char *desc = znprintf(MAXDESCSIZE, "DVD/CD [%s Drive %s %s %s]"
+ , s, vendor, product, rev);
+ boot_add_cd(drive, desc, prio);
+ return 0;
+ }
+
+ if (pdt != SCSI_TYPE_DISK)
+ return -1;
+
+ ret = scsi_is_ready(&dop);
+ if (ret) {
+ dprintf(1, "scsi_is_ready returned %d\n", ret);
+ return ret;
+ }
+
+ struct cdbres_read_capacity capdata;
+ ret = cdb_read_capacity(&dop, &capdata);
+ if (ret)
+ return ret;
+
+ // READ CAPACITY returns the address of the last block.
+ // We do not bother with READ CAPACITY(16) because BIOS does not support
+ // 64-bit LBA anyway.
+ drive->blksize = be32_to_cpu(capdata.blksize);
+ if (drive->blksize != DISK_SECTOR_SIZE) {
+ dprintf(1, "%s: unsupported block size %d\n", s, drive->blksize);
+ return -1;
+ }
+ drive->sectors = (u64)be32_to_cpu(capdata.sectors) + 1;
+ dprintf(1, "%s blksize=%d sectors=%u\n"
+ , s, drive->blksize, (unsigned)drive->sectors);
+
+ // We do not recover from USB stalls, so try to be safe and avoid
+ // sending the command if the (obsolete, but still provided by QEMU)
+ // fixed disk geometry page may not be supported.
+ //
+ // We could also send the command only to small disks (e.g. <504MiB)
+ // but some old USB keys only support a very small subset of SCSI which
+ // does not even include the MODE SENSE command!
+ //
+ if (CONFIG_QEMU_HARDWARE && memcmp(vendor, "QEMU", 5) == 0) {
+ struct cdbres_mode_sense_geom geomdata;
+ ret = cdb_mode_sense_geom(&dop, &geomdata);
+ if (ret == 0) {
+ u32 cylinders;
+ cylinders = geomdata.cyl[0] << 16;
+ cylinders |= geomdata.cyl[1] << 8;
+ cylinders |= geomdata.cyl[2];
+ if (cylinders && geomdata.heads &&
+ drive->sectors <= 0xFFFFFFFFULL &&
+ ((u32)drive->sectors % (geomdata.heads * cylinders) == 0)) {
+ drive->pchs.cylinder = cylinders;
+ drive->pchs.head = geomdata.heads;
+ drive->pchs.sector = (u32)drive->sectors / (geomdata.heads * cylinders);
+ }
+ }
+ }
+
+ char *desc = znprintf(MAXDESCSIZE, "%s Drive %s %s %s"
+ , s, vendor, product, rev);
+ boot_add_hd(drive, desc, prio);
+ return 0;
+}
diff --git a/roms/seabios-hppa/src/hw/blockcmd.h b/roms/seabios-hppa/src/hw/blockcmd.h
new file mode 100644
index 000000000..42e18732b
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/blockcmd.h
@@ -0,0 +1,114 @@
+// Definitions for SCSI style command data blocks.
+#ifndef __BLOCKCMD_H
+#define __BLOCKCMD_H
+
+#include "types.h" // u8
+
+#define CDB_CMD_READ_10 0x28
+#define CDB_CMD_VERIFY_10 0x2f
+#define CDB_CMD_WRITE_10 0x2a
+
+struct cdb_rwdata_10 {
+ u8 command;
+ u8 flags;
+ u32 lba;
+ u8 resreved_06;
+ u16 count;
+ u8 reserved_09;
+ u8 pad[6];
+} PACKED;
+
+#define CDB_CMD_READ_CAPACITY 0x25
+
+struct cdb_read_capacity {
+ u8 command;
+ u8 flags;
+ u8 resreved_02[8];
+ u8 pad[6];
+} PACKED;
+
+struct cdbres_read_capacity {
+ u32 sectors;
+ u32 blksize;
+} PACKED;
+
+#define CDB_CMD_TEST_UNIT_READY 0x00
+#define CDB_CMD_INQUIRY 0x12
+#define CDB_CMD_REQUEST_SENSE 0x03
+
+struct cdb_request_sense {
+ u8 command;
+ u8 flags;
+ u16 reserved_02;
+ u8 length;
+ u8 reserved_05;
+ u8 pad[10];
+} PACKED;
+
+struct cdbres_request_sense {
+ u8 errcode;
+ u8 segment;
+ u8 flags;
+ u32 info;
+ u8 additional;
+ u32 specific;
+ u8 asc;
+ u8 ascq;
+ u32 reserved_0e;
+} PACKED;
+
+#define SCSI_TYPE_DISK 0x00
+#define SCSI_TYPE_CDROM 0x05
+
+struct cdbres_inquiry {
+ u8 pdt;
+ u8 removable;
+ u8 reserved_02[2];
+ u8 additional;
+ u8 reserved_05[3];
+ char vendor[8];
+ char product[16];
+ char rev[4];
+} PACKED;
+
+#define CDB_CMD_MODE_SENSE 0x5A
+#define MODE_PAGE_HD_GEOMETRY 0x04
+
+struct cdb_mode_sense {
+ u8 command;
+ u8 flags;
+ u8 page;
+ u32 reserved_03;
+ u16 count;
+ u8 reserved_09;
+ u8 pad[6];
+} PACKED;
+
+struct cdbres_mode_sense_geom {
+ u8 unused_00[3];
+ u8 read_only;
+ u32 unused_04;
+ u8 page;
+ u8 length;
+ u8 cyl[3];
+ u8 heads;
+ u8 precomp[3];
+ u8 reduced[3];
+ u16 step_rate;
+ u8 landing[3];
+ u16 rpm;
+} PACKED;
+
+// blockcmd.c
+struct disk_op_s;
+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, u8 target, u8 lun);
+typedef int (*scsi_add_lun)(u32 lun, struct drive_s *tmpl_drv);
+int scsi_rep_luns_scan(struct drive_s *tmp_drive, scsi_add_lun add_lun);
+int scsi_sequential_scan(struct drive_s *tmp_drive, u32 maxluns,
+ scsi_add_lun add_lun);
+
+#endif // blockcmd.h
diff --git a/roms/seabios-hppa/src/hw/dma.c b/roms/seabios-hppa/src/hw/dma.c
new file mode 100644
index 000000000..20c9fbb76
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/dma.c
@@ -0,0 +1,67 @@
+// Code to support legacy Intel 8237 DMA chip.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dma_setup
+#include "x86.h" // outb
+
+#define PORT_DMA_ADDR_2 0x0004
+#define PORT_DMA_CNT_2 0x0005
+#define PORT_DMA1_MASK_REG 0x000a
+#define PORT_DMA1_MODE_REG 0x000b
+#define PORT_DMA1_CLEAR_FF_REG 0x000c
+#define PORT_DMA1_MASTER_CLEAR 0x000d
+#define PORT_DMA_PAGE_2 0x0081
+#define PORT_DMA2_MASK_REG 0x00d4
+#define PORT_DMA2_MODE_REG 0x00d6
+#define PORT_DMA2_MASTER_CLEAR 0x00da
+
+// Setup the DMA controller for a floppy transfer.
+int
+dma_floppy(u32 addr, int count, int isWrite)
+{
+ // check for 64K boundary overrun
+ u16 end = count - 1;
+ u32 last_addr = addr + end;
+ if ((addr >> 16) != (last_addr >> 16))
+ return -1;
+
+ u8 mode_register = 0x46; // single mode, increment, autoinit disable,
+ if (isWrite)
+ mode_register = 0x4a;
+
+ outb(0x06, PORT_DMA1_MASK_REG);
+ outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop
+ outb(addr, PORT_DMA_ADDR_2);
+ outb(addr>>8, PORT_DMA_ADDR_2);
+ outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop
+ outb(end, PORT_DMA_CNT_2);
+ outb(end>>8, PORT_DMA_CNT_2);
+
+ // port 0b: DMA-1 Mode Register
+ // transfer type=write, channel 2
+ outb(mode_register, PORT_DMA1_MODE_REG);
+
+ // port 81: DMA-1 Page Register, channel 2
+ outb(addr>>16, PORT_DMA_PAGE_2);
+
+ outb(0x02, PORT_DMA1_MASK_REG); // unmask channel 2
+
+ return 0;
+}
+
+// Reset DMA controller
+void
+dma_setup(void)
+{
+ // first reset the DMA controllers
+ outb(0, PORT_DMA1_MASTER_CLEAR);
+ outb(0, PORT_DMA2_MASTER_CLEAR);
+
+ // then initialize the DMA controllers
+ outb(0xc0, PORT_DMA2_MODE_REG);
+ outb(0x00, PORT_DMA2_MASK_REG);
+}
diff --git a/roms/seabios-hppa/src/hw/esp-scsi.c b/roms/seabios-hppa/src/hw/esp-scsi.c
new file mode 100644
index 000000000..328243778
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/esp-scsi.c
@@ -0,0 +1,243 @@
+// AMD PCscsi boot support.
+//
+// Copyright (C) 2012 Red Hat Inc.
+//
+// Authors:
+// Paolo Bonzini <pbonzini@redhat.com>
+//
+// based on lsi-scsi.c which is written by:
+// Gerd Hoffman <kraxel@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBALFLAT
+#include "block.h" // struct drive_s
+#include "blockcmd.h" // scsi_drive_setup
+#include "config.h" // CONFIG_*
+#include "fw/paravirt.h" // runningOnQEMU
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_DEVICE_ID
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "stacks.h" // run_thread
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // usleep
+
+#define ESP_TCLO 0x00
+#define ESP_TCMID 0x04
+#define ESP_FIFO 0x08
+#define ESP_CMD 0x0c
+#define ESP_WBUSID 0x10
+#define ESP_TCHI 0x38
+
+#define ESP_RSTAT 0x10
+#define ESP_RINTR 0x14
+#define ESP_RFLAGS 0x1c
+
+#define ESP_DMA_CMD 0x40
+#define ESP_DMA_STC 0x44
+#define ESP_DMA_SPA 0x48
+#define ESP_DMA_WBC 0x4c
+#define ESP_DMA_WAC 0x50
+#define ESP_DMA_STAT 0x54
+#define ESP_DMA_SMDLA 0x58
+#define ESP_DMA_WMAC 0x58c
+
+#define ESP_CMD_DMA 0x80
+#define ESP_CMD_RESET 0x02
+#define ESP_CMD_TI 0x10
+#define ESP_CMD_ICCS 0x11
+#define ESP_CMD_SELATN 0x42
+
+#define ESP_STAT_DI 0x01
+#define ESP_STAT_CD 0x02
+#define ESP_STAT_MSG 0x04
+#define ESP_STAT_TC 0x10
+
+#define ESP_INTR_DC 0x20
+
+struct esp_lun_s {
+ struct drive_s drive;
+ struct pci_device *pci;
+ u32 iobase;
+ u8 target;
+ u8 lun;
+};
+
+static void
+esp_scsi_dma(u32 iobase, u32 buf, u32 len, int read)
+{
+ outb(len & 0xff, iobase + ESP_TCLO);
+ outb((len >> 8) & 0xff, iobase + ESP_TCMID);
+ outb((len >> 16) & 0xff, iobase + ESP_TCHI);
+ outl(buf, iobase + ESP_DMA_SPA);
+ outl(len, iobase + ESP_DMA_STC);
+ outb(read ? 0x83 : 0x03, iobase + ESP_DMA_CMD);
+}
+
+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_fl, 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;
+
+ outb(target, iobase + ESP_WBUSID);
+
+ /*
+ * We need to pass the LUN at the beginning of the command, and the FIFO
+ * is only 16 bytes, so we cannot support 16-byte CDBs. The alternative
+ * would be to use DMA for the 17-byte command too, which is quite
+ * overkill.
+ */
+ outb(lun, iobase + ESP_FIFO);
+ cdbcmd[1] &= 0x1f;
+ cdbcmd[1] |= lun << 5;
+ for (i = 0; i < 12; i++)
+ outb(cdbcmd[i], iobase + ESP_FIFO);
+ outb(ESP_CMD_SELATN, iobase + ESP_CMD);
+
+ for (state = 0;;) {
+ u8 stat = inb(iobase + ESP_RSTAT);
+
+ /* Detect disconnected device. */
+ if (state == 0 && (inb(iobase + ESP_RINTR) & ESP_INTR_DC)) {
+ return DISK_RET_ENOTREADY;
+ }
+
+ /* HBA reads command, clears CD, sets TC -> do DMA if needed. */
+ if (state == 0 && (stat & ESP_STAT_TC)) {
+ state++;
+ if (op->count && blocksize) {
+ /* Data phase. */
+ u32 count = (u32)op->count * 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;
+ }
+ }
+
+ /* At end of DMA TC is set again -> complete command. */
+ if (state == 1 && (stat & ESP_STAT_TC)) {
+ state++;
+ outb(ESP_CMD_ICCS, iobase + ESP_CMD);
+ continue;
+ }
+
+ /* Finally read data from the message in phase. */
+ if (state == 2 && (stat & ESP_STAT_MSG)) {
+ state++;
+ status = inb(iobase + ESP_FIFO);
+ inb(iobase + ESP_FIFO);
+ break;
+ }
+ usleep(5);
+ }
+
+ if (status == 0) {
+ return DISK_RET_SUCCESS;
+ }
+
+ return DISK_RET_EBADTRACK;
+}
+
+static void
+esp_scsi_init_lun(struct esp_lun_s *llun, struct pci_device *pci, u32 iobase,
+ u8 target, u8 lun)
+{
+ memset(llun, 0, sizeof(*llun));
+ llun->drive.type = DTYPE_ESP_SCSI;
+ llun->drive.cntl_id = pci->bdf;
+ llun->pci = pci;
+ llun->target = target;
+ llun->lun = lun;
+ llun->iobase = iobase;
+}
+
+static int
+esp_scsi_add_lun(u32 lun, struct drive_s *tmpl_drv)
+{
+ struct esp_lun_s *tmpl_llun =
+ container_of(tmpl_drv, struct esp_lun_s, drive);
+ struct esp_lun_s *llun = malloc_fseg(sizeof(*llun));
+ if (!llun) {
+ warn_noalloc();
+ return -1;
+ }
+ esp_scsi_init_lun(llun, tmpl_llun->pci, tmpl_llun->iobase,
+ tmpl_llun->target, lun);
+
+ char *name = znprintf(MAXDESCSIZE, "esp %pP %d:%d",
+ llun->pci, llun->target, llun->lun);
+ boot_lchs_find_scsi_device(llun->pci, llun->target, llun->lun,
+ &(llun->drive.lchs));
+ int prio = bootprio_find_scsi_device(llun->pci, llun->target, llun->lun);
+ int ret = scsi_drive_setup(&llun->drive, name, prio, llun->target, llun->lun);
+ free(name);
+ if (ret)
+ goto fail;
+ return 0;
+
+fail:
+ free(llun);
+ return -1;
+}
+
+static void
+esp_scsi_scan_target(struct pci_device *pci, u32 iobase, u8 target)
+{
+ struct esp_lun_s llun0;
+
+ esp_scsi_init_lun(&llun0, pci, iobase, target, 0);
+
+ scsi_rep_luns_scan(&llun0.drive, esp_scsi_add_lun);
+}
+
+static void
+init_esp_scsi(void *data)
+{
+ struct pci_device *pci = data;
+ u32 iobase = pci_enable_iobar(pci, PCI_BASE_ADDRESS_0);
+ if (!iobase)
+ return;
+ pci_enable_busmaster(pci);
+
+ dprintf(1, "found esp at %pP, io @ %x\n", pci, iobase);
+
+ // reset
+ outb(ESP_CMD_RESET, iobase + ESP_CMD);
+
+ int i;
+ for (i = 0; i <= 7; i++)
+ esp_scsi_scan_target(pci, iobase, i);
+}
+
+void
+esp_scsi_setup(void)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_ESP_SCSI || !runningOnQEMU())
+ return;
+
+ dprintf(3, "init esp\n");
+
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->vendor != PCI_VENDOR_ID_AMD
+ || pci->device != PCI_DEVICE_ID_AMD_SCSI)
+ continue;
+ run_thread(init_esp_scsi, pci);
+ }
+}
diff --git a/roms/seabios-hppa/src/hw/esp-scsi.h b/roms/seabios-hppa/src/hw/esp-scsi.h
new file mode 100644
index 000000000..0616d14b1
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/esp-scsi.h
@@ -0,0 +1,8 @@
+#ifndef __ESP_SCSI_H
+#define __ESP_SCSI_H
+
+struct disk_op_s;
+int esp_scsi_process_op(struct disk_op_s *op);
+void esp_scsi_setup(void);
+
+#endif /* __ESP_SCSI_H */
diff --git a/roms/seabios-hppa/src/hw/floppy.c b/roms/seabios-hppa/src/hw/floppy.c
new file mode 100644
index 000000000..9e6647d4e
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/floppy.c
@@ -0,0 +1,741 @@
+// 16bit code to access floppy drives.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // SET_BDA
+#include "block.h" // struct drive_s
+#include "bregs.h" // struct bregs
+#include "config.h" // CONFIG_FLOPPY
+#include "malloc.h" // malloc_fseg
+#include "output.h" // dprintf
+#include "pcidevice.h" // pci_find_class
+#include "pci_ids.h" // PCI_CLASS_BRIDGE_ISA
+#include "pic.h" // pic_eoi1
+#include "romfile.h" // romfile_loadint
+#include "rtc.h" // rtc_read
+#include "stacks.h" // yield
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // timer_calc
+
+#define PORT_FD_BASE 0x03f0
+#define PORT_FD_DOR 0x03f2
+#define PORT_FD_STATUS 0x03f4
+#define PORT_FD_DATA 0x03f5
+#define PORT_FD_DIR 0x03f7
+
+#define FLOPPY_SIZE_CODE 0x02 // 512 byte sectors
+#define FLOPPY_DATALEN 0xff // Not used - because size code is 0x02
+#define FLOPPY_MOTOR_TICKS 37 // ~2 seconds
+#define FLOPPY_FILLBYTE 0xf6
+#define FLOPPY_GAPLEN 0x1B
+#define FLOPPY_FORMAT_GAPLEN 0x6c
+#define FLOPPY_PIO_TIMEOUT 1000
+#define FLOPPY_IRQ_TIMEOUT 5000
+#define FLOPPY_SPECIFY1 0xAF // step rate 12ms, head unload 240ms
+#define FLOPPY_SPECIFY2 0x02 // head load time 4ms, DMA used
+#define FLOPPY_STARTUP_TIME 8 // 1 second
+
+#define FLOPPY_DOR_MOTOR_D 0x80 // Set to turn drive 3's motor ON
+#define FLOPPY_DOR_MOTOR_C 0x40 // Set to turn drive 2's motor ON
+#define FLOPPY_DOR_MOTOR_B 0x20 // Set to turn drive 1's motor ON
+#define FLOPPY_DOR_MOTOR_A 0x10 // Set to turn drive 0's motor ON
+#define FLOPPY_DOR_MOTOR_MASK 0xf0
+#define FLOPPY_DOR_IRQ 0x08 // Set to enable IRQs and DMA
+#define FLOPPY_DOR_RESET 0x04 // Clear = enter reset mode, Set = normal operation
+#define FLOPPY_DOR_DSEL_MASK 0x03 // "Select" drive number for next access
+
+// New diskette parameter table adding 3 parameters from IBM
+// Since no provisions are made for multiple drive types, most
+// values in this table are ignored. I set parameters for 1.44M
+// floppy here
+struct floppy_ext_dbt_s diskette_param_table2 VARFSEG = {
+ .dbt = {
+ .specify1 = FLOPPY_SPECIFY1,
+ .specify2 = FLOPPY_SPECIFY2,
+ .shutoff_ticks = FLOPPY_MOTOR_TICKS, // ~2 seconds
+ .bps_code = FLOPPY_SIZE_CODE,
+ .sectors = 18,
+ .interblock_len = FLOPPY_GAPLEN,
+ .data_len = FLOPPY_DATALEN,
+ .gap_len = FLOPPY_FORMAT_GAPLEN,
+ .fill_byte = FLOPPY_FILLBYTE,
+ .settle_time = 0x0F, // 15ms
+ .startup_time = FLOPPY_STARTUP_TIME,
+ },
+ .max_track = 79, // maximum track
+ .data_rate = 0, // data transfer rate
+ .drive_type = 4, // drive type in cmos
+};
+
+struct floppyinfo_s {
+ struct chs_s chs;
+ u8 floppy_size;
+ u8 data_rate;
+};
+
+#define FLOPPY_SIZE_525 0x01
+#define FLOPPY_SIZE_350 0x02
+
+#define FLOPPY_RATE_500K 0x00
+#define FLOPPY_RATE_300K 0x01
+#define FLOPPY_RATE_250K 0x02
+#define FLOPPY_RATE_1M 0x03
+
+struct floppyinfo_s FloppyInfo[] VARFSEG = {
+ // Unknown
+ { {0, 0, 0}, 0x00, 0x00},
+ // 1 - 360KB, 5.25" - 2 heads, 40 tracks, 9 sectors
+ { {2, 40, 9}, FLOPPY_SIZE_525, FLOPPY_RATE_300K},
+ // 2 - 1.2MB, 5.25" - 2 heads, 80 tracks, 15 sectors
+ { {2, 80, 15}, FLOPPY_SIZE_525, FLOPPY_RATE_500K},
+ // 3 - 720KB, 3.5" - 2 heads, 80 tracks, 9 sectors
+ { {2, 80, 9}, FLOPPY_SIZE_350, FLOPPY_RATE_250K},
+ // 4 - 1.44MB, 3.5" - 2 heads, 80 tracks, 18 sectors
+ { {2, 80, 18}, FLOPPY_SIZE_350, FLOPPY_RATE_500K},
+ // 5 - 2.88MB, 3.5" - 2 heads, 80 tracks, 36 sectors
+ { {2, 80, 36}, FLOPPY_SIZE_350, FLOPPY_RATE_1M},
+ // 6 - 160k, 5.25" - 1 heads, 40 tracks, 8 sectors
+ { {1, 40, 8}, FLOPPY_SIZE_525, FLOPPY_RATE_250K},
+ // 7 - 180k, 5.25" - 1 heads, 40 tracks, 9 sectors
+ { {1, 40, 9}, FLOPPY_SIZE_525, FLOPPY_RATE_300K},
+ // 8 - 320k, 5.25" - 2 heads, 40 tracks, 8 sectors
+ { {2, 40, 8}, FLOPPY_SIZE_525, FLOPPY_RATE_250K},
+};
+
+struct drive_s *
+init_floppy(int floppyid, int ftype)
+{
+ if (ftype <= 0 || ftype >= ARRAY_SIZE(FloppyInfo)) {
+ dprintf(1, "Bad floppy type %d\n", ftype);
+ return NULL;
+ }
+
+ struct drive_s *drive = malloc_fseg(sizeof(*drive));
+ if (!drive) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(drive, 0, sizeof(*drive));
+ drive->cntl_id = floppyid;
+ drive->type = DTYPE_FLOPPY;
+ drive->blksize = DISK_SECTOR_SIZE;
+ drive->floppy_type = ftype;
+ drive->sectors = (u64)-1;
+
+ memcpy(&drive->lchs, &FloppyInfo[ftype].chs
+ , sizeof(FloppyInfo[ftype].chs));
+ return drive;
+}
+
+static void
+addFloppy(int floppyid, int ftype)
+{
+ struct drive_s *drive = init_floppy(floppyid, ftype);
+ if (!drive)
+ return;
+ char *desc = znprintf(MAXDESCSIZE, "Floppy [drive %c]", 'A' + floppyid);
+ struct pci_device *pci = pci_find_class(PCI_CLASS_BRIDGE_ISA); /* isa-to-pci bridge */
+ int prio = bootprio_find_fdc_device(pci, PORT_FD_BASE, floppyid);
+ boot_add_floppy(drive, desc, prio);
+}
+
+void
+floppy_setup(void)
+{
+ memcpy(&diskette_param_table, &diskette_param_table2
+ , sizeof(diskette_param_table));
+ SET_IVT(0x1E, SEGOFF(SEG_BIOS
+ , (u32)&diskette_param_table2 - BUILD_BIOS_ADDR));
+
+ if (! CONFIG_FLOPPY)
+ return;
+ dprintf(3, "init floppy drives\n");
+
+ if (CONFIG_QEMU) {
+ u8 type = rtc_read(CMOS_FLOPPY_DRIVE_TYPE);
+ if (type & 0xf0)
+ addFloppy(0, type >> 4);
+ if (type & 0x0f)
+ addFloppy(1, type & 0x0f);
+ } else {
+ u8 type = romfile_loadint("etc/floppy0", 0);
+ if (type)
+ addFloppy(0, type);
+ type = romfile_loadint("etc/floppy1", 0);
+ if (type)
+ addFloppy(1, type);
+ }
+
+ enable_hwirq(6, FUNC16(entry_0e));
+}
+
+// Find a floppy type that matches a given image size.
+int
+find_floppy_type(u32 size)
+{
+ int i;
+ for (i=1; i<ARRAY_SIZE(FloppyInfo); i++) {
+ struct chs_s *c = &FloppyInfo[i].chs;
+ if (c->cylinder * c->head * c->sector * DISK_SECTOR_SIZE == size)
+ return i;
+ }
+ return -1;
+}
+
+
+/****************************************************************
+ * Low-level floppy IO
+ ****************************************************************/
+
+u8 FloppyDOR VARLOW;
+
+static inline u8
+floppy_dor_read(void)
+{
+ return GET_LOW(FloppyDOR);
+}
+
+static inline void
+floppy_dor_write(u8 val)
+{
+ outb(val, PORT_FD_DOR);
+ SET_LOW(FloppyDOR, val);
+}
+
+static inline void
+floppy_dor_mask(u8 off, u8 on)
+{
+ floppy_dor_write((floppy_dor_read() & ~off) | on);
+}
+
+static void
+floppy_disable_controller(void)
+{
+ dprintf(2, "Floppy_disable_controller\n");
+ // Clear the reset bit (enter reset state) and clear 'enable IRQ and DMA'
+ floppy_dor_mask(FLOPPY_DOR_IRQ | FLOPPY_DOR_RESET, 0);
+}
+
+static int
+floppy_wait_irq(void)
+{
+ u8 frs = GET_BDA(floppy_recalibration_status);
+ SET_BDA(floppy_recalibration_status, frs & ~FRS_IRQ);
+ u32 end = timer_calc(FLOPPY_IRQ_TIMEOUT);
+ for (;;) {
+ if (timer_check(end)) {
+ warn_timeout();
+ floppy_disable_controller();
+ return DISK_RET_ETIMEOUT;
+ }
+ frs = GET_BDA(floppy_recalibration_status);
+ if (frs & FRS_IRQ)
+ break;
+ // Could use yield_toirq() here, but that causes issues on
+ // bochs, so use yield() instead.
+ yield();
+ }
+
+ SET_BDA(floppy_recalibration_status, frs & ~FRS_IRQ);
+ return DISK_RET_SUCCESS;
+}
+
+// Floppy commands
+#define FCF_WAITIRQ 0x10000
+#define FC_CHECKIRQ (0x08 | (0<<8) | (2<<12))
+#define FC_SEEK (0x0f | (2<<8) | (0<<12) | FCF_WAITIRQ)
+#define FC_RECALIBRATE (0x07 | (1<<8) | (0<<12) | FCF_WAITIRQ)
+#define FC_READID (0x4a | (1<<8) | (7<<12) | FCF_WAITIRQ)
+#define FC_READ (0xe6 | (8<<8) | (7<<12) | FCF_WAITIRQ)
+#define FC_WRITE (0xc5 | (8<<8) | (7<<12) | FCF_WAITIRQ)
+#define FC_FORMAT (0x4d | (5<<8) | (7<<12) | FCF_WAITIRQ)
+#define FC_SPECIFY (0x03 | (2<<8) | (0<<12))
+
+// Send the specified command and it's parameters to the floppy controller.
+static int
+floppy_pio(int command, u8 *param)
+{
+ dprintf(9, "Floppy pio command %x\n", command);
+ // Send command and parameters to controller.
+ u32 end = timer_calc(FLOPPY_PIO_TIMEOUT);
+ int send = (command >> 8) & 0xf;
+ int i = 0;
+ for (;;) {
+ u8 sts = inb(PORT_FD_STATUS);
+ if (!(sts & 0x80)) {
+ if (timer_check(end)) {
+ warn_timeout();
+ floppy_disable_controller();
+ return DISK_RET_ETIMEOUT;
+ }
+ yield();
+ continue;
+ }
+ if (sts & 0x40) {
+ floppy_disable_controller();
+ return DISK_RET_ECONTROLLER;
+ }
+ if (i == 0)
+ outb(command & 0xff, PORT_FD_DATA);
+ else
+ outb(param[i-1], PORT_FD_DATA);
+ if (i++ >= send)
+ break;
+ }
+
+ // Wait for command to complete.
+ if (command & FCF_WAITIRQ) {
+ int ret = floppy_wait_irq();
+ if (ret)
+ return ret;
+ }
+
+ // Read response from controller.
+ end = timer_calc(FLOPPY_PIO_TIMEOUT);
+ int receive = (command >> 12) & 0xf;
+ i = 0;
+ for (;;) {
+ u8 sts = inb(PORT_FD_STATUS);
+ if (!(sts & 0x80)) {
+ if (timer_check(end)) {
+ warn_timeout();
+ floppy_disable_controller();
+ return DISK_RET_ETIMEOUT;
+ }
+ yield();
+ continue;
+ }
+ if (i >= receive) {
+ if (sts & 0x40) {
+ floppy_disable_controller();
+ return DISK_RET_ECONTROLLER;
+ }
+ break;
+ }
+ if (!(sts & 0x40)) {
+ floppy_disable_controller();
+ return DISK_RET_ECONTROLLER;
+ }
+ param[i++] = inb(PORT_FD_DATA);
+ }
+
+ return DISK_RET_SUCCESS;
+}
+
+static int
+floppy_enable_controller(void)
+{
+ dprintf(2, "Floppy_enable_controller\n");
+ // Clear the reset bit (enter reset state), but set 'enable IRQ and DMA'
+ floppy_dor_mask(FLOPPY_DOR_RESET, FLOPPY_DOR_IRQ);
+ // Real hardware needs a 4 microsecond delay
+ usleep(4);
+ // Set the reset bit (normal operation) and keep 'enable IRQ and DMA' on
+ floppy_dor_mask(0, FLOPPY_DOR_IRQ | FLOPPY_DOR_RESET);
+ int ret = floppy_wait_irq();
+ if (ret)
+ return ret;
+
+ // After the interrupt is received, send 4 SENSE INTERRUPT commands to
+ // clear the interrupt status for each of the four logical drives,
+ // supported by the controller.
+ // See section 7.4 - "Drive Polling" of the Intel 82077AA datasheet for
+ // a more detailed description of why this voodoo needs to be done.
+ // Without this, initialization fails on real controllers (but still works
+ // in QEMU)
+ u8 param[2];
+ int i;
+ for (i=0; i<4; i++) {
+ ret = floppy_pio(FC_CHECKIRQ, param);
+ if (ret)
+ return ret;
+ }
+ return DISK_RET_SUCCESS;
+}
+
+// Activate a drive and send a command to it.
+static int
+floppy_drive_pio(u8 floppyid, int command, u8 *param)
+{
+ // Enable controller if it isn't running.
+ if (!(floppy_dor_read() & FLOPPY_DOR_RESET)) {
+ int ret = floppy_enable_controller();
+ if (ret)
+ return ret;
+ }
+
+ // set the disk motor timeout value of INT 08 to the highest value
+ SET_BDA(floppy_motor_counter, 255);
+
+ // Check if the motor is already running
+ u8 motor_mask = FLOPPY_DOR_MOTOR_A << floppyid;
+ int motor_already_running = floppy_dor_read() & motor_mask;
+
+ // Turn on motor of selected drive, DMA & int enabled, normal operation
+ floppy_dor_write(motor_mask | FLOPPY_DOR_IRQ | FLOPPY_DOR_RESET | floppyid);
+
+ // If the motor was just started, wait for it to get up to speed
+ if (!motor_already_running && !CONFIG_QEMU)
+ msleep(FLOPPY_STARTUP_TIME * 125);
+
+ // Send command.
+ int ret = floppy_pio(command, param);
+ SET_BDA(floppy_motor_counter, FLOPPY_MOTOR_TICKS); // reset motor timeout
+ if (ret)
+ return ret;
+
+ // Check IRQ command is needed after irq commands with no results
+ if ((command & FCF_WAITIRQ) && ((command >> 12) & 0xf) == 0)
+ return floppy_pio(FC_CHECKIRQ, param);
+ return DISK_RET_SUCCESS;
+}
+
+
+/****************************************************************
+ * Floppy media sense and seeking
+ ****************************************************************/
+
+static int
+floppy_drive_recal(u8 floppyid)
+{
+ dprintf(2, "Floppy_drive_recal %d\n", floppyid);
+ // send Recalibrate command to controller
+ u8 param[2];
+ param[0] = floppyid;
+ int ret = floppy_drive_pio(floppyid, FC_RECALIBRATE, param);
+ if (ret)
+ return ret;
+
+ u8 frs = GET_BDA(floppy_recalibration_status);
+ SET_BDA(floppy_recalibration_status, frs | (1<<floppyid));
+ SET_BDA(floppy_track[floppyid], 0);
+ return DISK_RET_SUCCESS;
+}
+
+static int
+floppy_drive_specify(void)
+{
+ u8 param[2];
+ param[0] = FLOPPY_SPECIFY1;
+ param[1] = FLOPPY_SPECIFY2;
+ return floppy_pio(FC_SPECIFY, param);
+}
+
+static int
+floppy_drive_readid(u8 floppyid, u8 data_rate, u8 head)
+{
+ // Set data rate.
+ outb(data_rate, PORT_FD_DIR);
+
+ // send Read Sector Id command
+ u8 param[7];
+ param[0] = (head << 2) | floppyid; // HD DR1 DR2
+ int ret = floppy_drive_pio(floppyid, FC_READID, param);
+ if (ret)
+ return ret;
+ if (param[0] & 0xc0)
+ return -1;
+ return 0;
+}
+
+static int
+floppy_media_sense(struct drive_s *drive_gf)
+{
+ u8 ftype = GET_GLOBALFLAT(drive_gf->floppy_type), stype = ftype;
+ u8 floppyid = GET_GLOBALFLAT(drive_gf->cntl_id);
+
+ u8 data_rate = GET_GLOBAL(FloppyInfo[stype].data_rate);
+ int ret = floppy_drive_readid(floppyid, data_rate, 0);
+ if (ret) {
+ // Attempt media sense.
+ for (stype=1; ; stype++) {
+ if (stype >= ARRAY_SIZE(FloppyInfo))
+ return DISK_RET_EMEDIA;
+ if (stype==ftype
+ || (GET_GLOBAL(FloppyInfo[stype].floppy_size)
+ != GET_GLOBAL(FloppyInfo[ftype].floppy_size))
+ || (GET_GLOBAL(FloppyInfo[stype].chs.head)
+ > GET_GLOBAL(FloppyInfo[ftype].chs.head))
+ || (GET_GLOBAL(FloppyInfo[stype].chs.cylinder)
+ > GET_GLOBAL(FloppyInfo[ftype].chs.cylinder))
+ || (GET_GLOBAL(FloppyInfo[stype].chs.sector)
+ > GET_GLOBAL(FloppyInfo[ftype].chs.sector)))
+ continue;
+ data_rate = GET_GLOBAL(FloppyInfo[stype].data_rate);
+ ret = floppy_drive_readid(floppyid, data_rate, 0);
+ if (!ret)
+ break;
+ }
+ }
+ dprintf(2, "Floppy_media_sense on drive %d found rate %d\n"
+ , floppyid, data_rate);
+
+ u8 old_data_rate = GET_BDA(floppy_media_state[floppyid]) >> 6;
+ SET_BDA(floppy_last_data_rate, (old_data_rate<<2) | (data_rate<<6));
+ u8 media = (stype == 1 ? 0x04 : (stype == 2 ? 0x05 : 0x07));
+ u8 fms = (data_rate<<6) | FMS_MEDIA_DRIVE_ESTABLISHED | media;
+ if (GET_GLOBAL(FloppyInfo[stype].chs.cylinder)
+ < GET_GLOBAL(FloppyInfo[ftype].chs.cylinder))
+ fms |= FMS_DOUBLE_STEPPING;
+ SET_BDA(floppy_media_state[floppyid], fms);
+
+ return DISK_RET_SUCCESS;
+}
+
+// Prepare a floppy for a data transfer.
+static int
+floppy_prep(struct drive_s *drive_gf, u8 cylinder)
+{
+ u8 floppyid = GET_GLOBALFLAT(drive_gf->cntl_id);
+ if (!(GET_BDA(floppy_recalibration_status) & (1<<floppyid)) ||
+ !(GET_BDA(floppy_media_state[floppyid]) & FMS_MEDIA_DRIVE_ESTABLISHED)) {
+ // Recalibrate drive.
+ int ret = floppy_drive_recal(floppyid);
+ if (ret)
+ return ret;
+
+ // Sense media.
+ ret = floppy_media_sense(drive_gf);
+ if (ret)
+ return ret;
+
+ // Execute a SPECIFY command (sets the Step Rate Time,
+ // Head Load Time, Head Unload Time and the DMA enable/disable bit).
+ ret = floppy_drive_specify();
+ if (ret)
+ return ret;
+ }
+
+ // Seek to cylinder if needed.
+ u8 lastcyl = GET_BDA(floppy_track[floppyid]);
+ if (cylinder != lastcyl) {
+ u8 param[2];
+ param[0] = floppyid;
+ param[1] = cylinder;
+ int ret = floppy_drive_pio(floppyid, FC_SEEK, param);
+ if (ret)
+ return ret;
+ SET_BDA(floppy_track[floppyid], cylinder);
+ }
+
+ return DISK_RET_SUCCESS;
+}
+
+
+/****************************************************************
+ * Floppy DMA transfer
+ ****************************************************************/
+
+// Perform a floppy transfer command (setup DMA and issue PIO).
+static int
+floppy_dma_cmd(struct disk_op_s *op, int count, int command, u8 *param)
+{
+ // Setup DMA controller
+ int isWrite = command != FC_READ;
+ int ret = dma_floppy((u32)op->buf_fl, count, isWrite);
+ if (ret)
+ return DISK_RET_EBOUNDARY;
+
+ // Invoke floppy controller
+ u8 floppyid = GET_GLOBALFLAT(op->drive_fl->cntl_id);
+ ret = floppy_drive_pio(floppyid, command, param);
+ if (ret)
+ return ret;
+
+ // Populate floppy_return_status in BDA
+ int i;
+ for (i=0; i<7; i++)
+ SET_BDA(floppy_return_status[i], param[i]);
+
+ if (param[0] & 0xc0) {
+ if (param[1] & 0x02)
+ return DISK_RET_EWRITEPROTECT;
+ dprintf(1, "floppy error: %02x %02x %02x %02x %02x %02x %02x\n"
+ , param[0], param[1], param[2], param[3]
+ , param[4], param[5], param[6]);
+ return DISK_RET_ECONTROLLER;
+ }
+
+ return DISK_RET_SUCCESS;
+}
+
+
+/****************************************************************
+ * Floppy handlers
+ ****************************************************************/
+
+static struct chs_s
+lba2chs(struct disk_op_s *op)
+{
+ struct chs_s res = { };
+
+ u32 tmp = op->lba;
+ u16 nls = GET_GLOBALFLAT(op->drive_fl->lchs.sector);
+ res.sector = (tmp % nls) + 1;
+
+ tmp /= nls;
+ u16 nlh = GET_GLOBALFLAT(op->drive_fl->lchs.head);
+ res.head = tmp % nlh;
+
+ tmp /= nlh;
+ res.cylinder = tmp;
+
+ return res;
+}
+
+// diskette controller reset
+static int
+floppy_reset(struct disk_op_s *op)
+{
+ SET_BDA(floppy_recalibration_status, 0);
+ SET_BDA(floppy_media_state[0], 0);
+ SET_BDA(floppy_media_state[1], 0);
+ SET_BDA(floppy_track[0], 0);
+ SET_BDA(floppy_track[1], 0);
+ SET_BDA(floppy_last_data_rate, 0);
+ floppy_disable_controller();
+ return floppy_enable_controller();
+}
+
+// Read Diskette Sectors
+static int
+floppy_read(struct disk_op_s *op)
+{
+ struct chs_s chs = lba2chs(op);
+ int ret = floppy_prep(op->drive_fl, chs.cylinder);
+ if (ret)
+ return ret;
+
+ // send read-normal-data command to controller
+ u8 floppyid = GET_GLOBALFLAT(op->drive_fl->cntl_id);
+ u8 param[8];
+ param[0] = (chs.head << 2) | floppyid; // HD DR1 DR2
+ param[1] = chs.cylinder;
+ param[2] = chs.head;
+ param[3] = chs.sector;
+ param[4] = FLOPPY_SIZE_CODE;
+ param[5] = chs.sector + op->count - 1; // last sector to read on track
+ param[6] = FLOPPY_GAPLEN;
+ param[7] = FLOPPY_DATALEN;
+ return floppy_dma_cmd(op, op->count * DISK_SECTOR_SIZE, FC_READ, param);
+}
+
+// Write Diskette Sectors
+static int
+floppy_write(struct disk_op_s *op)
+{
+ struct chs_s chs = lba2chs(op);
+ int ret = floppy_prep(op->drive_fl, chs.cylinder);
+ if (ret)
+ return ret;
+
+ // send write-normal-data command to controller
+ u8 floppyid = GET_GLOBALFLAT(op->drive_fl->cntl_id);
+ u8 param[8];
+ param[0] = (chs.head << 2) | floppyid; // HD DR1 DR2
+ param[1] = chs.cylinder;
+ param[2] = chs.head;
+ param[3] = chs.sector;
+ param[4] = FLOPPY_SIZE_CODE;
+ param[5] = chs.sector + op->count - 1; // last sector to write on track
+ param[6] = FLOPPY_GAPLEN;
+ param[7] = FLOPPY_DATALEN;
+ return floppy_dma_cmd(op, op->count * DISK_SECTOR_SIZE, FC_WRITE, param);
+}
+
+// Verify Diskette Sectors
+static int
+floppy_verify(struct disk_op_s *op)
+{
+ struct chs_s chs = lba2chs(op);
+ int ret = floppy_prep(op->drive_fl, chs.cylinder);
+ if (ret)
+ return ret;
+
+ // This command isn't implemented - just return success.
+ return DISK_RET_SUCCESS;
+}
+
+// format diskette track
+static int
+floppy_format(struct disk_op_s *op)
+{
+ struct chs_s chs = lba2chs(op);
+ int ret = floppy_prep(op->drive_fl, chs.cylinder);
+ if (ret)
+ return ret;
+
+ // send format-track command to controller
+ u8 floppyid = GET_GLOBALFLAT(op->drive_fl->cntl_id);
+ u8 param[7];
+ param[0] = (chs.head << 2) | floppyid; // HD DR1 DR2
+ param[1] = FLOPPY_SIZE_CODE;
+ param[2] = op->count; // number of sectors per track
+ param[3] = FLOPPY_FORMAT_GAPLEN;
+ param[4] = FLOPPY_FILLBYTE;
+ return floppy_dma_cmd(op, op->count * 4, FC_FORMAT, param);
+}
+
+int
+floppy_process_op(struct disk_op_s *op)
+{
+ if (!CONFIG_FLOPPY)
+ return 0;
+
+ switch (op->command) {
+ case CMD_RESET:
+ return floppy_reset(op);
+ case CMD_READ:
+ return floppy_read(op);
+ case CMD_WRITE:
+ return floppy_write(op);
+ case CMD_VERIFY:
+ return floppy_verify(op);
+ case CMD_FORMAT:
+ return floppy_format(op);
+ default:
+ return DISK_RET_EPARAM;
+ }
+}
+
+
+/****************************************************************
+ * HW irqs
+ ****************************************************************/
+
+// INT 0Eh Diskette Hardware ISR Entry Point
+void VISIBLE16
+handle_0e(void)
+{
+ if (! CONFIG_FLOPPY)
+ return;
+ debug_isr(DEBUG_ISR_0e);
+
+ // diskette interrupt has occurred
+ u8 frs = GET_BDA(floppy_recalibration_status);
+ SET_BDA(floppy_recalibration_status, frs | FRS_IRQ);
+
+ pic_eoi1();
+}
+
+// Called from int08 handler.
+void
+floppy_tick(void)
+{
+ if (! CONFIG_FLOPPY)
+ return;
+
+ // time to turn off drive(s)?
+ u8 fcount = GET_BDA(floppy_motor_counter);
+ if (fcount) {
+ fcount--;
+ SET_BDA(floppy_motor_counter, fcount);
+ if (fcount == 0)
+ // turn motor(s) off
+ floppy_dor_mask(FLOPPY_DOR_MOTOR_MASK, 0);
+ }
+}
diff --git a/roms/seabios-hppa/src/hw/lsi-scsi.c b/roms/seabios-hppa/src/hw/lsi-scsi.c
new file mode 100644
index 000000000..5583bd69a
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/lsi-scsi.c
@@ -0,0 +1,227 @@
+// (qemu-emulated) lsi53c895a boot support.
+//
+// Copyright (C) 2012 Red Hat Inc.
+//
+// Authors:
+// Gerd Hoffmann <kraxel@redhat.com>
+//
+// based on virtio-scsi.c which is written by:
+// Paolo Bonzini <pbonzini@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBALFLAT
+#include "block.h" // struct drive_s
+#include "blockcmd.h" // scsi_drive_setup
+#include "config.h" // CONFIG_*
+#include "byteorder.h" // cpu_to_*
+#include "fw/paravirt.h" // runningOnQEMU
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "stacks.h" // run_thread
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // usleep
+
+#define LSI_REG_DSTAT 0x0c
+#define LSI_REG_ISTAT0 0x14
+#define LSI_REG_DSP0 0x2c
+#define LSI_REG_DSP1 0x2d
+#define LSI_REG_DSP2 0x2e
+#define LSI_REG_DSP3 0x2f
+#define LSI_REG_SIST0 0x42
+#define LSI_REG_SIST1 0x43
+
+#define LSI_ISTAT0_DIP 0x01
+#define LSI_ISTAT0_SIP 0x02
+#define LSI_ISTAT0_INTF 0x04
+#define LSI_ISTAT0_CON 0x08
+#define LSI_ISTAT0_SEM 0x10
+#define LSI_ISTAT0_SIGP 0x20
+#define LSI_ISTAT0_SRST 0x40
+#define LSI_ISTAT0_ABRT 0x80
+
+struct lsi_lun_s {
+ struct drive_s drive;
+ struct pci_device *pci;
+ u32 iobase;
+ u8 target;
+ u8 lun;
+};
+
+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_fl, 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 = ((scsi_is_read(op) ? 0x01000000 : 0x00000000) |
+ (op->count * blocksize));
+ u8 msgout[] = {
+ 0x80 | lun, // select lun
+ 0x08,
+ };
+ u8 status = 0xff;
+ u8 msgin_tmp[2];
+ u8 msgin = 0xff;
+
+ u32 script[] = {
+ /* select target, send scsi command */
+ 0x40000000 | target << 16, // select target
+ 0x00000000,
+ 0x06000001, // msgout
+ (u32)MAKE_FLATPTR(GET_SEG(SS), &msgout),
+ 0x02000010, // scsi command
+ (u32)MAKE_FLATPTR(GET_SEG(SS), cdbcmd),
+
+ /* handle disconnect */
+ 0x87820000, // phase == msgin ?
+ 0x00000018,
+ 0x07000002, // msgin
+ (u32)MAKE_FLATPTR(GET_SEG(SS), &msgin_tmp),
+ 0x50000000, // re-select
+ 0x00000000,
+ 0x07000002, // msgin
+ (u32)MAKE_FLATPTR(GET_SEG(SS), &msgin_tmp),
+
+ /* dma data, get status, raise irq */
+ dma, // dma data
+ (u32)op->buf_fl,
+ 0x03000001, // status
+ (u32)MAKE_FLATPTR(GET_SEG(SS), &status),
+ 0x07000001, // msgin
+ (u32)MAKE_FLATPTR(GET_SEG(SS), &msgin),
+ 0x98080000, // dma irq
+ 0x00000000,
+ };
+ u32 dsp = (u32)MAKE_FLATPTR(GET_SEG(SS), &script);
+
+ /* convert to little endian for PCI */
+ convert_to_le32(script, sizeof(script));
+
+ outb(dsp & 0xff, iobase + LSI_REG_DSP0);
+ outb((dsp >> 8) & 0xff, iobase + LSI_REG_DSP1);
+ outb((dsp >> 16) & 0xff, iobase + LSI_REG_DSP2);
+ outb((dsp >> 24) & 0xff, iobase + LSI_REG_DSP3);
+
+ for (;;) {
+ u8 dstat = inb(iobase + LSI_REG_DSTAT);
+ u8 sist0 = inb(iobase + LSI_REG_SIST0);
+ u8 sist1 = inb(iobase + LSI_REG_SIST1);
+ if (sist0 || sist1) {
+ goto fail;
+ }
+ if (dstat & 0x04) {
+ break;
+ }
+ usleep(5);
+ }
+
+ if (msgin == 0 && status == 0) {
+ return DISK_RET_SUCCESS;
+ }
+
+fail:
+ return DISK_RET_EBADTRACK;
+}
+
+static void
+lsi_scsi_init_lun(struct lsi_lun_s *llun, struct pci_device *pci, u32 iobase,
+ u8 target, u8 lun)
+{
+ memset(llun, 0, sizeof(*llun));
+ llun->drive.type = DTYPE_LSI_SCSI;
+ llun->drive.cntl_id = pci->bdf;
+ llun->pci = pci;
+ llun->target = target;
+ llun->lun = lun;
+ llun->iobase = iobase;
+}
+
+static int
+lsi_scsi_add_lun(u32 lun, struct drive_s *tmpl_drv)
+{
+ struct lsi_lun_s *tmpl_llun =
+ container_of(tmpl_drv, struct lsi_lun_s, drive);
+ struct lsi_lun_s *llun = malloc_fseg(sizeof(*llun));
+ if (!llun) {
+ warn_noalloc();
+ return -1;
+ }
+ lsi_scsi_init_lun(llun, tmpl_llun->pci, tmpl_llun->iobase,
+ tmpl_llun->target, lun);
+
+ boot_lchs_find_scsi_device(llun->pci, llun->target, llun->lun,
+ &(llun->drive.lchs));
+ char *name = znprintf(MAXDESCSIZE, "lsi %pP %d:%d",
+ llun->pci, llun->target, llun->lun);
+ int prio = bootprio_find_scsi_device(llun->pci, llun->target, llun->lun);
+ int ret = scsi_drive_setup(&llun->drive, name, prio, llun->target, llun->lun);
+ free(name);
+ if (ret)
+ goto fail;
+ return 0;
+
+fail:
+ free(llun);
+ return -1;
+}
+
+static void
+lsi_scsi_scan_target(struct pci_device *pci, u32 iobase, u8 target)
+{
+ struct lsi_lun_s llun0;
+
+ lsi_scsi_init_lun(&llun0, pci, iobase, target, 0);
+
+ if (scsi_rep_luns_scan(&llun0.drive, lsi_scsi_add_lun) < 0)
+ scsi_sequential_scan(&llun0.drive, 8, lsi_scsi_add_lun);
+}
+
+static void
+init_lsi_scsi(void *data)
+{
+ struct pci_device *pci = data;
+ u32 iobase = pci_enable_iobar(pci, PCI_BASE_ADDRESS_0);
+ if (!iobase)
+ return;
+ pci_enable_busmaster(pci);
+
+ dprintf(1, "found lsi53c895a at %pP, io @ %x\n", pci, iobase);
+
+ // reset
+ outb(LSI_ISTAT0_SRST, iobase + LSI_REG_ISTAT0);
+
+ int i;
+ for (i = 0; i < 7; i++)
+ lsi_scsi_scan_target(pci, iobase, i);
+}
+
+void
+lsi_scsi_setup(void)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_LSI_SCSI || !runningOnQEMU())
+ return;
+
+ dprintf(3, "init lsi53c895a\n");
+
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->vendor != PCI_VENDOR_ID_LSI_LOGIC
+ || pci->device != PCI_DEVICE_ID_LSI_53C895A)
+ continue;
+ run_thread(init_lsi_scsi, pci);
+ }
+}
diff --git a/roms/seabios-hppa/src/hw/lsi-scsi.h b/roms/seabios-hppa/src/hw/lsi-scsi.h
new file mode 100644
index 000000000..6baf4a162
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/lsi-scsi.h
@@ -0,0 +1,8 @@
+#ifndef __LSI_SCSI_H
+#define __LSI_SCSI_H
+
+struct disk_op_s;
+int lsi_scsi_process_op(struct disk_op_s *op);
+void lsi_scsi_setup(void);
+
+#endif /* __LSI_SCSI_H */
diff --git a/roms/seabios-hppa/src/hw/megasas.c b/roms/seabios-hppa/src/hw/megasas.c
new file mode 100644
index 000000000..94331d662
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/megasas.c
@@ -0,0 +1,406 @@
+// MegaRAID SAS boot support.
+//
+// Copyright (C) 2012 Hannes Reinecke, SUSE Linux Products GmbH
+//
+// Authors:
+// Hannes Reinecke <hare@suse.de>
+//
+// based on virtio-scsi.c which is written by:
+// Paolo Bonzini <pbonzini@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBALFLAT
+#include "block.h" // struct drive_s
+#include "blockcmd.h" // scsi_drive_setup
+#include "config.h" // CONFIG_*
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "pci.h" // pci_config_readl
+#include "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_DEVICE_ID_XXX
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "stacks.h" // yield
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // timer_calc
+
+#define MFI_DB 0x0 // Doorbell
+#define MFI_OMSG0 0x18 // Outbound message 0
+#define MFI_IDB 0x20 // Inbound doorbell
+#define MFI_ODB 0x2c // Outbound doorbell
+#define MFI_IQP 0x40 // Inbound queue port
+#define MFI_OSP0 0xb0 // Outbound scratch pad0
+#define MFI_IQPL 0xc0 // Inbound queue port (low bytes)
+#define MFI_IQPH 0xc4 // Inbound queue port (high bytes)
+
+#define MFI_STATE_MASK 0xf0000000
+#define MFI_STATE_WAIT_HANDSHAKE 0x60000000
+#define MFI_STATE_BOOT_MESSAGE_PENDING 0x90000000
+#define MFI_STATE_READY 0xb0000000
+#define MFI_STATE_OPERATIONAL 0xc0000000
+#define MFI_STATE_FAULT 0xf0000000
+
+/* MFI Commands */
+typedef enum {
+ MFI_CMD_INIT = 0x00,
+ MFI_CMD_LD_READ,
+ MFI_CMD_LD_WRITE,
+ MFI_CMD_LD_SCSI_IO,
+ MFI_CMD_PD_SCSI_IO,
+ MFI_CMD_DCMD,
+ MFI_CMD_ABORT,
+ MFI_CMD_SMP,
+ MFI_CMD_STP
+} mfi_cmd_t;
+
+struct megasas_cmd_frame {
+ u8 cmd; /*00h */
+ u8 sense_len; /*01h */
+ u8 cmd_status; /*02h */
+ u8 scsi_status; /*03h */
+
+ u8 target_id; /*04h */
+ u8 lun; /*05h */
+ u8 cdb_len; /*06h */
+ u8 sge_count; /*07h */
+
+ u32 context; /*08h */
+ u32 context_64; /*0Ch */
+
+ u16 flags; /*10h */
+ u16 timeout; /*12h */
+ u32 data_xfer_len; /*14h */
+
+ union {
+ struct {
+ u32 opcode; /*18h */
+ u8 mbox[12]; /*1Ch */
+ u32 sgl_addr; /*28h */
+ u32 sgl_len; /*32h */
+ u32 pad; /*34h */
+ } dcmd;
+ struct {
+ u32 sense_buf_lo; /*18h */
+ u32 sense_buf_hi; /*1Ch */
+ u8 cdb[16]; /*20h */
+ u32 sgl_addr; /*30h */
+ u32 sgl_len; /*34h */
+ } pthru;
+ struct {
+ u8 pad[22]; /*18h */
+ } gen;
+ };
+} __attribute__ ((packed));
+
+struct mfi_ld_list_s {
+ u32 count;
+ u32 reserved_0;
+ struct {
+ u8 target;
+ u8 lun;
+ u16 seq;
+ u8 state;
+ u8 reserved_1[3];
+ u64 size;
+ } lds[64];
+} __attribute__ ((packed));
+
+#define MEGASAS_POLL_TIMEOUT 60000 // 60 seconds polling timeout
+
+struct megasas_lun_s {
+ struct drive_s drive;
+ struct megasas_cmd_frame *frame;
+ u32 iobase;
+ u16 pci_id;
+ u8 target;
+ u8 lun;
+};
+
+static int megasas_fire_cmd(u16 pci_id, u32 ioaddr,
+ struct megasas_cmd_frame *frame)
+{
+ u32 frame_addr = (u32)frame;
+ int frame_count = 1;
+ u8 cmd_state;
+
+ dprintf(2, "Frame 0x%x\n", frame_addr);
+ if (pci_id == PCI_DEVICE_ID_LSI_SAS2004 ||
+ pci_id == PCI_DEVICE_ID_LSI_SAS2008) {
+ outl(0, ioaddr + MFI_IQPH);
+ outl(frame_addr | frame_count << 1 | 1, ioaddr + MFI_IQPL);
+ } else if (pci_id == PCI_DEVICE_ID_DELL_PERC5 ||
+ pci_id == PCI_DEVICE_ID_LSI_SAS1064R ||
+ pci_id == PCI_DEVICE_ID_LSI_VERDE_ZCR) {
+ outl(frame_addr >> 3 | frame_count, ioaddr + MFI_IQP);
+ } else {
+ outl(frame_addr | frame_count << 1 | 1, ioaddr + MFI_IQP);
+ }
+
+ u32 end = timer_calc(MEGASAS_POLL_TIMEOUT);
+ do {
+ for (;;) {
+ cmd_state = GET_LOWFLAT(frame->cmd_status);
+ if (cmd_state != 0xff)
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+ } while (cmd_state == 0xff);
+
+ if (cmd_state == 0 || cmd_state == 0x2d)
+ return 0;
+ dprintf(1, "ERROR: Frame 0x%x, status 0x%x\n", frame_addr, cmd_state);
+ return -1;
+}
+
+int
+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_fl, struct megasas_lun_s, drive);
+ struct megasas_cmd_frame *frame = GET_GLOBALFLAT(mlun_gf->frame);
+ u16 pci_id = GET_GLOBALFLAT(mlun_gf->pci_id);
+ int i;
+
+ memset_fl(frame, 0, sizeof(*frame));
+ SET_LOWFLAT(frame->cmd, MFI_CMD_LD_SCSI_IO);
+ SET_LOWFLAT(frame->cmd_status, 0xFF);
+ SET_LOWFLAT(frame->target_id, GET_GLOBALFLAT(mlun_gf->target));
+ SET_LOWFLAT(frame->lun, GET_GLOBALFLAT(mlun_gf->lun));
+ SET_LOWFLAT(frame->flags, 0x0001);
+ SET_LOWFLAT(frame->data_xfer_len, op->count * blocksize);
+ SET_LOWFLAT(frame->cdb_len, 16);
+
+ for (i = 0; i < 16; i++) {
+ SET_LOWFLAT(frame->pthru.cdb[i], cdb[i]);
+ }
+ dprintf(2, "pthru cmd 0x%x count %d bs %d\n",
+ cdb[0], op->count, blocksize);
+
+ if (op->count) {
+ SET_LOWFLAT(frame->pthru.sgl_addr, (u32)op->buf_fl);
+ SET_LOWFLAT(frame->pthru.sgl_len, op->count * blocksize);
+ SET_LOWFLAT(frame->sge_count, 1);
+ }
+ SET_LOWFLAT(frame->context, (u32)frame);
+
+ if (megasas_fire_cmd(pci_id, GET_GLOBALFLAT(mlun_gf->iobase), frame) == 0)
+ return DISK_RET_SUCCESS;
+
+ dprintf(2, "pthru cmd 0x%x failed\n", cdb[0]);
+ return DISK_RET_EBADTRACK;
+}
+
+static int
+megasas_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun)
+{
+ struct megasas_lun_s *mlun = malloc_fseg(sizeof(*mlun));
+ char *name;
+ int prio, ret = 0;
+
+ if (!mlun) {
+ warn_noalloc();
+ return -1;
+ }
+ memset(mlun, 0, sizeof(*mlun));
+ mlun->drive.type = DTYPE_MEGASAS;
+ mlun->drive.cntl_id = pci->bdf;
+ mlun->pci_id = pci->device;
+ mlun->target = target;
+ mlun->lun = lun;
+ mlun->iobase = iobase;
+ mlun->frame = memalign_low(256, sizeof(struct megasas_cmd_frame));
+ if (!mlun->frame) {
+ warn_noalloc();
+ free(mlun);
+ return -1;
+ }
+ boot_lchs_find_scsi_device(pci, target, lun, &(mlun->drive.lchs));
+ name = znprintf(MAXDESCSIZE, "MegaRAID SAS (PCI %pP) LD %d:%d"
+ , pci, target, lun);
+ prio = bootprio_find_scsi_device(pci, target, lun);
+ ret = scsi_drive_setup(&mlun->drive, name, prio, target, lun);
+ free(name);
+ if (ret) {
+ free(mlun->frame);
+ free(mlun);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+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));
+ if (!frame) {
+ warn_noalloc();
+ return;
+ }
+
+ memset(&ld_list, 0, sizeof(ld_list));
+ memset_fl(frame, 0, sizeof(*frame));
+
+ frame->cmd = MFI_CMD_DCMD;
+ frame->cmd_status = 0xFF;
+ frame->sge_count = 1;
+ frame->flags = 0x0011;
+ frame->data_xfer_len = sizeof(ld_list);
+ frame->dcmd.opcode = 0x03010000;
+ frame->dcmd.sgl_addr = (u32)MAKE_FLATPTR(GET_SEG(SS), &ld_list);
+ frame->dcmd.sgl_len = sizeof(ld_list);
+ frame->context = (u32)frame;
+
+ 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,
+ ld_list.lds[i].state);
+ if (ld_list.lds[i].state != 0) {
+ megasas_add_lun(pci, iobase,
+ ld_list.lds[i].target, ld_list.lds[i].lun);
+ }
+ }
+ }
+}
+
+static int megasas_transition_to_ready(struct pci_device *pci, u32 ioaddr)
+{
+ u32 fw_state = 0, new_state, mfi_flags = 0;
+
+ if (pci->device == PCI_DEVICE_ID_LSI_SAS1064R ||
+ pci->device == PCI_DEVICE_ID_DELL_PERC5)
+ new_state = inl(ioaddr + MFI_OMSG0) & MFI_STATE_MASK;
+ else
+ new_state = inl(ioaddr + MFI_OSP0) & MFI_STATE_MASK;
+
+ while (fw_state != new_state) {
+ switch (new_state) {
+ case MFI_STATE_FAULT:
+ dprintf(1, "ERROR: fw in fault state\n");
+ return -1;
+ break;
+ case MFI_STATE_WAIT_HANDSHAKE:
+ mfi_flags = 0x08;
+ /* fallthrough */
+ case MFI_STATE_BOOT_MESSAGE_PENDING:
+ mfi_flags |= 0x10;
+ if (pci->device == PCI_DEVICE_ID_LSI_SAS2004 ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS2008 ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS3108) {
+ outl(mfi_flags, ioaddr + MFI_DB);
+ } else {
+ outl(mfi_flags, ioaddr + MFI_IDB);
+ }
+ break;
+ case MFI_STATE_OPERATIONAL:
+ mfi_flags = 0x07;
+ if (pci->device == PCI_DEVICE_ID_LSI_SAS2004 ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS2008 ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS3108) {
+ outl(mfi_flags, ioaddr + MFI_DB);
+ if (pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS3108) {
+ int j = 0;
+ u32 doorbell;
+
+ while (j < MEGASAS_POLL_TIMEOUT) {
+ doorbell = inl(ioaddr + MFI_DB) & 1;
+ if (!doorbell)
+ break;
+ msleep(20);
+ j++;
+ }
+ }
+ } else {
+ outl(mfi_flags, ioaddr + MFI_IDB);
+ }
+ break;
+ case MFI_STATE_READY:
+ dprintf(2, "MegaRAID SAS fw ready\n");
+ return 0;
+ }
+ // The current state should not last longer than poll timeout
+ u32 end = timer_calc(MEGASAS_POLL_TIMEOUT);
+ for (;;) {
+ if (timer_check(end)) {
+ break;
+ }
+ yield();
+ fw_state = new_state;
+ if (pci->device == PCI_DEVICE_ID_LSI_SAS1064R ||
+ pci->device == PCI_DEVICE_ID_DELL_PERC5)
+ new_state = inl(ioaddr + MFI_OMSG0) & MFI_STATE_MASK;
+ else
+ new_state = inl(ioaddr + MFI_OSP0) & MFI_STATE_MASK;
+ if (new_state != fw_state) {
+ break;
+ }
+ }
+ }
+ dprintf(1, "ERROR: fw in state %x\n", new_state & MFI_STATE_MASK);
+ return -1;
+}
+
+static void
+init_megasas(void *data)
+{
+ struct pci_device *pci = data;
+ u32 bar = PCI_BASE_ADDRESS_2;
+ if (!(pci_config_readl(pci->bdf, bar) & PCI_BASE_ADDRESS_IO_MASK))
+ bar = PCI_BASE_ADDRESS_0;
+ u32 iobase = pci_enable_iobar(pci, bar);
+ if (!iobase)
+ return;
+ pci_enable_busmaster(pci);
+
+ dprintf(1, "found MegaRAID SAS at %pP, io @ %x\n", pci, iobase);
+
+ // reset
+ if (megasas_transition_to_ready(pci, iobase) == 0)
+ megasas_scan_target(pci, iobase);
+}
+
+void
+megasas_setup(void)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_MEGASAS)
+ return;
+
+ dprintf(3, "init megasas\n");
+
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->vendor != PCI_VENDOR_ID_LSI_LOGIC &&
+ pci->vendor != PCI_VENDOR_ID_DELL)
+ continue;
+ if (pci->device == PCI_DEVICE_ID_LSI_SAS1064R ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS1078 ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS1078DE ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS2108 ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS2108E ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS2004 ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS2008 ||
+ pci->device == PCI_DEVICE_ID_LSI_VERDE_ZCR ||
+ pci->device == PCI_DEVICE_ID_DELL_PERC5 ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
+ pci->device == PCI_DEVICE_ID_LSI_SAS3108)
+ run_thread(init_megasas, pci);
+ }
+}
diff --git a/roms/seabios-hppa/src/hw/megasas.h b/roms/seabios-hppa/src/hw/megasas.h
new file mode 100644
index 000000000..ed0e4f096
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/megasas.h
@@ -0,0 +1,8 @@
+#ifndef __MEGASAS_H
+#define __MEGASAS_H
+
+struct disk_op_s;
+int megasas_process_op(struct disk_op_s *op);
+void megasas_setup(void);
+
+#endif /* __MEGASAS_H */
diff --git a/roms/seabios-hppa/src/hw/mpt-scsi.c b/roms/seabios-hppa/src/hw/mpt-scsi.c
new file mode 100644
index 000000000..7dd4946b3
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/mpt-scsi.c
@@ -0,0 +1,321 @@
+// MPT Fusion boot support.
+//
+// Copyright (c) 2012 Verizon, Inc.
+// Copyright (C) 2016 Paolo Bonzini <pbonzini@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBALFLAT
+#include "block.h" // struct drive_s
+#include "blockcmd.h" // scsi_drive_setup
+#include "config.h" // CONFIG_*
+#include "fw/paravirt.h" // runningOnQEMU
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_DEVICE_ID
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "stacks.h" // run_thread
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // usleep
+
+#define MPT_REG_DOORBELL 0x00
+#define MPT_REG_WRITE_SEQ 0x04
+#define MPT_REG_HOST_DIAG 0x08
+#define MPT_REG_TEST 0x0c
+#define MPT_REG_DIAG_DATA 0x10
+#define MPT_REG_DIAG_ADDR 0x14
+#define MPT_REG_ISTATUS 0x30
+#define MPT_REG_IMASK 0x34
+#define MPT_REG_REQ_Q 0x40
+#define MPT_REG_REP_Q 0x44
+
+#define MPT_DOORBELL_MSG_RESET 0x40
+#define MPT_DOORBELL_HANDSHAKE 0x42
+
+#define MPT_IMASK_DOORBELL 0x01
+#define MPT_IMASK_REPLY 0x08
+
+struct mpt_lun_s {
+ struct drive_s drive;
+ struct pci_device *pci;
+ u32 iobase;
+ u8 target;
+ u8 lun;
+};
+
+u8 reply_msg[4] __attribute((aligned(4))) VARLOW;
+
+#define MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST (0x00)
+#define MPT_MESSAGE_HDR_FUNCTION_IOC_INIT (0x02)
+
+static struct MptIOCInitRequest
+{
+ u8 WhoInit; /* Which system sent this init request. */
+ u8 Reserved1; /* Reserved */
+ u8 ChainOffset; /* Chain offset in the SG list. */
+ u8 Function; /* Function to execute. */
+ u8 Flags; /* Flags */
+ u8 MaxDevices; /* Max devices the driver can handle. */
+ u8 MaxBuses; /* Max buses the driver can handle. */
+ u8 MessageFlags; /* Message flags. */
+ u32 MessageContext; /* Message context ID. */
+ u16 ReplyFrameSize; /* Reply frame size. */
+ u16 Reserved2; /* Reserved */
+ u32 HostMfaHighAddr; /* Upper 32bit of the message frames. */
+ u32 SenseBufferHighAddr; /* Upper 32bit of the sense buffer. */
+} MptIOCInitRequest = {
+ .WhoInit = 2,
+ .Function = MPT_MESSAGE_HDR_FUNCTION_IOC_INIT,
+ .MaxDevices = 8,
+ .MaxBuses = 1,
+ .ReplyFrameSize = sizeof(reply_msg),
+ .HostMfaHighAddr = 0,
+ .SenseBufferHighAddr = 0
+};
+
+struct MptIOCInitReply {
+ u8 WhoInit; /* Which subsystem sent this init request. */
+ u8 Reserved1; /* Reserved */
+ u8 MessageLength; /* Message length */
+ u8 Function; /* Function. */
+ u8 Flags; /* Flags */
+ u8 MaxDevices; /* Maximum number of devices the driver can handle. */
+ u8 MaxBuses; /* Maximum number of busses the driver can handle. */
+ u8 MessageFlags; /* Message flags. */
+ u32 MessageContext; /* Message context ID */
+ u16 Reserved2; /* Reserved */
+ u16 IOCStatus; /* IO controller status. */
+ u32 IOCLogInfo; /* IO controller log information. */
+};
+
+typedef struct MptSCSIIORequest {
+ u8 TargetID; /* Target ID */
+ u8 Bus; /* Bus number */
+ u8 ChainOffset; /* Chain offset */
+ u8 Function; /* Function number. */
+ u8 CDBLength; /* CDB length. */
+ u8 SenseBufferLength; /* Sense buffer length. */
+ u8 Reserved; /* Reserved */
+ u8 MessageFlags; /* Message flags. */
+ u32 MessageContext; /* Message context ID. */
+ u8 LUN[8]; /* LUN */
+ u32 Control; /* Control values. */
+ u8 CDB[16]; /* The CDB. */
+ u32 DataLength; /* Data length. */
+ u32 SenseBufferLowAddr; /* Sense buffer low 32bit address. */
+} __attribute__((packed)) MptSCSIIORequest_t;
+
+#define MPT_POLL_TIMEOUT 60000
+
+typedef struct MptSGEntrySimple32 {
+ u32 FlagsLength;
+ u32 DataBufferAddressLow;
+} __attribute__((packed)) MptSGEntrySimple32_t;
+
+static int
+mpt_scsi_cmd(u32 iobase, struct disk_op_s *op,
+ u8 *cdb, u16 target, u16 lun, u16 blocksize)
+{
+ u32 end = timer_calc(MPT_POLL_TIMEOUT);
+
+ u8 sense_buf[18];
+ struct scsi_req {
+ MptSCSIIORequest_t scsi_io;
+ MptSGEntrySimple32_t sge;
+ } __attribute__((packed, aligned(4))) req = {
+ .scsi_io = {
+ .TargetID = target,
+ .Bus = 0,
+ .Function = MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST,
+ .CDBLength = 16,
+ .SenseBufferLength = 18,
+ .MessageContext = end & 0x7fffffff,
+ .DataLength = op->count * blocksize,
+ .SenseBufferLowAddr = (u32)MAKE_FLATPTR(GET_SEG(SS), &sense_buf[0]),
+ },
+ .sge = {
+ /* end of list, simple entry, end of buffer, last element */
+ .FlagsLength = (op->count * blocksize) | 0xD1000000,
+ .DataBufferAddressLow = (u32)op->buf_fl,
+ }
+ };
+
+ req.scsi_io.LUN[1] = lun;
+ memcpy(req.scsi_io.CDB, cdb, 16);
+ if (blocksize) {
+ if (scsi_is_read(op)) {
+ req.scsi_io.Control = 2 << 24;
+ } else {
+ req.scsi_io.Control = 1 << 24;
+ req.sge.FlagsLength |= 0x04000000;
+ }
+ }
+
+ outl((u32)MAKE_FLATPTR(GET_SEG(SS), &req), iobase + MPT_REG_REQ_Q);
+
+ for (;;) {
+ if (timer_check(end)) {
+ return DISK_RET_ETIMEOUT;
+ }
+
+ u32 istatus = inl(iobase + MPT_REG_ISTATUS);
+ if (istatus & MPT_IMASK_REPLY) {
+ u32 resp = inl(iobase + MPT_REG_REP_Q);
+ /* another read to turn interrupt off */
+ inl(iobase + MPT_REG_REP_Q);
+ if (resp == req.scsi_io.MessageContext) {
+ return DISK_RET_SUCCESS;
+ } else if (resp & 0x80000000) {
+ outl((u32)&reply_msg[0], iobase + MPT_REG_REP_Q);
+ return DISK_RET_EBADTRACK;
+ }
+ }
+ usleep(50);
+ }
+}
+
+int
+mpt_scsi_process_op(struct disk_op_s *op)
+{
+ if (!CONFIG_MPT_SCSI)
+ return DISK_RET_EBADTRACK;
+
+ u8 cdbcmd[16];
+ int blocksize = scsi_fill_cmd(op, cdbcmd, sizeof(cdbcmd));
+ if (blocksize < 0)
+ return default_process_op(op);
+
+ struct mpt_lun_s *llun_gf =
+ container_of(op->drive_fl, struct mpt_lun_s, drive);
+ u16 target = GET_GLOBALFLAT(llun_gf->target);
+ u16 lun = GET_GLOBALFLAT(llun_gf->lun);
+ u32 iobase = GET_GLOBALFLAT(llun_gf->iobase);
+ return mpt_scsi_cmd(iobase, op, cdbcmd, target, lun, blocksize);
+}
+
+static void
+mpt_scsi_init_lun(struct mpt_lun_s *llun, struct pci_device *pci,
+ u32 iobase, u8 target, u8 lun)
+{
+ memset(llun, 0, sizeof(*llun));
+ llun->drive.type = DTYPE_MPT_SCSI;
+ llun->drive.cntl_id = pci->bdf;
+ llun->pci = pci;
+ llun->target = target;
+ llun->lun = lun;
+ llun->iobase = iobase;
+}
+
+static int
+mpt_scsi_add_lun(u32 lun, struct drive_s *tmpl_drv)
+{
+ struct mpt_lun_s *tmpl_llun =
+ container_of(tmpl_drv, struct mpt_lun_s, drive);
+ struct mpt_lun_s *llun = malloc_fseg(sizeof(*llun));
+ if (!llun) {
+ warn_noalloc();
+ return -1;
+ }
+ mpt_scsi_init_lun(llun, tmpl_llun->pci, tmpl_llun->iobase,
+ tmpl_llun->target, lun);
+
+ boot_lchs_find_scsi_device(llun->pci, llun->target, llun->lun,
+ &(llun->drive.lchs));
+ char *name = znprintf(MAXDESCSIZE, "mpt %pP %d:%d",
+ llun->pci, llun->target, llun->lun);
+ int prio = bootprio_find_scsi_device(llun->pci, llun->target, llun->lun);
+ int ret = scsi_drive_setup(&llun->drive, name, prio, llun->target, llun->lun);
+ free(name);
+ if (ret) {
+ goto fail;
+ }
+ return 0;
+
+fail:
+ free(llun);
+ return -1;
+}
+
+static void
+mpt_scsi_scan_target(struct pci_device *pci, u32 iobase, u8 target)
+{
+ struct mpt_lun_s llun0;
+
+ mpt_scsi_init_lun(&llun0, pci, iobase, target, 0);
+
+ if (scsi_rep_luns_scan(&llun0.drive, mpt_scsi_add_lun) < 0)
+ scsi_sequential_scan(&llun0.drive, 8, mpt_scsi_add_lun);
+}
+
+static inline void
+mpt_out_doorbell(u8 func, u8 arg, u16 iobase)
+{
+ outl((func << 24) | (arg << 16), iobase + MPT_REG_DOORBELL);
+}
+
+static void
+init_mpt_scsi(void *data)
+{
+ struct pci_device *pci = data;
+ u16 *msg_in_p;
+ u32 iobase = pci_enable_iobar(pci, PCI_BASE_ADDRESS_0);
+ if (!iobase)
+ return;
+ struct MptIOCInitReply MptIOCInitReply;
+ pci_enable_busmaster(pci);
+
+ dprintf(1, "found mpt-scsi(%04x) at %pP, io @ %x\n"
+ , pci->device, pci, iobase);
+
+ // reset
+ mpt_out_doorbell(MPT_DOORBELL_MSG_RESET, 0, iobase);
+ outl(MPT_IMASK_DOORBELL|MPT_IMASK_REPLY , iobase + MPT_REG_IMASK);
+ outl(0, iobase + MPT_REG_ISTATUS);
+
+ // send IOC Init message through the doorbell
+ mpt_out_doorbell(MPT_DOORBELL_HANDSHAKE,
+ sizeof(MptIOCInitRequest)/sizeof(u32),
+ iobase);
+
+ outsl(iobase + MPT_REG_DOORBELL,
+ (u32 *)&MptIOCInitRequest,
+ sizeof(MptIOCInitRequest)/sizeof(u32));
+
+ // Read the reply 16 bits at a time. Cannot use insl
+ // because the port is 32 bits wide.
+ msg_in_p = (u16 *)&MptIOCInitReply;
+ while(msg_in_p != (u16 *)(&MptIOCInitReply + 1))
+ *msg_in_p++ = (u16)inl(iobase + MPT_REG_DOORBELL);
+
+ // Eat doorbell interrupt
+ outl(0, iobase + MPT_REG_ISTATUS);
+
+ // Post reply message used for SCSI errors
+ outl((u32)&reply_msg[0], iobase + MPT_REG_REP_Q);
+
+ int i;
+ for (i = 0; i < 7; i++)
+ mpt_scsi_scan_target(pci, iobase, i);
+}
+
+void
+mpt_scsi_setup(void)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_MPT_SCSI || !runningOnQEMU()) {
+ return;
+ }
+
+ dprintf(3, "init MPT\n");
+
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->vendor == PCI_VENDOR_ID_LSI_LOGIC
+ && (pci->device == PCI_DEVICE_ID_LSI_53C1030
+ || pci->device == PCI_DEVICE_ID_LSI_SAS1068
+ || pci->device == PCI_DEVICE_ID_LSI_SAS1068E))
+ run_thread(init_mpt_scsi, pci);
+ }
+}
diff --git a/roms/seabios-hppa/src/hw/mpt-scsi.h b/roms/seabios-hppa/src/hw/mpt-scsi.h
new file mode 100644
index 000000000..6535dd8d4
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/mpt-scsi.h
@@ -0,0 +1,8 @@
+#ifndef __MPT_SCSI_H
+#define __MPT_SCSI_H
+
+struct disk_op_s;
+int mpt_scsi_process_op(struct disk_op_s *op);
+void mpt_scsi_setup(void);
+
+#endif /* __MPT_SCSI_H */
diff --git a/roms/seabios-hppa/src/hw/nvme-int.h b/roms/seabios-hppa/src/hw/nvme-int.h
new file mode 100644
index 000000000..a4c1555cc
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/nvme-int.h
@@ -0,0 +1,212 @@
+// NVMe datastructures and constants
+//
+// Copyright 2017 Amazon.com, Inc. or its affiliates.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#ifndef __NVME_INT_H
+#define __NVME_INT_H
+
+#include "types.h" // u32
+#include "pcidevice.h" // struct pci_device
+
+#define NVME_MAX_PRPL_ENTRIES 15 /* Allows requests up to 64kb */
+
+/* Data structures */
+
+/* The register file of a NVMe host controller. This struct follows the naming
+ scheme in the NVMe specification. */
+struct nvme_reg {
+ u64 cap; /* controller capabilities */
+ u32 vs; /* version */
+ u32 intms; /* interrupt mask set */
+ u32 intmc; /* interrupt mask clear */
+ u32 cc; /* controller configuration */
+ u32 _res0;
+ u32 csts; /* controller status */
+ u32 _res1;
+ u32 aqa; /* admin queue attributes */
+ u64 asq; /* admin submission queue base address */
+ u64 acq; /* admin completion queue base address */
+};
+
+/* Submission queue entry */
+struct nvme_sqe {
+ union {
+ u32 dword[16];
+ struct {
+ u32 cdw0; /* Command DWORD 0 */
+ u32 nsid; /* Namespace ID */
+ u64 _res0;
+ u64 mptr; /* metadata ptr */
+
+ u64 dptr_prp1;
+ u64 dptr_prp2;
+ };
+ };
+};
+
+/* Completion queue entry */
+struct nvme_cqe {
+ union {
+ u32 dword[4];
+ struct {
+ u32 cdw0;
+ u32 _res0;
+ u16 sq_head;
+ u16 sq_id;
+ u16 cid;
+ u16 status;
+ };
+ };
+};
+
+/* The common part of every submission or completion queue. */
+struct nvme_queue {
+ u32 *dbl; /* doorbell */
+ u16 mask; /* length - 1 */
+};
+
+struct nvme_cq {
+ struct nvme_queue common;
+ struct nvme_cqe *cqe;
+
+ /* We have read upto (but not including) this entry in the queue. */
+ u16 head;
+
+ /* The current phase bit the controller uses to indicate that it has written
+ a new entry. This is inverted after each wrap. */
+ unsigned phase : 1;
+};
+
+struct nvme_sq {
+ struct nvme_queue common;
+ struct nvme_sqe *sqe;
+
+ /* Corresponding completion queue. We only support a single SQ per CQ. */
+ struct nvme_cq *cq;
+
+ /* The last entry the controller has fetched. */
+ u16 head;
+
+ /* The last value we have written to the tail doorbell. */
+ u16 tail;
+};
+
+struct nvme_ctrl {
+ struct pci_device *pci;
+ struct nvme_reg volatile *reg;
+
+ u32 doorbell_stride; /* in bytes */
+
+ struct nvme_sq admin_sq;
+ struct nvme_cq admin_cq;
+
+ u32 ns_count;
+
+ struct nvme_sq io_sq;
+ struct nvme_cq io_cq;
+};
+
+struct nvme_namespace {
+ struct drive_s drive;
+ struct nvme_ctrl *ctrl;
+
+ u32 ns_id;
+
+ u64 lba_count; /* The total amount of sectors. */
+
+ u32 block_size;
+ u32 metadata_size;
+ u32 max_req_size;
+
+ /* Page aligned buffer of size NVME_PAGE_SIZE. */
+ char *dma_buffer;
+
+ /* Page List */
+ u32 prpl_len;
+ void *prp1;
+ u64 prpl[NVME_MAX_PRPL_ENTRIES];
+};
+
+/* Data structures for NVMe admin identify commands */
+
+struct nvme_identify_ctrl {
+ u16 vid;
+ u16 ssvid;
+ char sn[20];
+ char mn[40];
+ char fr[8];
+
+ u8 rab;
+ u8 ieee[3];
+ u8 cmic;
+ u8 mdts;
+
+ char _boring[516 - 78];
+
+ u32 nn; /* number of namespaces */
+};
+
+struct nvme_identify_ns_list {
+ u32 ns_id[1024];
+};
+
+struct nvme_lba_format {
+ u16 ms;
+ u8 lbads;
+ u8 rp;
+ u8 res;
+};
+
+struct nvme_identify_ns {
+ u64 nsze;
+ u64 ncap;
+ u64 nuse;
+ u8 nsfeat;
+ u8 nlbaf;
+ u8 flbas;
+
+ char _boring[128 - 27];
+
+ struct nvme_lba_format lbaf[16];
+};
+
+union nvme_identify {
+ struct nvme_identify_ns ns;
+ struct nvme_identify_ctrl ctrl;
+ struct nvme_identify_ns_list ns_list;
+};
+
+/* NVMe constants */
+
+#define NVME_CAP_CSS_NVME (1ULL << 37)
+
+#define NVME_CSTS_FATAL (1U << 1)
+#define NVME_CSTS_RDY (1U << 0)
+
+#define NVME_CC_EN (1U << 0)
+
+#define NVME_SQE_OPC_ADMIN_CREATE_IO_SQ 1U
+#define NVME_SQE_OPC_ADMIN_CREATE_IO_CQ 5U
+#define NVME_SQE_OPC_ADMIN_IDENTIFY 6U
+
+#define NVME_SQE_OPC_IO_WRITE 1U
+#define NVME_SQE_OPC_IO_READ 2U
+
+#define NVME_ADMIN_IDENTIFY_CNS_ID_NS 0U
+#define NVME_ADMIN_IDENTIFY_CNS_ID_CTRL 1U
+#define NVME_ADMIN_IDENTIFY_CNS_GET_NS_LIST 2U
+
+#define NVME_CQE_DW3_P (1U << 16)
+
+#define NVME_PAGE_SIZE 4096
+#define NVME_PAGE_MASK ~(NVME_PAGE_SIZE - 1)
+
+/* Length for the queue entries. */
+#define NVME_SQE_SIZE_LOG 6
+#define NVME_CQE_SIZE_LOG 4
+
+#endif
+
+/* EOF */
diff --git a/roms/seabios-hppa/src/hw/nvme.c b/roms/seabios-hppa/src/hw/nvme.c
new file mode 100644
index 000000000..f035fa2c6
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/nvme.c
@@ -0,0 +1,786 @@
+// Low level NVMe disk access
+//
+// Copyright 2017 Amazon.com, Inc. or its affiliates.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "blockcmd.h"
+#include "malloc.h" // malloc_high
+#include "output.h" // dprintf
+#include "pci.h"
+#include "pci_ids.h" // PCI_CLASS_STORAGE_NVME
+#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "pcidevice.h" // foreachpci
+#include "stacks.h" // yield
+#include "std/disk.h" // DISK_RET_
+#include "string.h" // memset
+#include "util.h" // boot_add_hd
+#include "x86.h" // readl
+
+#include "nvme.h"
+#include "nvme-int.h"
+
+static void *
+zalloc_page_aligned(struct zone_s *zone, u32 size)
+{
+ void *res = _malloc(zone, size, NVME_PAGE_SIZE);
+ if (res) memset(res, 0, size);
+ return res;
+}
+
+static void
+nvme_init_queue_common(struct nvme_ctrl *ctrl, struct nvme_queue *q, u16 q_idx,
+ u16 length)
+{
+ memset(q, 0, sizeof(*q));
+ q->dbl = (u32 *)((char *)ctrl->reg + 0x1000 + q_idx * ctrl->doorbell_stride);
+ dprintf(3, " q %p q_idx %u dbl %p\n", q, q_idx, q->dbl);
+ q->mask = length - 1;
+}
+
+static int
+nvme_init_sq(struct nvme_ctrl *ctrl, struct nvme_sq *sq, u16 q_idx, u16 length,
+ struct nvme_cq *cq)
+{
+ nvme_init_queue_common(ctrl, &sq->common, q_idx, length);
+ sq->sqe = zalloc_page_aligned(&ZoneHigh, sizeof(*sq->sqe) * length);
+
+ if (!sq->sqe) {
+ warn_noalloc();
+ return -1;
+ }
+
+ dprintf(3, "sq %p q_idx %u sqe %p\n", sq, q_idx, sq->sqe);
+ sq->cq = cq;
+ sq->head = 0;
+ sq->tail = 0;
+
+ return 0;
+}
+
+static int
+nvme_init_cq(struct nvme_ctrl *ctrl, struct nvme_cq *cq, u16 q_idx, u16 length)
+{
+ nvme_init_queue_common(ctrl, &cq->common, q_idx, length);
+ cq->cqe = zalloc_page_aligned(&ZoneHigh, sizeof(*cq->cqe) * length);
+ if (!cq->cqe) {
+ warn_noalloc();
+ return -1;
+ }
+
+ cq->head = 0;
+
+ /* All CQE phase bits are initialized to zero. This means initially we wait
+ for the host controller to set these to 1. */
+ cq->phase = 1;
+
+ return 0;
+}
+
+static int
+nvme_poll_cq(struct nvme_cq *cq)
+{
+ u32 dw3 = readl(&cq->cqe[cq->head].dword[3]);
+ return (!!(dw3 & NVME_CQE_DW3_P) == cq->phase);
+}
+
+static int
+nvme_is_cqe_success(struct nvme_cqe const *cqe)
+{
+ return ((cqe->status >> 1) & 0xFF) == 0;
+}
+
+static struct nvme_cqe
+nvme_error_cqe(void)
+{
+ struct nvme_cqe r;
+
+ /* 0xFF is a vendor specific status code != success. Should be okay for
+ indicating failure. */
+ memset(&r, 0xFF, sizeof(r));
+ return r;
+}
+
+static struct nvme_cqe
+nvme_consume_cqe(struct nvme_sq *sq)
+{
+ struct nvme_cq *cq = sq->cq;
+
+ if (!nvme_poll_cq(cq)) {
+ /* Cannot consume a completion queue entry, if there is none ready. */
+ return nvme_error_cqe();
+ }
+
+ struct nvme_cqe *cqe = &cq->cqe[cq->head];
+ u16 cq_next_head = (cq->head + 1) & cq->common.mask;
+ dprintf(4, "cq %p head %u -> %u\n", cq, cq->head, cq_next_head);
+ if (cq_next_head < cq->head) {
+ dprintf(3, "cq %p wrap\n", cq);
+ cq->phase = ~cq->phase;
+ }
+ cq->head = cq_next_head;
+
+ /* Update the submission queue head. */
+ if (cqe->sq_head != sq->head) {
+ sq->head = cqe->sq_head;
+ dprintf(4, "sq %p advanced to %u\n", sq, cqe->sq_head);
+ }
+
+ /* Tell the controller that we consumed the completion. */
+ writel(cq->common.dbl, cq->head);
+
+ return *cqe;
+}
+
+static struct nvme_cqe
+nvme_wait(struct nvme_sq *sq)
+{
+ static const unsigned nvme_timeout = 5000 /* ms */;
+ u32 to = timer_calc(nvme_timeout);
+ while (!nvme_poll_cq(sq->cq)) {
+ yield();
+
+ if (timer_check(to)) {
+ warn_timeout();
+ return nvme_error_cqe();
+ }
+ }
+
+ return nvme_consume_cqe(sq);
+}
+
+/* Returns the next submission queue entry (or NULL if the queue is full). It
+ also fills out Command Dword 0 and clears the rest. */
+static struct nvme_sqe *
+nvme_get_next_sqe(struct nvme_sq *sq, u8 opc, void *metadata, void *data, void *data2)
+{
+ if (((sq->head + 1) & sq->common.mask) == sq->tail) {
+ dprintf(3, "submission queue is full\n");
+ return NULL;
+ }
+
+ struct nvme_sqe *sqe = &sq->sqe[sq->tail];
+ dprintf(4, "sq %p next_sqe %u\n", sq, sq->tail);
+
+ memset(sqe, 0, sizeof(*sqe));
+ sqe->cdw0 = opc | (sq->tail << 16 /* CID */);
+ sqe->mptr = (u32)metadata;
+ sqe->dptr_prp1 = (u32)data;
+ sqe->dptr_prp2 = (u32)data2;
+
+ return sqe;
+}
+
+/* Call this after you've filled out an sqe that you've got from nvme_get_next_sqe. */
+static void
+nvme_commit_sqe(struct nvme_sq *sq)
+{
+ dprintf(4, "sq %p commit_sqe %u\n", sq, sq->tail);
+ sq->tail = (sq->tail + 1) & sq->common.mask;
+ writel(sq->common.dbl, sq->tail);
+}
+
+/* Perform an identify command on the admin queue and return the resulting
+ buffer. This may be a NULL pointer, if something failed. This function
+ cannot be used after initialization, because it uses buffers in tmp zone. */
+static union nvme_identify *
+nvme_admin_identify(struct nvme_ctrl *ctrl, u8 cns, u32 nsid)
+{
+ union nvme_identify *identify_buf = zalloc_page_aligned(&ZoneTmpHigh, 4096);
+ if (!identify_buf) {
+ /* Could not allocate identify buffer. */
+ warn_internalerror();
+ return NULL;
+ }
+
+ struct nvme_sqe *cmd_identify;
+ cmd_identify = nvme_get_next_sqe(&ctrl->admin_sq,
+ NVME_SQE_OPC_ADMIN_IDENTIFY, NULL,
+ identify_buf, NULL);
+
+ if (!cmd_identify) {
+ warn_internalerror();
+ goto error;
+ }
+
+ cmd_identify->nsid = nsid;
+ cmd_identify->dword[10] = cns;
+
+ nvme_commit_sqe(&ctrl->admin_sq);
+
+ struct nvme_cqe cqe = nvme_wait(&ctrl->admin_sq);
+
+ if (!nvme_is_cqe_success(&cqe)) {
+ goto error;
+ }
+
+ return identify_buf;
+ error:
+ free(identify_buf);
+ return NULL;
+}
+
+static struct nvme_identify_ctrl *
+nvme_admin_identify_ctrl(struct nvme_ctrl *ctrl)
+{
+ return &nvme_admin_identify(ctrl, NVME_ADMIN_IDENTIFY_CNS_ID_CTRL, 0)->ctrl;
+}
+
+static struct nvme_identify_ns *
+nvme_admin_identify_ns(struct nvme_ctrl *ctrl, u32 ns_id)
+{
+ return &nvme_admin_identify(ctrl, NVME_ADMIN_IDENTIFY_CNS_ID_NS,
+ ns_id)->ns;
+}
+
+static void
+nvme_probe_ns(struct nvme_ctrl *ctrl, u32 ns_idx, u8 mdts)
+{
+ u32 ns_id = ns_idx + 1;
+
+ struct nvme_identify_ns *id = nvme_admin_identify_ns(ctrl, ns_id);
+ if (!id) {
+ dprintf(2, "NVMe couldn't identify namespace %u.\n", ns_id);
+ goto free_buffer;
+ }
+
+ u8 current_lba_format = id->flbas & 0xF;
+ if (current_lba_format > id->nlbaf) {
+ dprintf(2, "NVMe NS %u: current LBA format %u is beyond what the "
+ " namespace supports (%u)?\n",
+ ns_id, current_lba_format, id->nlbaf + 1);
+ goto free_buffer;
+ }
+
+ if (!id->nsze) {
+ dprintf(2, "NVMe NS %u is inactive.\n", ns_id);
+ goto free_buffer;
+ }
+
+ struct nvme_namespace *ns = malloc_fseg(sizeof(*ns));
+ if (!ns) {
+ warn_noalloc();
+ goto free_buffer;
+ }
+ memset(ns, 0, sizeof(*ns));
+ ns->ctrl = ctrl;
+ ns->ns_id = ns_id;
+ ns->lba_count = id->nsze;
+
+ struct nvme_lba_format *fmt = &id->lbaf[current_lba_format];
+
+ ns->block_size = 1U << fmt->lbads;
+ ns->metadata_size = fmt->ms;
+
+ if (ns->block_size > NVME_PAGE_SIZE) {
+ /* If we see devices that trigger this path, we need to increase our
+ buffer size. */
+ warn_internalerror();
+ free(ns);
+ goto free_buffer;
+ }
+
+ ns->drive.cntl_id = ns_idx;
+ ns->drive.removable = 0;
+ ns->drive.type = DTYPE_NVME;
+ ns->drive.blksize = ns->block_size;
+ ns->drive.sectors = ns->lba_count;
+
+ if (mdts) {
+ ns->max_req_size = ((1U << mdts) * NVME_PAGE_SIZE) / ns->block_size;
+ dprintf(3, "NVME NS %u max request size: %d sectors\n",
+ ns_id, ns->max_req_size);
+ } else {
+ ns->max_req_size = -1U;
+ }
+
+ ns->dma_buffer = zalloc_page_aligned(&ZoneHigh, NVME_PAGE_SIZE);
+
+ char *desc = znprintf(MAXDESCSIZE, "NVMe NS %u: %llu MiB (%llu %u-byte "
+ "blocks + %u-byte metadata)",
+ ns_id, (ns->lba_count * ns->block_size) >> 20,
+ ns->lba_count, ns->block_size, ns->metadata_size);
+
+ dprintf(3, "%s\n", desc);
+ boot_add_hd(&ns->drive, desc, bootprio_find_pci_device(ctrl->pci));
+
+free_buffer:
+ free (id);
+}
+
+
+/* Release memory allocated for a completion queue */
+static void
+nvme_destroy_cq(struct nvme_cq *cq)
+{
+ free(cq->cqe);
+ cq->cqe = NULL;
+}
+
+/* Release memory allocated for a submission queue */
+static void
+nvme_destroy_sq(struct nvme_sq *sq)
+{
+ free(sq->sqe);
+ sq->sqe = NULL;
+}
+
+/* Returns 0 on success. */
+static int
+nvme_create_io_cq(struct nvme_ctrl *ctrl, struct nvme_cq *cq, u16 q_idx)
+{
+ int rc;
+ struct nvme_sqe *cmd_create_cq;
+ u32 length = 1 + (ctrl->reg->cap & 0xffff);
+ if (length > NVME_PAGE_SIZE / sizeof(struct nvme_cqe))
+ length = NVME_PAGE_SIZE / sizeof(struct nvme_cqe);
+
+ rc = nvme_init_cq(ctrl, cq, q_idx, length);
+ if (rc) {
+ goto err;
+ }
+
+ cmd_create_cq = nvme_get_next_sqe(&ctrl->admin_sq,
+ NVME_SQE_OPC_ADMIN_CREATE_IO_CQ, NULL,
+ cq->cqe, NULL);
+ if (!cmd_create_cq) {
+ goto err_destroy_cq;
+ }
+
+ cmd_create_cq->dword[10] = (cq->common.mask << 16) | (q_idx >> 1);
+ cmd_create_cq->dword[11] = 1 /* physically contiguous */;
+
+ nvme_commit_sqe(&ctrl->admin_sq);
+
+ struct nvme_cqe cqe = nvme_wait(&ctrl->admin_sq);
+
+ if (!nvme_is_cqe_success(&cqe)) {
+ dprintf(2, "create io cq failed: %08x %08x %08x %08x\n",
+ cqe.dword[0], cqe.dword[1], cqe.dword[2], cqe.dword[3]);
+
+ goto err_destroy_cq;
+ }
+
+ return 0;
+
+err_destroy_cq:
+ nvme_destroy_cq(cq);
+err:
+ return -1;
+}
+
+/* Returns 0 on success. */
+static int
+nvme_create_io_sq(struct nvme_ctrl *ctrl, struct nvme_sq *sq, u16 q_idx, struct nvme_cq *cq)
+{
+ int rc;
+ struct nvme_sqe *cmd_create_sq;
+ u32 length = 1 + (ctrl->reg->cap & 0xffff);
+ if (length > NVME_PAGE_SIZE / sizeof(struct nvme_cqe))
+ length = NVME_PAGE_SIZE / sizeof(struct nvme_cqe);
+
+ rc = nvme_init_sq(ctrl, sq, q_idx, length, cq);
+ if (rc) {
+ goto err;
+ }
+
+ cmd_create_sq = nvme_get_next_sqe(&ctrl->admin_sq,
+ NVME_SQE_OPC_ADMIN_CREATE_IO_SQ, NULL,
+ sq->sqe, NULL);
+ if (!cmd_create_sq) {
+ goto err_destroy_sq;
+ }
+
+ cmd_create_sq->dword[10] = (sq->common.mask << 16) | (q_idx >> 1);
+ cmd_create_sq->dword[11] = (q_idx >> 1) << 16 | 1 /* contiguous */;
+ dprintf(3, "sq %p create dword10 %08x dword11 %08x\n", sq,
+ cmd_create_sq->dword[10], cmd_create_sq->dword[11]);
+
+ nvme_commit_sqe(&ctrl->admin_sq);
+
+ struct nvme_cqe cqe = nvme_wait(&ctrl->admin_sq);
+
+ if (!nvme_is_cqe_success(&cqe)) {
+ dprintf(2, "create io sq failed: %08x %08x %08x %08x\n",
+ cqe.dword[0], cqe.dword[1], cqe.dword[2], cqe.dword[3]);
+ goto err_destroy_sq;
+ }
+
+ return 0;
+
+err_destroy_sq:
+ nvme_destroy_sq(sq);
+err:
+ return -1;
+}
+
+/* Reads count sectors into buf. Returns DISK_RET_*. The buffer cannot cross
+ page boundaries. */
+static int
+nvme_io_readwrite(struct nvme_namespace *ns, u64 lba, char *buf, u16 count,
+ int write)
+{
+ u32 buf_addr = (u32)buf;
+ void *prp2;
+
+ if (buf_addr & 0x3) {
+ /* Buffer is misaligned */
+ warn_internalerror();
+ return DISK_RET_EBADTRACK;
+ }
+
+ if ((ns->block_size * count) > (NVME_PAGE_SIZE * 2)) {
+ /* We need to describe more than 2 pages, rely on PRP List */
+ prp2 = ns->prpl;
+ } else if ((ns->block_size * count) > NVME_PAGE_SIZE) {
+ /* Directly embed the 2nd page if we only need 2 pages */
+ prp2 = (void *)(long)ns->prpl[0];
+ } else {
+ /* One page is enough, don't expose anything else */
+ prp2 = NULL;
+ }
+
+ struct nvme_sqe *io_read = nvme_get_next_sqe(&ns->ctrl->io_sq,
+ write ? NVME_SQE_OPC_IO_WRITE
+ : NVME_SQE_OPC_IO_READ,
+ NULL, buf, prp2);
+ io_read->nsid = ns->ns_id;
+ io_read->dword[10] = (u32)lba;
+ io_read->dword[11] = (u32)(lba >> 32);
+ io_read->dword[12] = (1U << 31 /* limited retry */) | (count - 1);
+
+ nvme_commit_sqe(&ns->ctrl->io_sq);
+
+ struct nvme_cqe cqe = nvme_wait(&ns->ctrl->io_sq);
+
+ if (!nvme_is_cqe_success(&cqe)) {
+ dprintf(2, "read io: %08x %08x %08x %08x\n",
+ cqe.dword[0], cqe.dword[1], cqe.dword[2], cqe.dword[3]);
+
+ return DISK_RET_EBADTRACK;
+ }
+
+ return DISK_RET_SUCCESS;
+}
+
+static void nvme_reset_prpl(struct nvme_namespace *ns)
+{
+ ns->prpl_len = 0;
+}
+
+static int nvme_add_prpl(struct nvme_namespace *ns, u64 base)
+{
+ if (ns->prpl_len >= NVME_MAX_PRPL_ENTRIES)
+ return -1;
+
+ ns->prpl[ns->prpl_len++] = base;
+
+ return 0;
+}
+
+static int nvme_build_prpl(struct nvme_namespace *ns, void *op_buf, u16 count)
+{
+ int first_page = 1;
+ u32 base = (long)op_buf;
+ s32 size;
+
+ if (count > ns->max_req_size)
+ count = ns->max_req_size;
+
+ nvme_reset_prpl(ns);
+
+ size = count * ns->block_size;
+ /* Special case for transfers that fit into PRP1, but are unaligned */
+ if (((size + (base & ~NVME_PAGE_MASK)) <= NVME_PAGE_SIZE)) {
+ ns->prp1 = op_buf;
+ return count;
+ }
+
+ /* Every request has to be page aligned */
+ if (base & ~NVME_PAGE_MASK)
+ return 0;
+
+ /* Make sure a full block fits into the last chunk */
+ if (size & (ns->block_size - 1ULL))
+ return 0;
+
+ for (; size > 0; base += NVME_PAGE_SIZE, size -= NVME_PAGE_SIZE) {
+ if (first_page) {
+ /* First page is special */
+ ns->prp1 = (void*)base;
+ first_page = 0;
+ continue;
+ }
+ if (nvme_add_prpl(ns, base))
+ return 0;
+ }
+
+ return count;
+}
+
+static int
+nvme_create_io_queues(struct nvme_ctrl *ctrl)
+{
+ if (nvme_create_io_cq(ctrl, &ctrl->io_cq, 3))
+ goto err;
+
+ if (nvme_create_io_sq(ctrl, &ctrl->io_sq, 2, &ctrl->io_cq))
+ goto err_free_cq;
+
+ return 0;
+
+ err_free_cq:
+ nvme_destroy_cq(&ctrl->io_cq);
+ err:
+ return -1;
+}
+
+/* Waits for CSTS.RDY to match rdy. Returns 0 on success. */
+static int
+nvme_wait_csts_rdy(struct nvme_ctrl *ctrl, unsigned rdy)
+{
+ u32 const max_to = 500 /* ms */ * ((ctrl->reg->cap >> 24) & 0xFFU);
+ u32 to = timer_calc(max_to);
+ u32 csts;
+
+ while (rdy != ((csts = ctrl->reg->csts) & NVME_CSTS_RDY)) {
+ yield();
+
+ if (csts & NVME_CSTS_FATAL) {
+ dprintf(3, "NVMe fatal error during controller shutdown\n");
+ return -1;
+ }
+
+ if (timer_check(to)) {
+ warn_timeout();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* Returns 0 on success. */
+static int
+nvme_controller_enable(struct nvme_ctrl *ctrl)
+{
+ int rc;
+
+ pci_enable_busmaster(ctrl->pci);
+
+ /* Turn the controller off. */
+ ctrl->reg->cc = 0;
+ if (nvme_wait_csts_rdy(ctrl, 0)) {
+ dprintf(2, "NVMe fatal error during controller shutdown\n");
+ return -1;
+ }
+
+ ctrl->doorbell_stride = 4U << ((ctrl->reg->cap >> 32) & 0xF);
+
+ rc = nvme_init_cq(ctrl, &ctrl->admin_cq, 1,
+ NVME_PAGE_SIZE / sizeof(struct nvme_cqe));
+ if (rc) {
+ return -1;
+ }
+
+ rc = nvme_init_sq(ctrl, &ctrl->admin_sq, 0,
+ NVME_PAGE_SIZE / sizeof(struct nvme_sqe), &ctrl->admin_cq);
+ if (rc) {
+ goto err_destroy_admin_cq;
+ }
+
+ ctrl->reg->aqa = ctrl->admin_cq.common.mask << 16
+ | ctrl->admin_sq.common.mask;
+
+ ctrl->reg->asq = (u32)ctrl->admin_sq.sqe;
+ ctrl->reg->acq = (u32)ctrl->admin_cq.cqe;
+
+ dprintf(3, " admin submission queue: %p\n", ctrl->admin_sq.sqe);
+ dprintf(3, " admin completion queue: %p\n", ctrl->admin_cq.cqe);
+
+ ctrl->reg->cc = NVME_CC_EN | (NVME_CQE_SIZE_LOG << 20)
+ | (NVME_SQE_SIZE_LOG << 16 /* IOSQES */);
+
+ if (nvme_wait_csts_rdy(ctrl, 1)) {
+ dprintf(2, "NVMe fatal error while enabling controller\n");
+ goto err_destroy_admin_sq;
+ }
+
+ /* The admin queue is set up and the controller is ready. Let's figure out
+ what namespaces we have. */
+
+ struct nvme_identify_ctrl *identify = nvme_admin_identify_ctrl(ctrl);
+
+ if (!identify) {
+ dprintf(2, "NVMe couldn't identify controller.\n");
+ goto err_destroy_admin_sq;
+ }
+
+ dprintf(3, "NVMe has %u namespace%s.\n",
+ identify->nn, (identify->nn == 1) ? "" : "s");
+
+ ctrl->ns_count = identify->nn;
+ free(identify);
+
+ if ((ctrl->ns_count == 0) || nvme_create_io_queues(ctrl)) {
+ /* No point to continue, if the controller says it doesn't have
+ namespaces or we couldn't create I/O queues. */
+ goto err_destroy_admin_sq;
+ }
+
+ /* Populate namespace IDs */
+ int ns_idx;
+ for (ns_idx = 0; ns_idx < ctrl->ns_count; ns_idx++) {
+ nvme_probe_ns(ctrl, ns_idx, identify->mdts);
+ }
+
+ dprintf(3, "NVMe initialization complete!\n");
+ return 0;
+
+ err_destroy_admin_sq:
+ nvme_destroy_sq(&ctrl->admin_sq);
+ err_destroy_admin_cq:
+ nvme_destroy_cq(&ctrl->admin_cq);
+ return -1;
+}
+
+/* Initialize an NVMe controller and detect its drives. */
+static void
+nvme_controller_setup(void *opaque)
+{
+ u8 skip_nonbootable = is_bootprio_strict();
+ struct pci_device *pci = opaque;
+
+ if (skip_nonbootable && bootprio_find_pci_device(pci) < 0) {
+ dprintf(1, "skipping init of a non-bootable NVMe at %pP\n",
+ pci);
+ goto err;
+ }
+
+ struct nvme_reg volatile *reg = pci_enable_membar(pci, PCI_BASE_ADDRESS_0);
+ if (!reg)
+ return;
+
+ u32 version = reg->vs;
+ dprintf(3, "Found NVMe controller with version %u.%u.%u.\n",
+ version >> 16, (version >> 8) & 0xFF, version & 0xFF);
+ dprintf(3, " Capabilities %016llx\n", reg->cap);
+
+ if (~reg->cap & NVME_CAP_CSS_NVME) {
+ dprintf(3, "Controller doesn't speak NVMe command set. Skipping.\n");
+ goto err;
+ }
+
+ struct nvme_ctrl *ctrl = malloc_high(sizeof(*ctrl));
+ if (!ctrl) {
+ warn_noalloc();
+ goto err;
+ }
+
+ memset(ctrl, 0, sizeof(*ctrl));
+
+ ctrl->reg = reg;
+ ctrl->pci = pci;
+
+ if (nvme_controller_enable(ctrl)) {
+ goto err_free_ctrl;
+ }
+
+ return;
+
+ err_free_ctrl:
+ free(ctrl);
+ err:
+ dprintf(2, "Failed to enable NVMe controller.\n");
+}
+
+// Locate and init NVMe controllers
+static void
+nvme_scan(void)
+{
+ // Scan PCI bus for NVMe adapters
+ struct pci_device *pci;
+
+ foreachpci(pci) {
+ if (pci->class != PCI_CLASS_STORAGE_NVME)
+ continue;
+ if (pci->prog_if != 2 /* as of NVM 1.0e */) {
+ dprintf(3, "Found incompatble NVMe: prog-if=%02x\n", pci->prog_if);
+ continue;
+ }
+
+ run_thread(nvme_controller_setup, pci);
+ }
+}
+
+static int
+nvme_cmd_readwrite(struct nvme_namespace *ns, struct disk_op_s *op, int write)
+{
+ int res = DISK_RET_SUCCESS;
+ u16 const max_blocks = NVME_PAGE_SIZE / ns->block_size;
+ u16 i, blocks;
+
+ for (i = 0; i < op->count && res == DISK_RET_SUCCESS;) {
+ u16 blocks_remaining = op->count - i;
+ char *op_buf = op->buf_fl + i * ns->block_size;
+
+ blocks = nvme_build_prpl(ns, op_buf, blocks_remaining);
+ if (blocks) {
+ res = nvme_io_readwrite(ns, op->lba + i, ns->prp1, blocks, write);
+ dprintf(5, "ns %u %s lba %llu+%u: %d\n", ns->ns_id, write ? "write"
+ : "read",
+ op->lba, blocks, res);
+ } else {
+ blocks = blocks_remaining < max_blocks ? blocks_remaining
+ : max_blocks;
+
+ if (write) {
+ memcpy(ns->dma_buffer, op_buf, blocks * ns->block_size);
+ }
+
+ res = nvme_io_readwrite(ns, op->lba + i, ns->dma_buffer, blocks, write);
+ dprintf(5, "ns %u %s lba %llu+%u: %d\n", ns->ns_id, write ? "write"
+ : "read",
+ op->lba + i, blocks, res);
+
+ if (!write && res == DISK_RET_SUCCESS) {
+ memcpy(op_buf, ns->dma_buffer, blocks * ns->block_size);
+ }
+ }
+
+ i += blocks;
+ }
+
+ return res;
+}
+
+int
+nvme_process_op(struct disk_op_s *op)
+{
+ if (!CONFIG_NVME)
+ return DISK_RET_SUCCESS;
+
+ struct nvme_namespace *ns = container_of(op->drive_fl, struct nvme_namespace,
+ drive);
+
+ switch (op->command) {
+ case CMD_READ:
+ case CMD_WRITE:
+ return nvme_cmd_readwrite(ns, op, op->command == CMD_WRITE);
+ default:
+ return default_process_op(op);
+ }
+}
+
+void
+nvme_setup(void)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_NVME)
+ return;
+
+ dprintf(3, "init nvme\n");
+ nvme_scan();
+}
+
+/* EOF */
diff --git a/roms/seabios-hppa/src/hw/nvme.h b/roms/seabios-hppa/src/hw/nvme.h
new file mode 100644
index 000000000..4dbb70ae7
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/nvme.h
@@ -0,0 +1,17 @@
+// External interfaces for low level NVMe support
+//
+// Copyright 2017 Amazon.com, Inc. or its affiliates.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#ifndef __NVME_H
+#define __NVME_H
+
+#include "block.h" // struct disk_op_s
+
+void nvme_setup(void);
+int nvme_process_op(struct disk_op_s *op);
+
+#endif
+
+/* EOF */
diff --git a/roms/seabios-hppa/src/hw/pci.c b/roms/seabios-hppa/src/hw/pci.c
new file mode 100644
index 000000000..ecc724b06
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/pci.c
@@ -0,0 +1,183 @@
+// PCI config space access functions.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "output.h" // dprintf
+#include "pci.h" // pci_config_writel
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "byteorder.h" // cpu_to_le16
+#include "util.h" // udelay
+#include "x86.h" // outl
+
+#if CONFIG_X86
+#define PORT_PCI_CMD 0x0cf8
+#define PORT_PCI_DATA 0x0cfc
+#elif CONFIG_PARISC
+#include "parisc/hppa_hardware.h"
+#endif
+
+static u32 mmconfig;
+
+static void *mmconfig_addr(u16 bdf, u32 addr)
+{
+ return (void*)(mmconfig + ((u32)bdf << 12) + addr);
+}
+
+static u32 ioconfig_cmd(u16 bdf, u32 addr)
+{
+ return 0x80000000 | (bdf << 8) | (addr & 0xfc);
+}
+
+void pci_config_writel(u16 bdf, u32 addr, u32 val)
+{
+ if (!MODESEGMENT && mmconfig) {
+ writel(mmconfig_addr(bdf, addr), val);
+ } else {
+ outl(ioconfig_cmd(bdf, addr), PORT_PCI_CMD);
+ outl(cpu_to_le32(val), PORT_PCI_DATA);
+ }
+}
+
+void pci_config_writew(u16 bdf, u32 addr, u16 val)
+{
+ if (!MODESEGMENT && mmconfig) {
+ writew(mmconfig_addr(bdf, addr), val);
+ } else {
+ outl(ioconfig_cmd(bdf, addr), PORT_PCI_CMD);
+ outw(cpu_to_le16(val), PORT_PCI_DATA + (addr & 2));
+ }
+}
+
+void pci_config_writeb(u16 bdf, u32 addr, u8 val)
+{
+ if (!MODESEGMENT && mmconfig) {
+ writeb(mmconfig_addr(bdf, addr), val);
+ } else {
+ outl(ioconfig_cmd(bdf, addr), PORT_PCI_CMD);
+ outb(val, PORT_PCI_DATA + (addr & 3));
+ }
+}
+
+u32 pci_config_readl(u16 bdf, u32 addr)
+{
+ if (!MODESEGMENT && mmconfig) {
+ return readl(mmconfig_addr(bdf, addr));
+ } else {
+ outl(ioconfig_cmd(bdf, addr), PORT_PCI_CMD);
+ return le32_to_cpu(inl(PORT_PCI_DATA));
+ }
+}
+
+u16 pci_config_readw(u16 bdf, u32 addr)
+{
+ if (!MODESEGMENT && mmconfig) {
+ return readw(mmconfig_addr(bdf, addr));
+ } else {
+ outl(ioconfig_cmd(bdf, addr), PORT_PCI_CMD);
+ return le16_to_cpu(inw(PORT_PCI_DATA + (addr & 2)));
+ }
+}
+
+u8 pci_config_readb(u16 bdf, u32 addr)
+{
+ if (!MODESEGMENT && mmconfig) {
+ return readb(mmconfig_addr(bdf, addr));
+ } else {
+ outl(ioconfig_cmd(bdf, addr), PORT_PCI_CMD);
+ return inb(PORT_PCI_DATA + (addr & 3));
+ }
+}
+
+void
+pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on)
+{
+ u16 val = pci_config_readw(bdf, addr);
+ val = (val & ~off) | on;
+ pci_config_writew(bdf, addr, val);
+}
+
+void
+pci_enable_mmconfig(u64 addr, const char *name)
+{
+ if (addr >= 0x100000000ll)
+ return;
+ dprintf(1, "PCIe: using %s mmconfig at 0x%llx\n", name, addr);
+ mmconfig = addr;
+}
+
+u8 pci_find_capability(u16 bdf, u8 cap_id, u8 cap)
+{
+ int i;
+ u16 status = pci_config_readw(bdf, PCI_STATUS);
+
+ if (!(status & PCI_STATUS_CAP_LIST))
+ return 0;
+
+ if (cap == 0) {
+ /* find first */
+ cap = pci_config_readb(bdf, PCI_CAPABILITY_LIST);
+ } else {
+ /* find next */
+ cap = pci_config_readb(bdf, cap + PCI_CAP_LIST_NEXT);
+ }
+ for (i = 0; cap && i <= 0xff; i++) {
+ if (pci_config_readb(bdf, cap + PCI_CAP_LIST_ID) == cap_id)
+ return cap;
+ cap = pci_config_readb(bdf, cap + PCI_CAP_LIST_NEXT);
+ }
+
+ return 0;
+}
+
+// Helper function for foreachbdf() macro - return next device
+int
+pci_next(int bdf, int bus)
+{
+ if (pci_bdf_to_fn(bdf) == 0
+ && (pci_config_readb(bdf, PCI_HEADER_TYPE) & 0x80) == 0)
+ // Last found device wasn't a multi-function device - skip to
+ // the next device.
+ bdf += 8;
+ else
+ bdf += 1;
+
+ for (;;) {
+ if (pci_bdf_to_bus(bdf) != bus)
+ return -1;
+
+ u16 v = pci_config_readw(bdf, PCI_VENDOR_ID);
+ if (v != 0x0000 && v != 0xffff)
+ // Device is present.
+ return bdf;
+
+ if (pci_bdf_to_fn(bdf) == 0)
+ bdf += 8;
+ else
+ bdf += 1;
+ }
+}
+
+// Check if PCI is available at all
+int
+pci_probe_host(void)
+{
+ outl(0x80000000, PORT_PCI_CMD);
+ if (inl(PORT_PCI_CMD) != 0x80000000) {
+ dprintf(1, "Detected non-PCI system\n");
+ return -1;
+ }
+ return 0;
+}
+
+void
+pci_reboot(void)
+{
+ u8 v = inb(PORT_PCI_REBOOT) & ~6;
+ outb(v|2, PORT_PCI_REBOOT); /* Request hard reset */
+ udelay(50);
+ outb(v|6, PORT_PCI_REBOOT); /* Actually do the reset */
+ udelay(50);
+}
diff --git a/roms/seabios-hppa/src/hw/pci.h b/roms/seabios-hppa/src/hw/pci.h
new file mode 100644
index 000000000..01c51f705
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/pci.h
@@ -0,0 +1,48 @@
+#ifndef __PCI_H
+#define __PCI_H
+
+#include "types.h" // u32
+
+#define PORT_PCI_REBOOT 0x0cf9
+
+static inline u8 pci_bdf_to_bus(u16 bdf) {
+ return bdf >> 8;
+}
+static inline u8 pci_bdf_to_devfn(u16 bdf) {
+ return bdf & 0xff;
+}
+static inline u16 pci_bdf_to_busdev(u16 bdf) {
+ return bdf & ~0x07;
+}
+static inline u8 pci_bdf_to_dev(u16 bdf) {
+ return (bdf >> 3) & 0x1f;
+}
+static inline u8 pci_bdf_to_fn(u16 bdf) {
+ return bdf & 0x07;
+}
+static inline u16 pci_to_bdf(int bus, int dev, int fn) {
+ return (bus<<8) | (dev<<3) | fn;
+}
+static inline u16 pci_bus_devfn_to_bdf(int bus, u16 devfn) {
+ return (bus << 8) | devfn;
+}
+
+#define foreachbdf(BDF, BUS) \
+ for (BDF=pci_next(pci_bus_devfn_to_bdf((BUS), 0)-1, (BUS)) \
+ ; BDF >= 0 \
+ ; BDF=pci_next(BDF, (BUS)))
+
+void pci_config_writel(u16 bdf, u32 addr, u32 val);
+void pci_config_writew(u16 bdf, u32 addr, u16 val);
+void pci_config_writeb(u16 bdf, u32 addr, u8 val);
+u32 pci_config_readl(u16 bdf, u32 addr);
+u16 pci_config_readw(u16 bdf, u32 addr);
+u8 pci_config_readb(u16 bdf, u32 addr);
+void pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on);
+void pci_enable_mmconfig(u64 addr, const char *name);
+u8 pci_find_capability(u16 bdf, u8 cap_id, u8 cap);
+int pci_next(int bdf, int bus);
+int pci_probe_host(void);
+void pci_reboot(void);
+
+#endif // pci.h
diff --git a/roms/seabios-hppa/src/hw/pci_ids.h b/roms/seabios-hppa/src/hw/pci_ids.h
new file mode 100644
index 000000000..109646161
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/pci_ids.h
@@ -0,0 +1,2632 @@
+/*
+ * PCI Class, Vendor and Device IDs
+ *
+ * Please keep sorted.
+ */
+
+/* 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_SATA 0x0106
+#define PCI_CLASS_STORAGE_SATA_AHCI 0x010601
+#define PCI_CLASS_STORAGE_SAS 0x0107
+#define PCI_CLASS_STORAGE_NVME 0x0108
+#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_PIC_IOAPIC 0x080010
+#define PCI_CLASS_SYSTEM_PIC_IOXAPIC 0x080020
+#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_SDHCI 0x0805
+#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_FIREWIRE_OHCI 0x0c0010
+#define PCI_CLASS_SERIAL_ACCESS 0x0c01
+#define PCI_CLASS_SERIAL_SSA 0x0c02
+#define PCI_CLASS_SERIAL_USB 0x0c03
+#define PCI_CLASS_SERIAL_USB_UHCI 0x0c0300
+#define PCI_CLASS_SERIAL_USB_OHCI 0x0c0310
+#define PCI_CLASS_SERIAL_USB_EHCI 0x0c0320
+#define PCI_CLASS_SERIAL_USB_XHCI 0x0c0330
+#define PCI_CLASS_SERIAL_FIBER 0x0c04
+#define PCI_CLASS_SERIAL_SMBUS 0x0c05
+
+#define PCI_BASE_CLASS_WIRELESS 0x0d
+#define PCI_CLASS_WIRELESS_RF_CONTROLLER 0x0d10
+#define PCI_CLASS_WIRELESS_WHCI 0x0d1010
+
+#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 and devices. Sort key: vendor first, device next. */
+
+#define PCI_VENDOR_ID_TTTECH 0x0357
+#define PCI_DEVICE_ID_TTTECH_MC322 0x000a
+
+#define PCI_VENDOR_ID_DYNALINK 0x0675
+#define PCI_DEVICE_ID_DYNALINK_IS64PH 0x1702
+
+#define PCI_VENDOR_ID_BERKOM 0x0871
+#define PCI_DEVICE_ID_BERKOM_A1T 0xffa1
+#define PCI_DEVICE_ID_BERKOM_T_CONCEPT 0xffa2
+#define PCI_DEVICE_ID_BERKOM_A4T 0xffa4
+#define PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO 0xffa8
+
+#define PCI_VENDOR_ID_COMPAQ 0x0e11
+#define PCI_DEVICE_ID_COMPAQ_TOKENRING 0x0508
+#define PCI_DEVICE_ID_COMPAQ_TACHYON 0xa0fc
+#define PCI_DEVICE_ID_COMPAQ_SMART2P 0xae10
+#define PCI_DEVICE_ID_COMPAQ_NETEL100 0xae32
+#define PCI_DEVICE_ID_COMPAQ_NETEL10 0xae34
+#define PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE 0xae33
+#define PCI_DEVICE_ID_COMPAQ_NETFLEX3I 0xae35
+#define PCI_DEVICE_ID_COMPAQ_NETEL100D 0xae40
+#define PCI_DEVICE_ID_COMPAQ_NETEL100PI 0xae43
+#define PCI_DEVICE_ID_COMPAQ_NETEL100I 0xb011
+#define PCI_DEVICE_ID_COMPAQ_CISS 0xb060
+#define PCI_DEVICE_ID_COMPAQ_CISSB 0xb178
+#define PCI_DEVICE_ID_COMPAQ_CISSC 0x46
+#define PCI_DEVICE_ID_COMPAQ_THUNDER 0xf130
+#define PCI_DEVICE_ID_COMPAQ_NETFLEX3B 0xf150
+
+#define PCI_VENDOR_ID_NCR 0x1000
+#define PCI_VENDOR_ID_LSI_LOGIC 0x1000
+#define PCI_DEVICE_ID_NCR_53C810 0x0001
+#define PCI_DEVICE_ID_NCR_53C820 0x0002
+#define PCI_DEVICE_ID_NCR_53C825 0x0003
+#define PCI_DEVICE_ID_NCR_53C815 0x0004
+#define PCI_DEVICE_ID_LSI_53C810AP 0x0005
+#define PCI_DEVICE_ID_NCR_53C860 0x0006
+#define PCI_DEVICE_ID_LSI_53C1510 0x000a
+#define PCI_DEVICE_ID_NCR_53C896 0x000b
+#define PCI_DEVICE_ID_NCR_53C895 0x000c
+#define PCI_DEVICE_ID_NCR_53C885 0x000d
+#define PCI_DEVICE_ID_NCR_53C875 0x000f
+#define PCI_DEVICE_ID_NCR_53C1510 0x0010
+#define PCI_DEVICE_ID_LSI_53C895A 0x0012
+#define PCI_DEVICE_ID_LSI_53C875A 0x0013
+#define PCI_DEVICE_ID_LSI_53C1010_33 0x0020
+#define PCI_DEVICE_ID_LSI_53C1010_66 0x0021
+#define PCI_DEVICE_ID_LSI_53C1030 0x0030
+#define PCI_DEVICE_ID_LSI_1030_53C1035 0x0032
+#define PCI_DEVICE_ID_LSI_53C1035 0x0040
+#define PCI_DEVICE_ID_NCR_53C875J 0x008f
+#define PCI_DEVICE_ID_LSI_FC909 0x0621
+#define PCI_DEVICE_ID_LSI_FC929 0x0622
+#define PCI_DEVICE_ID_LSI_FC929_LAN 0x0623
+#define PCI_DEVICE_ID_LSI_FC919 0x0624
+#define PCI_DEVICE_ID_LSI_FC919_LAN 0x0625
+#define PCI_DEVICE_ID_LSI_FC929X 0x0626
+#define PCI_DEVICE_ID_LSI_FC939X 0x0642
+#define PCI_DEVICE_ID_LSI_FC949X 0x0640
+#define PCI_DEVICE_ID_LSI_FC949ES 0x0646
+#define PCI_DEVICE_ID_LSI_FC919X 0x0628
+#define PCI_DEVICE_ID_NCR_YELLOWFIN 0x0701
+#define PCI_DEVICE_ID_LSI_61C102 0x0901
+#define PCI_DEVICE_ID_LSI_63C815 0x1000
+#define PCI_DEVICE_ID_LSI_SAS1064 0x0050
+#define PCI_DEVICE_ID_LSI_SAS1064R 0x0411
+#define PCI_DEVICE_ID_LSI_VERDE_ZCR 0x0413
+#define PCI_DEVICE_ID_LSI_SAS1066 0x005E
+#define PCI_DEVICE_ID_LSI_SAS1068 0x0054
+#define PCI_DEVICE_ID_LSI_SAS1064A 0x005C
+#define PCI_DEVICE_ID_LSI_SAS1064E 0x0056
+#define PCI_DEVICE_ID_LSI_SAS1066E 0x005A
+#define PCI_DEVICE_ID_LSI_SAS1068E 0x0058
+#define PCI_DEVICE_ID_LSI_SAS1078 0x0060
+#define PCI_DEVICE_ID_LSI_SAS1078DE 0x007C
+#define PCI_DEVICE_ID_LSI_SAS2108E 0x0078
+#define PCI_DEVICE_ID_LSI_SAS2108 0x0079
+#define PCI_DEVICE_ID_LSI_SAS2208 0x005B
+#define PCI_DEVICE_ID_LSI_SAS3108 0x005D
+#define PCI_DEVICE_ID_LSI_SAS2004 0x0071
+#define PCI_DEVICE_ID_LSI_SAS2008 0x0073
+
+#define PCI_VENDOR_ID_ATI 0x1002
+/* Mach64 */
+#define PCI_DEVICE_ID_ATI_68800 0x4158
+#define PCI_DEVICE_ID_ATI_215CT222 0x4354
+#define PCI_DEVICE_ID_ATI_210888CX 0x4358
+#define PCI_DEVICE_ID_ATI_215ET222 0x4554
+/* Mach64 / Rage */
+#define PCI_DEVICE_ID_ATI_215GB 0x4742
+#define PCI_DEVICE_ID_ATI_215GD 0x4744
+#define PCI_DEVICE_ID_ATI_215GI 0x4749
+#define PCI_DEVICE_ID_ATI_215GP 0x4750
+#define PCI_DEVICE_ID_ATI_215GQ 0x4751
+#define PCI_DEVICE_ID_ATI_215XL 0x4752
+#define PCI_DEVICE_ID_ATI_215GT 0x4754
+#define PCI_DEVICE_ID_ATI_215GTB 0x4755
+#define PCI_DEVICE_ID_ATI_215_IV 0x4756
+#define PCI_DEVICE_ID_ATI_215_IW 0x4757
+#define PCI_DEVICE_ID_ATI_215_IZ 0x475A
+#define PCI_DEVICE_ID_ATI_210888GX 0x4758
+#define PCI_DEVICE_ID_ATI_215_LB 0x4c42
+#define PCI_DEVICE_ID_ATI_215_LD 0x4c44
+#define PCI_DEVICE_ID_ATI_215_LG 0x4c47
+#define PCI_DEVICE_ID_ATI_215_LI 0x4c49
+#define PCI_DEVICE_ID_ATI_215_LM 0x4c4D
+#define PCI_DEVICE_ID_ATI_215_LN 0x4c4E
+#define PCI_DEVICE_ID_ATI_215_LR 0x4c52
+#define PCI_DEVICE_ID_ATI_215_LS 0x4c53
+#define PCI_DEVICE_ID_ATI_264_LT 0x4c54
+/* Mach64 VT */
+#define PCI_DEVICE_ID_ATI_264VT 0x5654
+#define PCI_DEVICE_ID_ATI_264VU 0x5655
+#define PCI_DEVICE_ID_ATI_264VV 0x5656
+/* Rage128 GL */
+#define PCI_DEVICE_ID_ATI_RAGE128_RE 0x5245
+#define PCI_DEVICE_ID_ATI_RAGE128_RF 0x5246
+#define PCI_DEVICE_ID_ATI_RAGE128_RG 0x5247
+/* Rage128 VR */
+#define PCI_DEVICE_ID_ATI_RAGE128_RK 0x524b
+#define PCI_DEVICE_ID_ATI_RAGE128_RL 0x524c
+#define PCI_DEVICE_ID_ATI_RAGE128_SE 0x5345
+#define PCI_DEVICE_ID_ATI_RAGE128_SF 0x5346
+#define PCI_DEVICE_ID_ATI_RAGE128_SG 0x5347
+#define PCI_DEVICE_ID_ATI_RAGE128_SH 0x5348
+#define PCI_DEVICE_ID_ATI_RAGE128_SK 0x534b
+#define PCI_DEVICE_ID_ATI_RAGE128_SL 0x534c
+#define PCI_DEVICE_ID_ATI_RAGE128_SM 0x534d
+#define PCI_DEVICE_ID_ATI_RAGE128_SN 0x534e
+/* Rage128 Ultra */
+#define PCI_DEVICE_ID_ATI_RAGE128_TF 0x5446
+#define PCI_DEVICE_ID_ATI_RAGE128_TL 0x544c
+#define PCI_DEVICE_ID_ATI_RAGE128_TR 0x5452
+#define PCI_DEVICE_ID_ATI_RAGE128_TS 0x5453
+#define PCI_DEVICE_ID_ATI_RAGE128_TT 0x5454
+#define PCI_DEVICE_ID_ATI_RAGE128_TU 0x5455
+/* Rage128 M3 */
+#define PCI_DEVICE_ID_ATI_RAGE128_LE 0x4c45
+#define PCI_DEVICE_ID_ATI_RAGE128_LF 0x4c46
+/* Rage128 M4 */
+#define PCI_DEVICE_ID_ATI_RAGE128_MF 0x4d46
+#define PCI_DEVICE_ID_ATI_RAGE128_ML 0x4d4c
+/* Rage128 Pro GL */
+#define PCI_DEVICE_ID_ATI_RAGE128_PA 0x5041
+#define PCI_DEVICE_ID_ATI_RAGE128_PB 0x5042
+#define PCI_DEVICE_ID_ATI_RAGE128_PC 0x5043
+#define PCI_DEVICE_ID_ATI_RAGE128_PD 0x5044
+#define PCI_DEVICE_ID_ATI_RAGE128_PE 0x5045
+#define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046
+/* Rage128 Pro VR */
+#define PCI_DEVICE_ID_ATI_RAGE128_PG 0x5047
+#define PCI_DEVICE_ID_ATI_RAGE128_PH 0x5048
+#define PCI_DEVICE_ID_ATI_RAGE128_PI 0x5049
+#define PCI_DEVICE_ID_ATI_RAGE128_PJ 0x504A
+#define PCI_DEVICE_ID_ATI_RAGE128_PK 0x504B
+#define PCI_DEVICE_ID_ATI_RAGE128_PL 0x504C
+#define PCI_DEVICE_ID_ATI_RAGE128_PM 0x504D
+#define PCI_DEVICE_ID_ATI_RAGE128_PN 0x504E
+#define PCI_DEVICE_ID_ATI_RAGE128_PO 0x504F
+#define PCI_DEVICE_ID_ATI_RAGE128_PP 0x5050
+#define PCI_DEVICE_ID_ATI_RAGE128_PQ 0x5051
+#define PCI_DEVICE_ID_ATI_RAGE128_PR 0x5052
+#define PCI_DEVICE_ID_ATI_RAGE128_PS 0x5053
+#define PCI_DEVICE_ID_ATI_RAGE128_PT 0x5054
+#define PCI_DEVICE_ID_ATI_RAGE128_PU 0x5055
+#define PCI_DEVICE_ID_ATI_RAGE128_PV 0x5056
+#define PCI_DEVICE_ID_ATI_RAGE128_PW 0x5057
+#define PCI_DEVICE_ID_ATI_RAGE128_PX 0x5058
+/* Rage128 M4 */
+/* Radeon R100 */
+#define PCI_DEVICE_ID_ATI_RADEON_QD 0x5144
+#define PCI_DEVICE_ID_ATI_RADEON_QE 0x5145
+#define PCI_DEVICE_ID_ATI_RADEON_QF 0x5146
+#define PCI_DEVICE_ID_ATI_RADEON_QG 0x5147
+/* Radeon RV100 (VE) */
+#define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159
+#define PCI_DEVICE_ID_ATI_RADEON_QZ 0x515a
+/* Radeon R200 (8500) */
+#define PCI_DEVICE_ID_ATI_RADEON_QL 0x514c
+#define PCI_DEVICE_ID_ATI_RADEON_QN 0x514e
+#define PCI_DEVICE_ID_ATI_RADEON_QO 0x514f
+#define PCI_DEVICE_ID_ATI_RADEON_Ql 0x516c
+#define PCI_DEVICE_ID_ATI_RADEON_BB 0x4242
+/* Radeon R200 (9100) */
+#define PCI_DEVICE_ID_ATI_RADEON_QM 0x514d
+/* Radeon RV200 (7500) */
+#define PCI_DEVICE_ID_ATI_RADEON_QW 0x5157
+#define PCI_DEVICE_ID_ATI_RADEON_QX 0x5158
+/* Radeon NV-100 */
+/* Radeon RV250 (9000) */
+#define PCI_DEVICE_ID_ATI_RADEON_Id 0x4964
+#define PCI_DEVICE_ID_ATI_RADEON_Ie 0x4965
+#define PCI_DEVICE_ID_ATI_RADEON_If 0x4966
+#define PCI_DEVICE_ID_ATI_RADEON_Ig 0x4967
+/* Radeon RV280 (9200) */
+#define PCI_DEVICE_ID_ATI_RADEON_Ya 0x5961
+#define PCI_DEVICE_ID_ATI_RADEON_Yd 0x5964
+/* Radeon R300 (9500) */
+/* Radeon R300 (9700) */
+#define PCI_DEVICE_ID_ATI_RADEON_ND 0x4e44
+#define PCI_DEVICE_ID_ATI_RADEON_NE 0x4e45
+#define PCI_DEVICE_ID_ATI_RADEON_NF 0x4e46
+#define PCI_DEVICE_ID_ATI_RADEON_NG 0x4e47
+/* Radeon R350 (9800) */
+/* Radeon RV350 (9600) */
+/* Radeon M6 */
+#define PCI_DEVICE_ID_ATI_RADEON_LY 0x4c59
+#define PCI_DEVICE_ID_ATI_RADEON_LZ 0x4c5a
+/* Radeon M7 */
+#define PCI_DEVICE_ID_ATI_RADEON_LW 0x4c57
+#define PCI_DEVICE_ID_ATI_RADEON_LX 0x4c58
+/* Radeon M9 */
+#define PCI_DEVICE_ID_ATI_RADEON_Ld 0x4c64
+#define PCI_DEVICE_ID_ATI_RADEON_Le 0x4c65
+#define PCI_DEVICE_ID_ATI_RADEON_Lf 0x4c66
+#define PCI_DEVICE_ID_ATI_RADEON_Lg 0x4c67
+/* Radeon */
+/* RadeonIGP */
+#define PCI_DEVICE_ID_ATI_RS100 0xcab0
+#define PCI_DEVICE_ID_ATI_RS200 0xcab2
+#define PCI_DEVICE_ID_ATI_RS200_B 0xcbb2
+#define PCI_DEVICE_ID_ATI_RS250 0xcab3
+#define PCI_DEVICE_ID_ATI_RS300_100 0x5830
+#define PCI_DEVICE_ID_ATI_RS300_133 0x5831
+#define PCI_DEVICE_ID_ATI_RS300_166 0x5832
+#define PCI_DEVICE_ID_ATI_RS300_200 0x5833
+#define PCI_DEVICE_ID_ATI_RS350_100 0x7830
+#define PCI_DEVICE_ID_ATI_RS350_133 0x7831
+#define PCI_DEVICE_ID_ATI_RS350_166 0x7832
+#define PCI_DEVICE_ID_ATI_RS350_200 0x7833
+#define PCI_DEVICE_ID_ATI_RS400_100 0x5a30
+#define PCI_DEVICE_ID_ATI_RS400_133 0x5a31
+#define PCI_DEVICE_ID_ATI_RS400_166 0x5a32
+#define PCI_DEVICE_ID_ATI_RS400_200 0x5a33
+#define PCI_DEVICE_ID_ATI_RS480 0x5950
+/* ATI IXP Chipset */
+#define PCI_DEVICE_ID_ATI_IXP200_IDE 0x4349
+#define PCI_DEVICE_ID_ATI_IXP200_SMBUS 0x4353
+#define PCI_DEVICE_ID_ATI_IXP300_SMBUS 0x4363
+#define PCI_DEVICE_ID_ATI_IXP300_IDE 0x4369
+#define PCI_DEVICE_ID_ATI_IXP300_SATA 0x436e
+#define PCI_DEVICE_ID_ATI_IXP400_SMBUS 0x4372
+#define PCI_DEVICE_ID_ATI_IXP400_IDE 0x4376
+#define PCI_DEVICE_ID_ATI_IXP400_SATA 0x4379
+#define PCI_DEVICE_ID_ATI_IXP400_SATA2 0x437a
+#define PCI_DEVICE_ID_ATI_IXP600_SATA 0x4380
+#define PCI_DEVICE_ID_ATI_SBX00_SMBUS 0x4385
+#define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c
+#define PCI_DEVICE_ID_ATI_IXP700_SATA 0x4390
+#define PCI_DEVICE_ID_ATI_IXP700_IDE 0x439c
+
+#define PCI_VENDOR_ID_VLSI 0x1004
+#define PCI_DEVICE_ID_VLSI_82C592 0x0005
+#define PCI_DEVICE_ID_VLSI_82C593 0x0006
+#define PCI_DEVICE_ID_VLSI_82C594 0x0007
+#define PCI_DEVICE_ID_VLSI_82C597 0x0009
+#define PCI_DEVICE_ID_VLSI_82C541 0x000c
+#define PCI_DEVICE_ID_VLSI_82C543 0x000d
+#define PCI_DEVICE_ID_VLSI_82C532 0x0101
+#define PCI_DEVICE_ID_VLSI_82C534 0x0102
+#define PCI_DEVICE_ID_VLSI_82C535 0x0104
+#define PCI_DEVICE_ID_VLSI_82C147 0x0105
+#define PCI_DEVICE_ID_VLSI_VAS96011 0x0702
+
+#define PCI_VENDOR_ID_ADL 0x1005
+#define PCI_DEVICE_ID_ADL_2301 0x2301
+
+#define PCI_VENDOR_ID_NS 0x100b
+#define PCI_DEVICE_ID_NS_87415 0x0002
+#define PCI_DEVICE_ID_NS_87560_LIO 0x000e
+#define PCI_DEVICE_ID_NS_87560_USB 0x0012
+#define PCI_DEVICE_ID_NS_83815 0x0020
+#define PCI_DEVICE_ID_NS_83820 0x0022
+#define PCI_DEVICE_ID_NS_CS5535_ISA 0x002b
+#define PCI_DEVICE_ID_NS_CS5535_IDE 0x002d
+#define PCI_DEVICE_ID_NS_CS5535_AUDIO 0x002e
+#define PCI_DEVICE_ID_NS_CS5535_USB 0x002f
+#define PCI_DEVICE_ID_NS_GX_VIDEO 0x0030
+#define PCI_DEVICE_ID_NS_SATURN 0x0035
+#define PCI_DEVICE_ID_NS_SCx200_BRIDGE 0x0500
+#define PCI_DEVICE_ID_NS_SCx200_SMI 0x0501
+#define PCI_DEVICE_ID_NS_SCx200_IDE 0x0502
+#define PCI_DEVICE_ID_NS_SCx200_AUDIO 0x0503
+#define PCI_DEVICE_ID_NS_SCx200_VIDEO 0x0504
+#define PCI_DEVICE_ID_NS_SCx200_XBUS 0x0505
+#define PCI_DEVICE_ID_NS_SC1100_BRIDGE 0x0510
+#define PCI_DEVICE_ID_NS_SC1100_SMI 0x0511
+#define PCI_DEVICE_ID_NS_SC1100_XBUS 0x0515
+#define PCI_DEVICE_ID_NS_87410 0xd001
+
+#define PCI_DEVICE_ID_NS_GX_HOST_BRIDGE 0x0028
+
+#define PCI_VENDOR_ID_TSENG 0x100c
+#define PCI_DEVICE_ID_TSENG_W32P_2 0x3202
+#define PCI_DEVICE_ID_TSENG_W32P_b 0x3205
+#define PCI_DEVICE_ID_TSENG_W32P_c 0x3206
+#define PCI_DEVICE_ID_TSENG_W32P_d 0x3207
+#define PCI_DEVICE_ID_TSENG_ET6000 0x3208
+
+#define PCI_VENDOR_ID_WEITEK 0x100e
+#define PCI_DEVICE_ID_WEITEK_P9000 0x9001
+#define PCI_DEVICE_ID_WEITEK_P9100 0x9100
+
+#define PCI_VENDOR_ID_DEC 0x1011
+#define PCI_DEVICE_ID_DEC_BRD 0x0001
+#define PCI_DEVICE_ID_DEC_TULIP 0x0002
+#define PCI_DEVICE_ID_DEC_TGA 0x0004
+#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
+#define PCI_DEVICE_ID_DEC_TGA2 0x000D
+#define PCI_DEVICE_ID_DEC_FDDI 0x000F
+#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014
+#define PCI_DEVICE_ID_DEC_21142 0x0019
+#define PCI_DEVICE_ID_DEC_21052 0x0021
+#define PCI_DEVICE_ID_DEC_21150 0x0022
+#define PCI_DEVICE_ID_DEC_21152 0x0024
+#define PCI_DEVICE_ID_DEC_21153 0x0025
+#define PCI_DEVICE_ID_DEC_21154 0x0026
+#define PCI_DEVICE_ID_DEC_21285 0x1065
+#define PCI_DEVICE_ID_COMPAQ_42XX 0x0046
+
+#define PCI_VENDOR_ID_CIRRUS 0x1013
+#define PCI_DEVICE_ID_CIRRUS_7548 0x0038
+#define PCI_DEVICE_ID_CIRRUS_5430 0x00a0
+#define PCI_DEVICE_ID_CIRRUS_5434_4 0x00a4
+#define PCI_DEVICE_ID_CIRRUS_5434_8 0x00a8
+#define PCI_DEVICE_ID_CIRRUS_5436 0x00ac
+#define PCI_DEVICE_ID_CIRRUS_5446 0x00b8
+#define PCI_DEVICE_ID_CIRRUS_5480 0x00bc
+#define PCI_DEVICE_ID_CIRRUS_5462 0x00d0
+#define PCI_DEVICE_ID_CIRRUS_5464 0x00d4
+#define PCI_DEVICE_ID_CIRRUS_5465 0x00d6
+#define PCI_DEVICE_ID_CIRRUS_6729 0x1100
+#define PCI_DEVICE_ID_CIRRUS_6832 0x1110
+#define PCI_DEVICE_ID_CIRRUS_7543 0x1202
+#define PCI_DEVICE_ID_CIRRUS_4610 0x6001
+#define PCI_DEVICE_ID_CIRRUS_4612 0x6003
+#define PCI_DEVICE_ID_CIRRUS_4615 0x6004
+
+#define PCI_VENDOR_ID_IBM 0x1014
+#define PCI_DEVICE_ID_IBM_TR 0x0018
+#define PCI_DEVICE_ID_IBM_TR_WAKE 0x003e
+#define PCI_DEVICE_ID_IBM_CPC710_PCI64 0x00fc
+#define PCI_DEVICE_ID_IBM_SNIPE 0x0180
+#define PCI_DEVICE_ID_IBM_CITRINE 0x028C
+#define PCI_DEVICE_ID_IBM_GEMSTONE 0xB166
+#define PCI_DEVICE_ID_IBM_OBSIDIAN 0x02BD
+#define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1 0x0031
+#define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2 0x0219
+#define PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX 0x021A
+#define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM 0x0251
+#define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE 0x0361
+#define PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL 0x252
+
+#define PCI_VENDOR_ID_UNISYS 0x1018
+#define PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR 0x001C
+
+#define PCI_VENDOR_ID_COMPEX2 0x101a /* pci.ids says "AT&T GIS (NCR)" */
+#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005
+
+#define PCI_VENDOR_ID_WD 0x101c
+#define PCI_DEVICE_ID_WD_90C 0xc24a
+
+#define PCI_VENDOR_ID_AMI 0x101e
+#define PCI_DEVICE_ID_AMI_MEGARAID3 0x1960
+#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010
+#define PCI_DEVICE_ID_AMI_MEGARAID2 0x9060
+
+#define PCI_VENDOR_ID_AMD 0x1022
+#define PCI_DEVICE_ID_AMD_K8_NB 0x1100
+#define PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP 0x1101
+#define PCI_DEVICE_ID_AMD_K8_NB_MEMCTL 0x1102
+#define PCI_DEVICE_ID_AMD_K8_NB_MISC 0x1103
+#define PCI_DEVICE_ID_AMD_10H_NB_HT 0x1200
+#define PCI_DEVICE_ID_AMD_10H_NB_MAP 0x1201
+#define PCI_DEVICE_ID_AMD_10H_NB_DRAM 0x1202
+#define PCI_DEVICE_ID_AMD_10H_NB_MISC 0x1203
+#define PCI_DEVICE_ID_AMD_10H_NB_LINK 0x1204
+#define PCI_DEVICE_ID_AMD_11H_NB_HT 0x1300
+#define PCI_DEVICE_ID_AMD_11H_NB_MAP 0x1301
+#define PCI_DEVICE_ID_AMD_11H_NB_DRAM 0x1302
+#define PCI_DEVICE_ID_AMD_11H_NB_MISC 0x1303
+#define PCI_DEVICE_ID_AMD_11H_NB_LINK 0x1304
+#define PCI_DEVICE_ID_AMD_LANCE 0x2000
+#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
+#define PCI_DEVICE_ID_AMD_SCSI 0x2020
+#define PCI_DEVICE_ID_AMD_SERENADE 0x36c0
+#define PCI_DEVICE_ID_AMD_FE_GATE_7006 0x7006
+#define PCI_DEVICE_ID_AMD_FE_GATE_7007 0x7007
+#define PCI_DEVICE_ID_AMD_FE_GATE_700C 0x700C
+#define PCI_DEVICE_ID_AMD_FE_GATE_700E 0x700E
+#define PCI_DEVICE_ID_AMD_COBRA_7401 0x7401
+#define PCI_DEVICE_ID_AMD_VIPER_7409 0x7409
+#define PCI_DEVICE_ID_AMD_VIPER_740B 0x740B
+#define PCI_DEVICE_ID_AMD_VIPER_7410 0x7410
+#define PCI_DEVICE_ID_AMD_VIPER_7411 0x7411
+#define PCI_DEVICE_ID_AMD_VIPER_7413 0x7413
+#define PCI_DEVICE_ID_AMD_VIPER_7440 0x7440
+#define PCI_DEVICE_ID_AMD_OPUS_7441 0x7441
+#define PCI_DEVICE_ID_AMD_OPUS_7443 0x7443
+#define PCI_DEVICE_ID_AMD_VIPER_7443 0x7443
+#define PCI_DEVICE_ID_AMD_OPUS_7445 0x7445
+#define PCI_DEVICE_ID_AMD_8111_LPC 0x7468
+#define PCI_DEVICE_ID_AMD_8111_IDE 0x7469
+#define PCI_DEVICE_ID_AMD_8111_SMBUS2 0x746a
+#define PCI_DEVICE_ID_AMD_8111_SMBUS 0x746b
+#define PCI_DEVICE_ID_AMD_8111_AUDIO 0x746d
+#define PCI_DEVICE_ID_AMD_8151_0 0x7454
+#define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450
+#define PCI_DEVICE_ID_AMD_8131_APIC 0x7451
+#define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458
+#define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090
+#define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091
+#define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093
+#define PCI_DEVICE_ID_AMD_CS5536_OHC 0x2094
+#define PCI_DEVICE_ID_AMD_CS5536_EHC 0x2095
+#define PCI_DEVICE_ID_AMD_CS5536_UDC 0x2096
+#define PCI_DEVICE_ID_AMD_CS5536_UOC 0x2097
+#define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A
+
+#define PCI_DEVICE_ID_AMD_LX_VIDEO 0x2081
+#define PCI_DEVICE_ID_AMD_LX_AES 0x2082
+
+#define PCI_VENDOR_ID_TRIDENT 0x1023
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001
+#define PCI_DEVICE_ID_TRIDENT_9320 0x9320
+#define PCI_DEVICE_ID_TRIDENT_9388 0x9388
+#define PCI_DEVICE_ID_TRIDENT_9397 0x9397
+#define PCI_DEVICE_ID_TRIDENT_939A 0x939A
+#define PCI_DEVICE_ID_TRIDENT_9520 0x9520
+#define PCI_DEVICE_ID_TRIDENT_9525 0x9525
+#define PCI_DEVICE_ID_TRIDENT_9420 0x9420
+#define PCI_DEVICE_ID_TRIDENT_9440 0x9440
+#define PCI_DEVICE_ID_TRIDENT_9660 0x9660
+#define PCI_DEVICE_ID_TRIDENT_9750 0x9750
+#define PCI_DEVICE_ID_TRIDENT_9850 0x9850
+#define PCI_DEVICE_ID_TRIDENT_9880 0x9880
+#define PCI_DEVICE_ID_TRIDENT_8400 0x8400
+#define PCI_DEVICE_ID_TRIDENT_8420 0x8420
+#define PCI_DEVICE_ID_TRIDENT_8500 0x8500
+
+#define PCI_VENDOR_ID_AI 0x1025
+#define PCI_DEVICE_ID_AI_M1435 0x1435
+
+#define PCI_VENDOR_ID_DELL 0x1028
+#define PCI_DEVICE_ID_DELL_RACIII 0x0008
+#define PCI_DEVICE_ID_DELL_RAC4 0x0012
+#define PCI_DEVICE_ID_DELL_PERC5 0x0015
+
+#define PCI_VENDOR_ID_MATROX 0x102B
+#define PCI_DEVICE_ID_MATROX_MGA_2 0x0518
+#define PCI_DEVICE_ID_MATROX_MIL 0x0519
+#define PCI_DEVICE_ID_MATROX_MYS 0x051A
+#define PCI_DEVICE_ID_MATROX_MIL_2 0x051b
+#define PCI_DEVICE_ID_MATROX_MYS_AGP 0x051e
+#define PCI_DEVICE_ID_MATROX_MIL_2_AGP 0x051f
+#define PCI_DEVICE_ID_MATROX_MGA_IMP 0x0d10
+#define PCI_DEVICE_ID_MATROX_G100_MM 0x1000
+#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001
+#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520
+#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521
+#define PCI_DEVICE_ID_MATROX_G400 0x0525
+#define PCI_DEVICE_ID_MATROX_G200EV_PCI 0x0530
+#define PCI_DEVICE_ID_MATROX_G550 0x2527
+#define PCI_DEVICE_ID_MATROX_VIA 0x4536
+
+#define PCI_VENDOR_ID_CT 0x102c
+#define PCI_DEVICE_ID_CT_69000 0x00c0
+#define PCI_DEVICE_ID_CT_65545 0x00d8
+#define PCI_DEVICE_ID_CT_65548 0x00dc
+#define PCI_DEVICE_ID_CT_65550 0x00e0
+#define PCI_DEVICE_ID_CT_65554 0x00e4
+#define PCI_DEVICE_ID_CT_65555 0x00e5
+
+#define PCI_VENDOR_ID_MIRO 0x1031
+#define PCI_DEVICE_ID_MIRO_36050 0x5601
+#define PCI_DEVICE_ID_MIRO_DC10PLUS 0x7efe
+#define PCI_DEVICE_ID_MIRO_DC30PLUS 0xd801
+
+#define PCI_VENDOR_ID_NEC 0x1033
+#define PCI_DEVICE_ID_NEC_CBUS_1 0x0001 /* PCI-Cbus Bridge */
+#define PCI_DEVICE_ID_NEC_LOCAL 0x0002 /* Local Bridge */
+#define PCI_DEVICE_ID_NEC_ATM 0x0003 /* ATM LAN Controller */
+#define PCI_DEVICE_ID_NEC_R4000 0x0004 /* R4000 Bridge */
+#define PCI_DEVICE_ID_NEC_486 0x0005 /* 486 Like Peripheral Bus Bridge */
+#define PCI_DEVICE_ID_NEC_ACCEL_1 0x0006 /* Graphic Accelerator */
+#define PCI_DEVICE_ID_NEC_UXBUS 0x0007 /* UX-Bus Bridge */
+#define PCI_DEVICE_ID_NEC_ACCEL_2 0x0008 /* Graphic Accelerator */
+#define PCI_DEVICE_ID_NEC_GRAPH 0x0009 /* PCI-CoreGraph Bridge */
+#define PCI_DEVICE_ID_NEC_VL 0x0016 /* PCI-VL Bridge */
+#define PCI_DEVICE_ID_NEC_STARALPHA2 0x002c /* STAR ALPHA2 */
+#define PCI_DEVICE_ID_NEC_CBUS_2 0x002d /* PCI-Cbus Bridge */
+#define PCI_DEVICE_ID_NEC_USB 0x0035 /* PCI-USB Host */
+#define PCI_DEVICE_ID_NEC_CBUS_3 0x003b
+#define PCI_DEVICE_ID_NEC_NAPCCARD 0x003e
+#define PCI_DEVICE_ID_NEC_PCX2 0x0046 /* PowerVR */
+#define PCI_DEVICE_ID_NEC_VRC5476 0x009b
+#define PCI_DEVICE_ID_NEC_VRC4173 0x00a5
+#define PCI_DEVICE_ID_NEC_VRC5477_AC97 0x00a6
+#define PCI_DEVICE_ID_NEC_PC9821CS01 0x800c /* PC-9821-CS01 */
+#define PCI_DEVICE_ID_NEC_PC9821NRB06 0x800d /* PC-9821NR-B06 */
+
+#define PCI_VENDOR_ID_FD 0x1036
+#define PCI_DEVICE_ID_FD_36C70 0x0000
+
+#define PCI_VENDOR_ID_SI 0x1039
+#define PCI_DEVICE_ID_SI_5591_AGP 0x0001
+#define PCI_DEVICE_ID_SI_6202 0x0002
+#define PCI_DEVICE_ID_SI_503 0x0008
+#define PCI_DEVICE_ID_SI_ACPI 0x0009
+#define PCI_DEVICE_ID_SI_SMBUS 0x0016
+#define PCI_DEVICE_ID_SI_LPC 0x0018
+#define PCI_DEVICE_ID_SI_5597_VGA 0x0200
+#define PCI_DEVICE_ID_SI_6205 0x0205
+#define PCI_DEVICE_ID_SI_501 0x0406
+#define PCI_DEVICE_ID_SI_496 0x0496
+#define PCI_DEVICE_ID_SI_300 0x0300
+#define PCI_DEVICE_ID_SI_315H 0x0310
+#define PCI_DEVICE_ID_SI_315 0x0315
+#define PCI_DEVICE_ID_SI_315PRO 0x0325
+#define PCI_DEVICE_ID_SI_530 0x0530
+#define PCI_DEVICE_ID_SI_540 0x0540
+#define PCI_DEVICE_ID_SI_550 0x0550
+#define PCI_DEVICE_ID_SI_540_VGA 0x5300
+#define PCI_DEVICE_ID_SI_550_VGA 0x5315
+#define PCI_DEVICE_ID_SI_620 0x0620
+#define PCI_DEVICE_ID_SI_630 0x0630
+#define PCI_DEVICE_ID_SI_633 0x0633
+#define PCI_DEVICE_ID_SI_635 0x0635
+#define PCI_DEVICE_ID_SI_640 0x0640
+#define PCI_DEVICE_ID_SI_645 0x0645
+#define PCI_DEVICE_ID_SI_646 0x0646
+#define PCI_DEVICE_ID_SI_648 0x0648
+#define PCI_DEVICE_ID_SI_650 0x0650
+#define PCI_DEVICE_ID_SI_651 0x0651
+#define PCI_DEVICE_ID_SI_655 0x0655
+#define PCI_DEVICE_ID_SI_661 0x0661
+#define PCI_DEVICE_ID_SI_730 0x0730
+#define PCI_DEVICE_ID_SI_733 0x0733
+#define PCI_DEVICE_ID_SI_630_VGA 0x6300
+#define PCI_DEVICE_ID_SI_735 0x0735
+#define PCI_DEVICE_ID_SI_740 0x0740
+#define PCI_DEVICE_ID_SI_741 0x0741
+#define PCI_DEVICE_ID_SI_745 0x0745
+#define PCI_DEVICE_ID_SI_746 0x0746
+#define PCI_DEVICE_ID_SI_755 0x0755
+#define PCI_DEVICE_ID_SI_760 0x0760
+#define PCI_DEVICE_ID_SI_900 0x0900
+#define PCI_DEVICE_ID_SI_961 0x0961
+#define PCI_DEVICE_ID_SI_962 0x0962
+#define PCI_DEVICE_ID_SI_963 0x0963
+#define PCI_DEVICE_ID_SI_965 0x0965
+#define PCI_DEVICE_ID_SI_966 0x0966
+#define PCI_DEVICE_ID_SI_968 0x0968
+#define PCI_DEVICE_ID_SI_1180 0x1180
+#define PCI_DEVICE_ID_SI_5511 0x5511
+#define PCI_DEVICE_ID_SI_5513 0x5513
+#define PCI_DEVICE_ID_SI_5517 0x5517
+#define PCI_DEVICE_ID_SI_5518 0x5518
+#define PCI_DEVICE_ID_SI_5571 0x5571
+#define PCI_DEVICE_ID_SI_5581 0x5581
+#define PCI_DEVICE_ID_SI_5582 0x5582
+#define PCI_DEVICE_ID_SI_5591 0x5591
+#define PCI_DEVICE_ID_SI_5596 0x5596
+#define PCI_DEVICE_ID_SI_5597 0x5597
+#define PCI_DEVICE_ID_SI_5598 0x5598
+#define PCI_DEVICE_ID_SI_5600 0x5600
+#define PCI_DEVICE_ID_SI_7012 0x7012
+#define PCI_DEVICE_ID_SI_7013 0x7013
+#define PCI_DEVICE_ID_SI_7016 0x7016
+#define PCI_DEVICE_ID_SI_7018 0x7018
+
+#define PCI_VENDOR_ID_HP 0x103c
+#define PCI_DEVICE_ID_HP_VISUALIZE_EG 0x1005
+#define PCI_DEVICE_ID_HP_VISUALIZE_FX6 0x1006
+#define PCI_DEVICE_ID_HP_VISUALIZE_FX4 0x1008
+#define PCI_DEVICE_ID_HP_VISUALIZE_FX2 0x100a
+#define PCI_DEVICE_ID_HP_TACHYON 0x1028
+#define PCI_DEVICE_ID_HP_TACHLITE 0x1029
+#define PCI_DEVICE_ID_HP_J2585A 0x1030
+#define PCI_DEVICE_ID_HP_J2585B 0x1031
+#define PCI_DEVICE_ID_HP_J2973A 0x1040
+#define PCI_DEVICE_ID_HP_J2970A 0x1042
+#define PCI_DEVICE_ID_HP_DIVA 0x1048
+#define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049
+#define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A
+#define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B
+#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1
+#define PCI_DEVICE_ID_HP_VISUALIZE_FXE 0x108b
+#define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223
+#define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226
+#define PCI_DEVICE_ID_HP_DIVA_POWERBAR 0x1227
+#define PCI_DEVICE_ID_HP_ZX1_IOC 0x122a
+#define PCI_DEVICE_ID_HP_PCIX_LBA 0x122e
+#define PCI_DEVICE_ID_HP_SX1000_IOC 0x127c
+#define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282
+#define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290
+#define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301
+#define PCI_DEVICE_ID_HP_DIVA_HURRICANE 0x132a
+#define PCI_DEVICE_ID_HP_CISSA 0x3220
+#define PCI_DEVICE_ID_HP_CISSC 0x3230
+#define PCI_DEVICE_ID_HP_CISSD 0x3238
+#define PCI_DEVICE_ID_HP_CISSE 0x323a
+#define PCI_DEVICE_ID_HP_ZX2_IOC 0x4031
+
+#define PCI_VENDOR_ID_PCTECH 0x1042
+#define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000
+#define PCI_DEVICE_ID_PCTECH_RZ1001 0x1001
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020
+
+#define PCI_VENDOR_ID_ASUSTEK 0x1043
+#define PCI_DEVICE_ID_ASUSTEK_0675 0x0675
+
+#define PCI_VENDOR_ID_DPT 0x1044
+#define PCI_DEVICE_ID_DPT 0xa400
+
+#define PCI_VENDOR_ID_OPTI 0x1045
+#define PCI_DEVICE_ID_OPTI_82C558 0xc558
+#define PCI_DEVICE_ID_OPTI_82C621 0xc621
+#define PCI_DEVICE_ID_OPTI_82C700 0xc700
+#define PCI_DEVICE_ID_OPTI_82C825 0xd568
+
+#define PCI_VENDOR_ID_ELSA 0x1048
+#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000
+#define PCI_DEVICE_ID_ELSA_QS3000 0x3000
+
+#define PCI_VENDOR_ID_BUSLOGIC 0x104B
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040
+#define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT 0x8130
+
+#define PCI_VENDOR_ID_TI 0x104c
+#define PCI_DEVICE_ID_TI_TVP4020 0x3d07
+#define PCI_DEVICE_ID_TI_4450 0x8011
+#define PCI_DEVICE_ID_TI_TSB43AB22 0x8023
+#define PCI_DEVICE_ID_TI_XX21_XX11 0x8031
+#define PCI_DEVICE_ID_TI_XX21_XX11_FM 0x8033
+#define PCI_DEVICE_ID_TI_XX21_XX11_SD 0x8034
+#define PCI_DEVICE_ID_TI_X515 0x8036
+#define PCI_DEVICE_ID_TI_XX12 0x8039
+#define PCI_DEVICE_ID_TI_XX12_FM 0x803b
+#define PCI_DEVICE_ID_TI_1130 0xac12
+#define PCI_DEVICE_ID_TI_1031 0xac13
+#define PCI_DEVICE_ID_TI_1131 0xac15
+#define PCI_DEVICE_ID_TI_1250 0xac16
+#define PCI_DEVICE_ID_TI_1220 0xac17
+#define PCI_DEVICE_ID_TI_1221 0xac19
+#define PCI_DEVICE_ID_TI_1210 0xac1a
+#define PCI_DEVICE_ID_TI_1450 0xac1b
+#define PCI_DEVICE_ID_TI_1225 0xac1c
+#define PCI_DEVICE_ID_TI_1251A 0xac1d
+#define PCI_DEVICE_ID_TI_1211 0xac1e
+#define PCI_DEVICE_ID_TI_1251B 0xac1f
+#define PCI_DEVICE_ID_TI_4410 0xac41
+#define PCI_DEVICE_ID_TI_4451 0xac42
+#define PCI_DEVICE_ID_TI_4510 0xac44
+#define PCI_DEVICE_ID_TI_4520 0xac46
+#define PCI_DEVICE_ID_TI_7510 0xac47
+#define PCI_DEVICE_ID_TI_7610 0xac48
+#define PCI_DEVICE_ID_TI_7410 0xac49
+#define PCI_DEVICE_ID_TI_1410 0xac50
+#define PCI_DEVICE_ID_TI_1420 0xac51
+#define PCI_DEVICE_ID_TI_1451A 0xac52
+#define PCI_DEVICE_ID_TI_1620 0xac54
+#define PCI_DEVICE_ID_TI_1520 0xac55
+#define PCI_DEVICE_ID_TI_1510 0xac56
+#define PCI_DEVICE_ID_TI_X620 0xac8d
+#define PCI_DEVICE_ID_TI_X420 0xac8e
+#define PCI_DEVICE_ID_TI_XX20_FM 0xac8f
+
+#define PCI_VENDOR_ID_SONY 0x104d
+
+/* Winbond have two vendor IDs! See 0x10ad as well */
+#define PCI_VENDOR_ID_WINBOND2 0x1050
+#define PCI_DEVICE_ID_WINBOND2_89C940F 0x5a5a
+#define PCI_DEVICE_ID_WINBOND2_6692 0x6692
+
+#define PCI_VENDOR_ID_ANIGMA 0x1051
+#define PCI_DEVICE_ID_ANIGMA_MC145575 0x0100
+
+#define PCI_VENDOR_ID_EFAR 0x1055
+#define PCI_DEVICE_ID_EFAR_SLC90E66_1 0x9130
+#define PCI_DEVICE_ID_EFAR_SLC90E66_3 0x9463
+
+#define PCI_VENDOR_ID_MOTOROLA 0x1057
+#define PCI_DEVICE_ID_MOTOROLA_MPC105 0x0001
+#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002
+#define PCI_DEVICE_ID_MOTOROLA_MPC107 0x0004
+#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801
+#define PCI_DEVICE_ID_MOTOROLA_FALCON 0x4802
+#define PCI_DEVICE_ID_MOTOROLA_HAWK 0x4803
+#define PCI_DEVICE_ID_MOTOROLA_HARRIER 0x480b
+#define PCI_DEVICE_ID_MOTOROLA_MPC5200 0x5803
+#define PCI_DEVICE_ID_MOTOROLA_MPC5200B 0x5809
+
+#define PCI_VENDOR_ID_PROMISE 0x105a
+#define PCI_DEVICE_ID_PROMISE_20265 0x0d30
+#define PCI_DEVICE_ID_PROMISE_20267 0x4d30
+#define PCI_DEVICE_ID_PROMISE_20246 0x4d33
+#define PCI_DEVICE_ID_PROMISE_20262 0x4d38
+#define PCI_DEVICE_ID_PROMISE_20263 0x0D38
+#define PCI_DEVICE_ID_PROMISE_20268 0x4d68
+#define PCI_DEVICE_ID_PROMISE_20269 0x4d69
+#define PCI_DEVICE_ID_PROMISE_20270 0x6268
+#define PCI_DEVICE_ID_PROMISE_20271 0x6269
+#define PCI_DEVICE_ID_PROMISE_20275 0x1275
+#define PCI_DEVICE_ID_PROMISE_20276 0x5275
+#define PCI_DEVICE_ID_PROMISE_20277 0x7275
+
+#define PCI_VENDOR_ID_UMC 0x1060
+#define PCI_DEVICE_ID_UMC_UM8673F 0x0101
+#define PCI_DEVICE_ID_UMC_UM8886BF 0x673a
+#define PCI_DEVICE_ID_UMC_UM8886A 0x886a
+
+#define PCI_VENDOR_ID_PICOPOWER 0x1066
+#define PCI_DEVICE_ID_PICOPOWER_PT86C523 0x0002
+#define PCI_DEVICE_ID_PICOPOWER_PT86C523BBP 0x8002
+
+#define PCI_VENDOR_ID_MYLEX 0x1069
+#define PCI_DEVICE_ID_MYLEX_DAC960_P 0x0001
+#define PCI_DEVICE_ID_MYLEX_DAC960_PD 0x0002
+#define PCI_DEVICE_ID_MYLEX_DAC960_PG 0x0010
+#define PCI_DEVICE_ID_MYLEX_DAC960_LA 0x0020
+#define PCI_DEVICE_ID_MYLEX_DAC960_LP 0x0050
+#define PCI_DEVICE_ID_MYLEX_DAC960_BA 0xBA56
+#define PCI_DEVICE_ID_MYLEX_DAC960_GEM 0xB166
+
+#define PCI_VENDOR_ID_APPLE 0x106b
+#define PCI_DEVICE_ID_APPLE_BANDIT 0x0001
+#define PCI_DEVICE_ID_APPLE_HYDRA 0x000e
+#define PCI_DEVICE_ID_APPLE_UNI_N_FW 0x0018
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC 0x0021
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMACP 0x0024
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P 0x0027
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP15 0x002d
+#define PCI_DEVICE_ID_APPLE_UNI_N_PCI15 0x002e
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC2 0x0032
+#define PCI_DEVICE_ID_APPLE_UNI_N_ATA 0x0033
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP2 0x0034
+#define PCI_DEVICE_ID_APPLE_IPID_ATA100 0x003b
+#define PCI_DEVICE_ID_APPLE_K2_ATA100 0x0043
+#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b
+#define PCI_DEVICE_ID_APPLE_K2_GMAC 0x004c
+#define PCI_DEVICE_ID_APPLE_SH_ATA 0x0050
+#define PCI_DEVICE_ID_APPLE_SH_SUNGEM 0x0051
+#define PCI_DEVICE_ID_APPLE_U3L_AGP 0x0058
+#define PCI_DEVICE_ID_APPLE_U3H_AGP 0x0059
+#define PCI_DEVICE_ID_APPLE_IPID2_AGP 0x0066
+#define PCI_DEVICE_ID_APPLE_IPID2_ATA 0x0069
+#define PCI_DEVICE_ID_APPLE_IPID2_FW 0x006a
+#define PCI_DEVICE_ID_APPLE_IPID2_GMAC 0x006b
+#define PCI_DEVICE_ID_APPLE_TIGON3 0x1645
+
+#define PCI_VENDOR_ID_YAMAHA 0x1073
+#define PCI_DEVICE_ID_YAMAHA_724 0x0004
+#define PCI_DEVICE_ID_YAMAHA_724F 0x000d
+#define PCI_DEVICE_ID_YAMAHA_740 0x000a
+#define PCI_DEVICE_ID_YAMAHA_740C 0x000c
+#define PCI_DEVICE_ID_YAMAHA_744 0x0010
+#define PCI_DEVICE_ID_YAMAHA_754 0x0012
+
+#define PCI_VENDOR_ID_QLOGIC 0x1077
+#define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016
+#define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020
+#define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080
+#define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216
+#define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240
+#define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280
+#define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100
+#define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200
+#define PCI_DEVICE_ID_QLOGIC_ISP2300 0x2300
+#define PCI_DEVICE_ID_QLOGIC_ISP2312 0x2312
+#define PCI_DEVICE_ID_QLOGIC_ISP2322 0x2322
+#define PCI_DEVICE_ID_QLOGIC_ISP6312 0x6312
+#define PCI_DEVICE_ID_QLOGIC_ISP6322 0x6322
+#define PCI_DEVICE_ID_QLOGIC_ISP2422 0x2422
+#define PCI_DEVICE_ID_QLOGIC_ISP2432 0x2432
+#define PCI_DEVICE_ID_QLOGIC_ISP2512 0x2512
+#define PCI_DEVICE_ID_QLOGIC_ISP2522 0x2522
+#define PCI_DEVICE_ID_QLOGIC_ISP5422 0x5422
+#define PCI_DEVICE_ID_QLOGIC_ISP5432 0x5432
+
+#define PCI_VENDOR_ID_CYRIX 0x1078
+#define PCI_DEVICE_ID_CYRIX_5510 0x0000
+#define PCI_DEVICE_ID_CYRIX_PCI_MASTER 0x0001
+#define PCI_DEVICE_ID_CYRIX_5520 0x0002
+#define PCI_DEVICE_ID_CYRIX_5530_LEGACY 0x0100
+#define PCI_DEVICE_ID_CYRIX_5530_IDE 0x0102
+#define PCI_DEVICE_ID_CYRIX_5530_AUDIO 0x0103
+#define PCI_DEVICE_ID_CYRIX_5530_VIDEO 0x0104
+
+#define PCI_VENDOR_ID_CONTAQ 0x1080
+#define PCI_DEVICE_ID_CONTAQ_82C693 0xc693
+
+#define PCI_VENDOR_ID_OLICOM 0x108d
+#define PCI_DEVICE_ID_OLICOM_OC2325 0x0012
+#define PCI_DEVICE_ID_OLICOM_OC2183 0x0013
+#define PCI_DEVICE_ID_OLICOM_OC2326 0x0014
+
+#define PCI_VENDOR_ID_SUN 0x108e
+#define PCI_DEVICE_ID_SUN_EBUS 0x1000
+#define PCI_DEVICE_ID_SUN_HAPPYMEAL 0x1001
+#define PCI_DEVICE_ID_SUN_RIO_EBUS 0x1100
+#define PCI_DEVICE_ID_SUN_RIO_GEM 0x1101
+#define PCI_DEVICE_ID_SUN_RIO_1394 0x1102
+#define PCI_DEVICE_ID_SUN_RIO_USB 0x1103
+#define PCI_DEVICE_ID_SUN_GEM 0x2bad
+#define PCI_DEVICE_ID_SUN_SIMBA 0x5000
+#define PCI_DEVICE_ID_SUN_PBM 0x8000
+#define PCI_DEVICE_ID_SUN_SCHIZO 0x8001
+#define PCI_DEVICE_ID_SUN_SABRE 0xa000
+#define PCI_DEVICE_ID_SUN_HUMMINGBIRD 0xa001
+#define PCI_DEVICE_ID_SUN_TOMATILLO 0xa801
+#define PCI_DEVICE_ID_SUN_CASSINI 0xabba
+
+#define PCI_VENDOR_ID_CMD 0x1095
+#define PCI_DEVICE_ID_CMD_643 0x0643
+#define PCI_DEVICE_ID_CMD_646 0x0646
+#define PCI_DEVICE_ID_CMD_648 0x0648
+#define PCI_DEVICE_ID_CMD_649 0x0649
+
+#define PCI_DEVICE_ID_SII_680 0x0680
+#define PCI_DEVICE_ID_SII_3112 0x3112
+#define PCI_DEVICE_ID_SII_1210SA 0x0240
+
+#define PCI_VENDOR_ID_BROOKTREE 0x109e
+#define PCI_DEVICE_ID_BROOKTREE_878 0x0878
+#define PCI_DEVICE_ID_BROOKTREE_879 0x0879
+
+#define PCI_VENDOR_ID_SGI 0x10a9
+#define PCI_DEVICE_ID_SGI_IOC3 0x0003
+#define PCI_DEVICE_ID_SGI_LITHIUM 0x1002
+#define PCI_DEVICE_ID_SGI_IOC4 0x100a
+
+#define PCI_VENDOR_ID_WINBOND 0x10ad
+#define PCI_DEVICE_ID_WINBOND_82C105 0x0105
+#define PCI_DEVICE_ID_WINBOND_83C553 0x0565
+
+#define PCI_VENDOR_ID_PLX 0x10b5
+#define PCI_DEVICE_ID_PLX_R685 0x1030
+#define PCI_DEVICE_ID_PLX_ROMULUS 0x106a
+#define PCI_DEVICE_ID_PLX_SPCOM800 0x1076
+#define PCI_DEVICE_ID_PLX_1077 0x1077
+#define PCI_DEVICE_ID_PLX_SPCOM200 0x1103
+#define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151
+#define PCI_DEVICE_ID_PLX_R753 0x1152
+#define PCI_DEVICE_ID_PLX_OLITEC 0x1187
+#define PCI_DEVICE_ID_PLX_PCI200SYN 0x3196
+#define PCI_DEVICE_ID_PLX_9030 0x9030
+#define PCI_DEVICE_ID_PLX_9050 0x9050
+#define PCI_DEVICE_ID_PLX_9080 0x9080
+#define PCI_DEVICE_ID_PLX_GTEK_SERIAL2 0xa001
+
+#define PCI_VENDOR_ID_MADGE 0x10b6
+#define PCI_DEVICE_ID_MADGE_MK2 0x0002
+
+#define PCI_VENDOR_ID_3COM 0x10b7
+#define PCI_DEVICE_ID_3COM_3C985 0x0001
+#define PCI_DEVICE_ID_3COM_3C940 0x1700
+#define PCI_DEVICE_ID_3COM_3C339 0x3390
+#define PCI_DEVICE_ID_3COM_3C359 0x3590
+#define PCI_DEVICE_ID_3COM_3C940B 0x80eb
+#define PCI_DEVICE_ID_3COM_3CR990 0x9900
+#define PCI_DEVICE_ID_3COM_3CR990_TX_95 0x9902
+#define PCI_DEVICE_ID_3COM_3CR990_TX_97 0x9903
+#define PCI_DEVICE_ID_3COM_3CR990B 0x9904
+#define PCI_DEVICE_ID_3COM_3CR990_FX 0x9905
+#define PCI_DEVICE_ID_3COM_3CR990SVR95 0x9908
+#define PCI_DEVICE_ID_3COM_3CR990SVR97 0x9909
+#define PCI_DEVICE_ID_3COM_3CR990SVR 0x990a
+
+#define PCI_VENDOR_ID_AL 0x10b9
+#define PCI_DEVICE_ID_AL_M1533 0x1533
+#define PCI_DEVICE_ID_AL_M1535 0x1535
+#define PCI_DEVICE_ID_AL_M1541 0x1541
+#define PCI_DEVICE_ID_AL_M1563 0x1563
+#define PCI_DEVICE_ID_AL_M1621 0x1621
+#define PCI_DEVICE_ID_AL_M1631 0x1631
+#define PCI_DEVICE_ID_AL_M1632 0x1632
+#define PCI_DEVICE_ID_AL_M1641 0x1641
+#define PCI_DEVICE_ID_AL_M1644 0x1644
+#define PCI_DEVICE_ID_AL_M1647 0x1647
+#define PCI_DEVICE_ID_AL_M1651 0x1651
+#define PCI_DEVICE_ID_AL_M1671 0x1671
+#define PCI_DEVICE_ID_AL_M1681 0x1681
+#define PCI_DEVICE_ID_AL_M1683 0x1683
+#define PCI_DEVICE_ID_AL_M1689 0x1689
+#define PCI_DEVICE_ID_AL_M5219 0x5219
+#define PCI_DEVICE_ID_AL_M5228 0x5228
+#define PCI_DEVICE_ID_AL_M5229 0x5229
+#define PCI_DEVICE_ID_AL_M5451 0x5451
+#define PCI_DEVICE_ID_AL_M7101 0x7101
+
+#define PCI_VENDOR_ID_NEOMAGIC 0x10c8
+#define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005
+#define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006
+#define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016
+
+#define PCI_VENDOR_ID_TCONRAD 0x10da
+#define PCI_DEVICE_ID_TCONRAD_TOKENRING 0x0508
+
+#define PCI_VENDOR_ID_NVIDIA 0x10de
+#define PCI_DEVICE_ID_NVIDIA_TNT 0x0020
+#define PCI_DEVICE_ID_NVIDIA_TNT2 0x0028
+#define PCI_DEVICE_ID_NVIDIA_UTNT2 0x0029
+#define PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN 0x002a
+#define PCI_DEVICE_ID_NVIDIA_VTNT2 0x002C
+#define PCI_DEVICE_ID_NVIDIA_UVTNT2 0x002D
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS 0x0034
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE 0x0035
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA 0x0036
+#define PCI_DEVICE_ID_NVIDIA_NVENET_10 0x0037
+#define PCI_DEVICE_ID_NVIDIA_NVENET_11 0x0038
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2 0x003e
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA 0x0040
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800 0x0041
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE 0x0042
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT 0x0045
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000 0x004E
+#define PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS 0x0052
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE 0x0053
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA 0x0054
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2 0x0055
+#define PCI_DEVICE_ID_NVIDIA_NVENET_8 0x0056
+#define PCI_DEVICE_ID_NVIDIA_NVENET_9 0x0057
+#define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059
+#define PCI_DEVICE_ID_NVIDIA_CK804_PCIE 0x005d
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065
+#define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066
+#define PCI_DEVICE_ID_NVIDIA_MCP2_MODEM 0x0069
+#define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS 0x0084
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE 0x0085
+#define PCI_DEVICE_ID_NVIDIA_NVENET_4 0x0086
+#define PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM 0x0089
+#define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO 0x008a
+#define PCI_DEVICE_ID_NVIDIA_NVENET_5 0x008c
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA 0x008e
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT 0x0090
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX 0x0091
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800 0x0098
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800_GTX 0x0099
+#define PCI_DEVICE_ID_NVIDIA_ITNT2 0x00A0
+#define PCI_DEVICE_ID_GEFORCE_6800A 0x00c1
+#define PCI_DEVICE_ID_GEFORCE_6800A_LE 0x00c2
+#define PCI_DEVICE_ID_GEFORCE_GO_6800 0x00c8
+#define PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA 0x00c9
+#define PCI_DEVICE_ID_QUADRO_FX_GO1400 0x00cc
+#define PCI_DEVICE_ID_QUADRO_FX_1400 0x00ce
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3 0x00d1
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS 0x00d4
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE 0x00d5
+#define PCI_DEVICE_ID_NVIDIA_NVENET_3 0x00d6
+#define PCI_DEVICE_ID_NVIDIA_MCP3_MODEM 0x00d9
+#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da
+#define PCI_DEVICE_ID_NVIDIA_NVENET_7 0x00df
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S 0x00e1
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA 0x00e3
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS 0x00e4
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE 0x00e5
+#define PCI_DEVICE_ID_NVIDIA_NVENET_6 0x00e6
+#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2 0x00ee
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1 0x00f0
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT1 0x00f1
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2 0x00f2
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1 0x00f3
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT 0x00f9
+#define PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280 0x00fd
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101
+#define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX 0x0110
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2 0x0111
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO 0x0112
+#define PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR 0x0113
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT 0x0140
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600 0x0141
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL 0x0145
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540 0x014E
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200 0x014F
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS 0x0150
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2 0x0151
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA 0x0152
+#define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO 0x0153
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE 0x0161
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200 0x0164
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250 0x0166
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1 0x0167
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1 0x0168
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460 0x0170
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440 0x0171
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420 0x0172
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE 0x0173
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO 0x0174
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO 0x0175
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32 0x0176
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO 0x0177
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL 0x0178
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64 0x0179
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_200 0x017A
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL 0x017B
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL 0x017C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16 0x017D
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X 0x0181
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X 0x0182
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X 0x0183
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_4000 0x0185
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO 0x0186
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO 0x0187
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL 0x0188
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC 0x0189
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS 0x018A
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL 0x018B
+#define PCI_DEVICE_ID_NVIDIA_IGEFORCE2 0x01a0
+#define PCI_DEVICE_ID_NVIDIA_NFORCE 0x01a4
+#define PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO 0x01b1
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS 0x01b4
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc
+#define PCI_DEVICE_ID_NVIDIA_MCP1_MODEM 0x01c1
+#define PCI_DEVICE_ID_NVIDIA_NVENET_1 0x01c3
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC 0x0203
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B 0x0211
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE 0x0212
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT 0x0215
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600 0x0250
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400 0x0251
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200 0x0253
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL 0x0258
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL 0x0259
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL 0x025B
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS 0x0264
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE 0x0265
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2 0x0267
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS 0x0368
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE 0x036E
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x037E
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2 0x037F
+#define PCI_DEVICE_ID_NVIDIA_NVENET_12 0x0268
+#define PCI_DEVICE_ID_NVIDIA_NVENET_13 0x0269
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800 0x0280
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X 0x0281
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE 0x0282
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO 0x0286
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL 0x0288
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL 0x0289
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL 0x028C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA 0x0301
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800 0x0302
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000 0x0308
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000 0x0309
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA 0x0311
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600 0x0312
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE 0x0314
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600 0x031A
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650 0x031B
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700 0x031C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200 0x0320
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA 0x0321
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1 0x0322
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE 0x0323
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200 0x0324
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250 0x0325
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500 0x0326
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100 0x0327
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32 0x0328
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200 0x0329
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI 0x032A
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500 0x032B
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300 0x032C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100 0x032D
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA 0x0330
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900 0x0331
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT 0x0332
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA 0x0333
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT 0x0334
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000 0x0338
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700 0x033F
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA 0x0341
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700 0x0342
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE 0x0343
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE 0x0344
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1 0x0347
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2 0x0348
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000 0x034C
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100 0x034E
+#define PCI_DEVICE_ID_NVIDIA_NVENET_14 0x0372
+#define PCI_DEVICE_ID_NVIDIA_NVENET_15 0x0373
+#define PCI_DEVICE_ID_NVIDIA_NVENET_16 0x03E5
+#define PCI_DEVICE_ID_NVIDIA_NVENET_17 0x03E6
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA 0x03E7
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS 0x03EB
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE 0x03EC
+#define PCI_DEVICE_ID_NVIDIA_NVENET_18 0x03EE
+#define PCI_DEVICE_ID_NVIDIA_NVENET_19 0x03EF
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2 0x03F6
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3 0x03F7
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS 0x0446
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE 0x0448
+#define PCI_DEVICE_ID_NVIDIA_NVENET_20 0x0450
+#define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451
+#define PCI_DEVICE_ID_NVIDIA_NVENET_22 0x0452
+#define PCI_DEVICE_ID_NVIDIA_NVENET_23 0x0453
+#define PCI_DEVICE_ID_NVIDIA_NVENET_24 0x054C
+#define PCI_DEVICE_ID_NVIDIA_NVENET_25 0x054D
+#define PCI_DEVICE_ID_NVIDIA_NVENET_26 0x054E
+#define PCI_DEVICE_ID_NVIDIA_NVENET_27 0x054F
+#define PCI_DEVICE_ID_NVIDIA_NVENET_28 0x07DC
+#define PCI_DEVICE_ID_NVIDIA_NVENET_29 0x07DD
+#define PCI_DEVICE_ID_NVIDIA_NVENET_30 0x07DE
+#define PCI_DEVICE_ID_NVIDIA_NVENET_31 0x07DF
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE 0x0560
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE 0x056C
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE 0x0759
+#define PCI_DEVICE_ID_NVIDIA_NVENET_32 0x0760
+#define PCI_DEVICE_ID_NVIDIA_NVENET_33 0x0761
+#define PCI_DEVICE_ID_NVIDIA_NVENET_34 0x0762
+#define PCI_DEVICE_ID_NVIDIA_NVENET_35 0x0763
+#define PCI_DEVICE_ID_NVIDIA_NVENET_36 0x0AB0
+#define PCI_DEVICE_ID_NVIDIA_NVENET_37 0x0AB1
+#define PCI_DEVICE_ID_NVIDIA_NVENET_38 0x0AB2
+#define PCI_DEVICE_ID_NVIDIA_NVENET_39 0x0AB3
+
+#define PCI_VENDOR_ID_IMS 0x10e0
+#define PCI_DEVICE_ID_IMS_TT128 0x9128
+#define PCI_DEVICE_ID_IMS_TT3D 0x9135
+
+#define PCI_VENDOR_ID_INTERG 0x10ea
+#define PCI_DEVICE_ID_INTERG_1682 0x1682
+#define PCI_DEVICE_ID_INTERG_2000 0x2000
+#define PCI_DEVICE_ID_INTERG_2010 0x2010
+#define PCI_DEVICE_ID_INTERG_5000 0x5000
+#define PCI_DEVICE_ID_INTERG_5050 0x5050
+
+#define PCI_VENDOR_ID_REALTEK 0x10ec
+#define PCI_DEVICE_ID_REALTEK_8139 0x8139
+
+#define PCI_VENDOR_ID_XILINX 0x10ee
+#define PCI_DEVICE_ID_RME_DIGI96 0x3fc0
+#define PCI_DEVICE_ID_RME_DIGI96_8 0x3fc1
+#define PCI_DEVICE_ID_RME_DIGI96_8_PRO 0x3fc2
+#define PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST 0x3fc3
+#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5
+#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6
+
+#define PCI_VENDOR_ID_INIT 0x1101
+
+#define PCI_VENDOR_ID_CREATIVE 0x1102 /* duplicate: ECTIVA */
+#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
+
+#define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */
+#define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938
+
+#define PCI_VENDOR_ID_TTI 0x1103
+#define PCI_DEVICE_ID_TTI_HPT343 0x0003
+#define PCI_DEVICE_ID_TTI_HPT366 0x0004
+#define PCI_DEVICE_ID_TTI_HPT372 0x0005
+#define PCI_DEVICE_ID_TTI_HPT302 0x0006
+#define PCI_DEVICE_ID_TTI_HPT371 0x0007
+#define PCI_DEVICE_ID_TTI_HPT374 0x0008
+#define PCI_DEVICE_ID_TTI_HPT372N 0x0009 /* apparently a 372N variant? */
+
+#define PCI_VENDOR_ID_VIA 0x1106
+#define PCI_DEVICE_ID_VIA_8763_0 0x0198
+#define PCI_DEVICE_ID_VIA_8380_0 0x0204
+#define PCI_DEVICE_ID_VIA_3238_0 0x0238
+#define PCI_DEVICE_ID_VIA_PT880 0x0258
+#define PCI_DEVICE_ID_VIA_PT880ULTRA 0x0308
+#define PCI_DEVICE_ID_VIA_PX8X0_0 0x0259
+#define PCI_DEVICE_ID_VIA_3269_0 0x0269
+#define PCI_DEVICE_ID_VIA_K8T800PRO_0 0x0282
+#define PCI_DEVICE_ID_VIA_3296_0 0x0296
+#define PCI_DEVICE_ID_VIA_8363_0 0x0305
+#define PCI_DEVICE_ID_VIA_P4M800CE 0x0314
+#define PCI_DEVICE_ID_VIA_P4M890 0x0327
+#define PCI_DEVICE_ID_VIA_VT3324 0x0324
+#define PCI_DEVICE_ID_VIA_VT3336 0x0336
+#define PCI_DEVICE_ID_VIA_VT3351 0x0351
+#define PCI_DEVICE_ID_VIA_VT3364 0x0364
+#define PCI_DEVICE_ID_VIA_8371_0 0x0391
+#define PCI_DEVICE_ID_VIA_8501_0 0x0501
+#define PCI_DEVICE_ID_VIA_82C561 0x0561
+#define PCI_DEVICE_ID_VIA_82C586_1 0x0571
+#define PCI_DEVICE_ID_VIA_82C576 0x0576
+#define PCI_DEVICE_ID_VIA_82C586_0 0x0586
+#define PCI_DEVICE_ID_VIA_82C596 0x0596
+#define PCI_DEVICE_ID_VIA_82C597_0 0x0597
+#define PCI_DEVICE_ID_VIA_82C598_0 0x0598
+#define PCI_DEVICE_ID_VIA_8601_0 0x0601
+#define PCI_DEVICE_ID_VIA_8605_0 0x0605
+#define PCI_DEVICE_ID_VIA_82C686 0x0686
+#define PCI_DEVICE_ID_VIA_82C691_0 0x0691
+#define PCI_DEVICE_ID_VIA_82C576_1 0x1571
+#define PCI_DEVICE_ID_VIA_82C586_2 0x3038
+#define PCI_DEVICE_ID_VIA_82C586_3 0x3040
+#define PCI_DEVICE_ID_VIA_82C596_3 0x3050
+#define PCI_DEVICE_ID_VIA_82C596B_3 0x3051
+#define PCI_DEVICE_ID_VIA_82C686_4 0x3057
+#define PCI_DEVICE_ID_VIA_82C686_5 0x3058
+#define PCI_DEVICE_ID_VIA_8233_5 0x3059
+#define PCI_DEVICE_ID_VIA_8233_0 0x3074
+#define PCI_DEVICE_ID_VIA_8633_0 0x3091
+#define PCI_DEVICE_ID_VIA_8367_0 0x3099
+#define PCI_DEVICE_ID_VIA_8653_0 0x3101
+#define PCI_DEVICE_ID_VIA_8622 0x3102
+#define PCI_DEVICE_ID_VIA_8235_USB_2 0x3104
+#define PCI_DEVICE_ID_VIA_8233C_0 0x3109
+#define PCI_DEVICE_ID_VIA_8361 0x3112
+#define PCI_DEVICE_ID_VIA_XM266 0x3116
+#define PCI_DEVICE_ID_VIA_612X 0x3119
+#define PCI_DEVICE_ID_VIA_862X_0 0x3123
+#define PCI_DEVICE_ID_VIA_8753_0 0x3128
+#define PCI_DEVICE_ID_VIA_8233A 0x3147
+#define PCI_DEVICE_ID_VIA_8703_51_0 0x3148
+#define PCI_DEVICE_ID_VIA_8237_SATA 0x3149
+#define PCI_DEVICE_ID_VIA_XN266 0x3156
+#define PCI_DEVICE_ID_VIA_6410 0x3164
+#define PCI_DEVICE_ID_VIA_8754C_0 0x3168
+#define PCI_DEVICE_ID_VIA_8235 0x3177
+#define PCI_DEVICE_ID_VIA_8385_0 0x3188
+#define PCI_DEVICE_ID_VIA_8377_0 0x3189
+#define PCI_DEVICE_ID_VIA_8378_0 0x3205
+#define PCI_DEVICE_ID_VIA_8783_0 0x3208
+#define PCI_DEVICE_ID_VIA_8237 0x3227
+#define PCI_DEVICE_ID_VIA_8251 0x3287
+#define PCI_DEVICE_ID_VIA_8237A 0x3337
+#define PCI_DEVICE_ID_VIA_8237S 0x3372
+#define PCI_DEVICE_ID_VIA_SATA_EIDE 0x5324
+#define PCI_DEVICE_ID_VIA_8231 0x8231
+#define PCI_DEVICE_ID_VIA_8231_4 0x8235
+#define PCI_DEVICE_ID_VIA_8365_1 0x8305
+#define PCI_DEVICE_ID_VIA_CX700 0x8324
+#define PCI_DEVICE_ID_VIA_CX700_IDE 0x0581
+#define PCI_DEVICE_ID_VIA_VX800 0x8353
+#define PCI_DEVICE_ID_VIA_8371_1 0x8391
+#define PCI_DEVICE_ID_VIA_82C598_1 0x8598
+#define PCI_DEVICE_ID_VIA_838X_1 0xB188
+#define PCI_DEVICE_ID_VIA_83_87XX_1 0xB198
+
+#define PCI_VENDOR_ID_SIEMENS 0x110A
+#define PCI_DEVICE_ID_SIEMENS_DSCC4 0x2102
+
+#define PCI_VENDOR_ID_VORTEX 0x1119
+#define PCI_DEVICE_ID_VORTEX_GDT60x0 0x0000
+#define PCI_DEVICE_ID_VORTEX_GDT6000B 0x0001
+#define PCI_DEVICE_ID_VORTEX_GDT6x10 0x0002
+#define PCI_DEVICE_ID_VORTEX_GDT6x20 0x0003
+#define PCI_DEVICE_ID_VORTEX_GDT6530 0x0004
+#define PCI_DEVICE_ID_VORTEX_GDT6550 0x0005
+#define PCI_DEVICE_ID_VORTEX_GDT6x17 0x0006
+#define PCI_DEVICE_ID_VORTEX_GDT6x27 0x0007
+#define PCI_DEVICE_ID_VORTEX_GDT6537 0x0008
+#define PCI_DEVICE_ID_VORTEX_GDT6557 0x0009
+#define PCI_DEVICE_ID_VORTEX_GDT6x15 0x000a
+#define PCI_DEVICE_ID_VORTEX_GDT6x25 0x000b
+#define PCI_DEVICE_ID_VORTEX_GDT6535 0x000c
+#define PCI_DEVICE_ID_VORTEX_GDT6555 0x000d
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP 0x0100
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP 0x0101
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP 0x0102
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP 0x0103
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP 0x0104
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP 0x0105
+
+#define PCI_VENDOR_ID_EF 0x111a
+#define PCI_DEVICE_ID_EF_ATM_FPGA 0x0000
+#define PCI_DEVICE_ID_EF_ATM_ASIC 0x0002
+#define PCI_DEVICE_ID_EF_ATM_LANAI2 0x0003
+#define PCI_DEVICE_ID_EF_ATM_LANAIHB 0x0005
+
+#define PCI_VENDOR_ID_IDT 0x111d
+#define PCI_DEVICE_ID_IDT_IDT77201 0x0001
+
+#define PCI_VENDOR_ID_FORE 0x1127
+#define PCI_DEVICE_ID_FORE_PCA200E 0x0300
+
+#define PCI_VENDOR_ID_PHILIPS 0x1131
+#define PCI_DEVICE_ID_PHILIPS_SAA7146 0x7146
+#define PCI_DEVICE_ID_PHILIPS_SAA9730 0x9730
+
+#define PCI_VENDOR_ID_EICON 0x1133
+#define PCI_DEVICE_ID_EICON_DIVA20 0xe002
+#define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004
+#define PCI_DEVICE_ID_EICON_DIVA201 0xe005
+#define PCI_DEVICE_ID_EICON_DIVA202 0xe00b
+#define PCI_DEVICE_ID_EICON_MAESTRA 0xe010
+#define PCI_DEVICE_ID_EICON_MAESTRAQ 0xe012
+#define PCI_DEVICE_ID_EICON_MAESTRAQ_U 0xe013
+#define PCI_DEVICE_ID_EICON_MAESTRAP 0xe014
+
+#define PCI_VENDOR_ID_CISCO 0x1137
+
+#define PCI_VENDOR_ID_ZIATECH 0x1138
+#define PCI_DEVICE_ID_ZIATECH_5550_HC 0x5550
+
+
+#define PCI_VENDOR_ID_SYSKONNECT 0x1148
+#define PCI_DEVICE_ID_SYSKONNECT_TR 0x4200
+#define PCI_DEVICE_ID_SYSKONNECT_GE 0x4300
+#define PCI_DEVICE_ID_SYSKONNECT_YU 0x4320
+#define PCI_DEVICE_ID_SYSKONNECT_9DXX 0x4400
+#define PCI_DEVICE_ID_SYSKONNECT_9MXX 0x4500
+
+#define PCI_VENDOR_ID_DIGI 0x114f
+#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E 0x0070
+#define PCI_DEVICE_ID_DIGI_DF_M_E 0x0071
+#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A 0x0072
+#define PCI_DEVICE_ID_DIGI_DF_M_A 0x0073
+#define PCI_DEVICE_ID_NEO_2DB9 0x00C8
+#define PCI_DEVICE_ID_NEO_2DB9PRI 0x00C9
+#define PCI_DEVICE_ID_NEO_2RJ45 0x00CA
+#define PCI_DEVICE_ID_NEO_2RJ45PRI 0x00CB
+#define PCIE_DEVICE_ID_NEO_4_IBM 0x00F4
+
+#define PCI_VENDOR_ID_XIRCOM 0x115d
+#define PCI_DEVICE_ID_XIRCOM_RBM56G 0x0101
+#define PCI_DEVICE_ID_XIRCOM_X3201_MDM 0x0103
+
+#define PCI_VENDOR_ID_SERVERWORKS 0x1166
+#define PCI_DEVICE_ID_SERVERWORKS_HE 0x0008
+#define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009
+#define PCI_DEVICE_ID_SERVERWORKS_GCNB_LE 0x0017
+#define PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB 0x0036
+#define PCI_DEVICE_ID_SERVERWORKS_EPB 0x0103
+#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132
+#define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200
+#define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6 0x0203
+#define PCI_DEVICE_ID_SERVERWORKS_HT1000SB 0x0205
+#define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211
+#define PCI_DEVICE_ID_SERVERWORKS_CSB5IDE 0x0212
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE 0x0213
+#define PCI_DEVICE_ID_SERVERWORKS_HT1000IDE 0x0214
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 0x0217
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227
+
+#define PCI_VENDOR_ID_SBE 0x1176
+#define PCI_DEVICE_ID_SBE_WANXL100 0x0301
+#define PCI_DEVICE_ID_SBE_WANXL200 0x0302
+#define PCI_DEVICE_ID_SBE_WANXL400 0x0104
+
+#define PCI_VENDOR_ID_TOSHIBA 0x1179
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO 0x0102
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1 0x0103
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_2 0x0105
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC100 0x0617
+
+#define PCI_VENDOR_ID_TOSHIBA_2 0x102f
+#define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU 0x0031
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939 0x0032
+#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE 0x0105
+#define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108
+#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
+
+#define PCI_VENDOR_ID_ATTO 0x117c
+
+#define PCI_VENDOR_ID_RICOH 0x1180
+#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465
+#define PCI_DEVICE_ID_RICOH_RL5C466 0x0466
+#define PCI_DEVICE_ID_RICOH_RL5C475 0x0475
+#define PCI_DEVICE_ID_RICOH_RL5C476 0x0476
+#define PCI_DEVICE_ID_RICOH_RL5C478 0x0478
+#define PCI_DEVICE_ID_RICOH_R5C822 0x0822
+#define PCI_DEVICE_ID_RICOH_R5C832 0x0832
+#define PCI_DEVICE_ID_RICOH_R5C843 0x0843
+
+#define PCI_VENDOR_ID_DLINK 0x1186
+#define PCI_DEVICE_ID_DLINK_DGE510T 0x4c00
+
+#define PCI_VENDOR_ID_ARTOP 0x1191
+#define PCI_DEVICE_ID_ARTOP_ATP850UF 0x0005
+#define PCI_DEVICE_ID_ARTOP_ATP860 0x0006
+#define PCI_DEVICE_ID_ARTOP_ATP860R 0x0007
+#define PCI_DEVICE_ID_ARTOP_ATP865 0x0008
+#define PCI_DEVICE_ID_ARTOP_ATP865R 0x0009
+#define PCI_DEVICE_ID_ARTOP_AEC7610 0x8002
+#define PCI_DEVICE_ID_ARTOP_AEC7612UW 0x8010
+#define PCI_DEVICE_ID_ARTOP_AEC7612U 0x8020
+#define PCI_DEVICE_ID_ARTOP_AEC7612S 0x8030
+#define PCI_DEVICE_ID_ARTOP_AEC7612D 0x8040
+#define PCI_DEVICE_ID_ARTOP_AEC7612SUW 0x8050
+#define PCI_DEVICE_ID_ARTOP_8060 0x8060
+
+#define PCI_VENDOR_ID_ZEITNET 0x1193
+#define PCI_DEVICE_ID_ZEITNET_1221 0x0001
+#define PCI_DEVICE_ID_ZEITNET_1225 0x0002
+
+#define PCI_VENDOR_ID_FUJITSU_ME 0x119e
+#define PCI_DEVICE_ID_FUJITSU_FS155 0x0001
+#define PCI_DEVICE_ID_FUJITSU_FS50 0x0003
+
+#define PCI_SUBVENDOR_ID_KEYSPAN 0x11a9
+#define PCI_SUBDEVICE_ID_KEYSPAN_SX2 0x5334
+
+#define PCI_VENDOR_ID_MARVELL 0x11ab
+#define PCI_DEVICE_ID_MARVELL_GT64111 0x4146
+#define PCI_DEVICE_ID_MARVELL_GT64260 0x6430
+#define PCI_DEVICE_ID_MARVELL_MV64360 0x6460
+#define PCI_DEVICE_ID_MARVELL_MV64460 0x6480
+#define PCI_DEVICE_ID_MARVELL_88ALP01_NAND 0x4100
+#define PCI_DEVICE_ID_MARVELL_88ALP01_SD 0x4101
+#define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC 0x4102
+
+#define PCI_VENDOR_ID_V3 0x11b0
+#define PCI_DEVICE_ID_V3_V960 0x0001
+#define PCI_DEVICE_ID_V3_V351 0x0002
+
+#define PCI_VENDOR_ID_ATT 0x11c1
+#define PCI_DEVICE_ID_ATT_VENUS_MODEM 0x480
+
+#define PCI_VENDOR_ID_SPECIALIX 0x11cb
+#define PCI_DEVICE_ID_SPECIALIX_IO8 0x2000
+#define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000
+#define PCI_SUBDEVICE_ID_SPECIALIX_SPEED4 0xa004
+
+#define PCI_VENDOR_ID_ANALOG_DEVICES 0x11d4
+#define PCI_DEVICE_ID_AD1889JS 0x1889
+
+#define PCI_DEVICE_ID_SEGA_BBA 0x1234
+
+#define PCI_VENDOR_ID_ZORAN 0x11de
+#define PCI_DEVICE_ID_ZORAN_36057 0x6057
+#define PCI_DEVICE_ID_ZORAN_36120 0x6120
+
+#define PCI_VENDOR_ID_COMPEX 0x11f6
+#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112
+
+#define PCI_VENDOR_ID_RP 0x11fe
+#define PCI_DEVICE_ID_RP32INTF 0x0001
+#define PCI_DEVICE_ID_RP8INTF 0x0002
+#define PCI_DEVICE_ID_RP16INTF 0x0003
+#define PCI_DEVICE_ID_RP4QUAD 0x0004
+#define PCI_DEVICE_ID_RP8OCTA 0x0005
+#define PCI_DEVICE_ID_RP8J 0x0006
+#define PCI_DEVICE_ID_RP4J 0x0007
+#define PCI_DEVICE_ID_RP8SNI 0x0008
+#define PCI_DEVICE_ID_RP16SNI 0x0009
+#define PCI_DEVICE_ID_RPP4 0x000A
+#define PCI_DEVICE_ID_RPP8 0x000B
+#define PCI_DEVICE_ID_RP4M 0x000D
+#define PCI_DEVICE_ID_RP2_232 0x000E
+#define PCI_DEVICE_ID_RP2_422 0x000F
+#define PCI_DEVICE_ID_URP32INTF 0x0801
+#define PCI_DEVICE_ID_URP8INTF 0x0802
+#define PCI_DEVICE_ID_URP16INTF 0x0803
+#define PCI_DEVICE_ID_URP8OCTA 0x0805
+#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C
+#define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D
+#define PCI_DEVICE_ID_CRP16INTF 0x0903
+
+#define PCI_VENDOR_ID_CYCLADES 0x120e
+#define PCI_DEVICE_ID_CYCLOM_Y_Lo 0x0100
+#define PCI_DEVICE_ID_CYCLOM_Y_Hi 0x0101
+#define PCI_DEVICE_ID_CYCLOM_4Y_Lo 0x0102
+#define PCI_DEVICE_ID_CYCLOM_4Y_Hi 0x0103
+#define PCI_DEVICE_ID_CYCLOM_8Y_Lo 0x0104
+#define PCI_DEVICE_ID_CYCLOM_8Y_Hi 0x0105
+#define PCI_DEVICE_ID_CYCLOM_Z_Lo 0x0200
+#define PCI_DEVICE_ID_CYCLOM_Z_Hi 0x0201
+#define PCI_DEVICE_ID_PC300_RX_2 0x0300
+#define PCI_DEVICE_ID_PC300_RX_1 0x0301
+#define PCI_DEVICE_ID_PC300_TE_2 0x0310
+#define PCI_DEVICE_ID_PC300_TE_1 0x0311
+#define PCI_DEVICE_ID_PC300_TE_M_2 0x0320
+#define PCI_DEVICE_ID_PC300_TE_M_1 0x0321
+
+#define PCI_VENDOR_ID_ESSENTIAL 0x120f
+#define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER 0x0001
+
+#define PCI_VENDOR_ID_O2 0x1217
+#define PCI_DEVICE_ID_O2_6729 0x6729
+#define PCI_DEVICE_ID_O2_6730 0x673a
+#define PCI_DEVICE_ID_O2_6832 0x6832
+#define PCI_DEVICE_ID_O2_6836 0x6836
+
+#define PCI_VENDOR_ID_3DFX 0x121a
+#define PCI_DEVICE_ID_3DFX_VOODOO 0x0001
+#define PCI_DEVICE_ID_3DFX_VOODOO2 0x0002
+#define PCI_DEVICE_ID_3DFX_BANSHEE 0x0003
+#define PCI_DEVICE_ID_3DFX_VOODOO3 0x0005
+#define PCI_DEVICE_ID_3DFX_VOODOO5 0x0009
+
+#define PCI_VENDOR_ID_AVM 0x1244
+#define PCI_DEVICE_ID_AVM_B1 0x0700
+#define PCI_DEVICE_ID_AVM_C4 0x0800
+#define PCI_DEVICE_ID_AVM_A1 0x0a00
+#define PCI_DEVICE_ID_AVM_A1_V2 0x0e00
+#define PCI_DEVICE_ID_AVM_C2 0x1100
+#define PCI_DEVICE_ID_AVM_T1 0x1200
+
+#define PCI_VENDOR_ID_STALLION 0x124d
+
+/* Allied Telesyn */
+#define PCI_VENDOR_ID_AT 0x1259
+#define PCI_SUBDEVICE_ID_AT_2700FX 0x2701
+#define PCI_SUBDEVICE_ID_AT_2701FX 0x2703
+
+#define PCI_VENDOR_ID_ESS 0x125d
+#define PCI_DEVICE_ID_ESS_ESS1968 0x1968
+#define PCI_DEVICE_ID_ESS_ESS1978 0x1978
+#define PCI_DEVICE_ID_ESS_ALLEGRO_1 0x1988
+#define PCI_DEVICE_ID_ESS_ALLEGRO 0x1989
+#define PCI_DEVICE_ID_ESS_CANYON3D_2LE 0x1990
+#define PCI_DEVICE_ID_ESS_CANYON3D_2 0x1992
+#define PCI_DEVICE_ID_ESS_MAESTRO3 0x1998
+#define PCI_DEVICE_ID_ESS_MAESTRO3_1 0x1999
+#define PCI_DEVICE_ID_ESS_MAESTRO3_HW 0x199a
+#define PCI_DEVICE_ID_ESS_MAESTRO3_2 0x199b
+
+#define PCI_VENDOR_ID_SATSAGEM 0x1267
+#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016
+
+#define PCI_VENDOR_ID_ENSONIQ 0x1274
+#define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880
+#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000
+#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
+
+#define PCI_VENDOR_ID_TRANSMETA 0x1279
+#define PCI_DEVICE_ID_EFFICEON 0x0060
+
+#define PCI_VENDOR_ID_ROCKWELL 0x127A
+
+#define PCI_VENDOR_ID_ITE 0x1283
+#define PCI_DEVICE_ID_ITE_8211 0x8211
+#define PCI_DEVICE_ID_ITE_8212 0x8212
+#define PCI_DEVICE_ID_ITE_8213 0x8213
+#define PCI_DEVICE_ID_ITE_8152 0x8152
+#define PCI_DEVICE_ID_ITE_8872 0x8872
+#define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886
+
+/* formerly Platform Tech */
+#define PCI_DEVICE_ID_ESS_ESS0100 0x0100
+
+#define PCI_VENDOR_ID_ALTEON 0x12ae
+
+#define PCI_SUBVENDOR_ID_CONNECT_TECH 0x12c4
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232 0x0001
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232 0x0002
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232 0x0003
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485 0x0004
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4 0x0005
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485 0x0006
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2 0x0007
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485 0x0008
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6 0x0009
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1 0x000A
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1 0x000B
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ 0x000C
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_PTM 0x000D
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_NT960PCI 0x0100
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2 0x0201
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4 0x0202
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232 0x0300
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232 0x0301
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232 0x0302
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1 0x0310
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2 0x0311
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4 0x0312
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2 0x0320
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4 0x0321
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8 0x0322
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485 0x0330
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485 0x0331
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485 0x0332
+
+#define PCI_VENDOR_ID_NVIDIA_SGS 0x12d2
+#define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018
+
+#define PCI_SUBVENDOR_ID_CHASE_PCIFAST 0x12E0
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST4 0x0031
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST8 0x0021
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16 0x0011
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC 0x0041
+#define PCI_SUBVENDOR_ID_CHASE_PCIRAS 0x124D
+#define PCI_SUBDEVICE_ID_CHASE_PCIRAS4 0xF001
+#define PCI_SUBDEVICE_ID_CHASE_PCIRAS8 0xF010
+
+#define PCI_VENDOR_ID_AUREAL 0x12eb
+#define PCI_DEVICE_ID_AUREAL_VORTEX_1 0x0001
+#define PCI_DEVICE_ID_AUREAL_VORTEX_2 0x0002
+#define PCI_DEVICE_ID_AUREAL_ADVANTAGE 0x0003
+
+#define PCI_VENDOR_ID_ELECTRONICDESIGNGMBH 0x12f8
+#define PCI_DEVICE_ID_LML_33R10 0x8a02
+
+#define PCI_VENDOR_ID_ESDGMBH 0x12fe
+#define PCI_DEVICE_ID_ESDGMBH_CPCIASIO4 0x0111
+
+#define PCI_VENDOR_ID_SIIG 0x131f
+#define PCI_SUBVENDOR_ID_SIIG 0x131f
+#define PCI_DEVICE_ID_SIIG_1S_10x_550 0x1000
+#define PCI_DEVICE_ID_SIIG_1S_10x_650 0x1001
+#define PCI_DEVICE_ID_SIIG_1S_10x_850 0x1002
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_550 0x1010
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_650 0x1011
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_850 0x1012
+#define PCI_DEVICE_ID_SIIG_1P_10x 0x1020
+#define PCI_DEVICE_ID_SIIG_2P_10x 0x1021
+#define PCI_DEVICE_ID_SIIG_2S_10x_550 0x1030
+#define PCI_DEVICE_ID_SIIG_2S_10x_650 0x1031
+#define PCI_DEVICE_ID_SIIG_2S_10x_850 0x1032
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_550 0x1034
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_650 0x1035
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_850 0x1036
+#define PCI_DEVICE_ID_SIIG_4S_10x_550 0x1050
+#define PCI_DEVICE_ID_SIIG_4S_10x_650 0x1051
+#define PCI_DEVICE_ID_SIIG_4S_10x_850 0x1052
+#define PCI_DEVICE_ID_SIIG_1S_20x_550 0x2000
+#define PCI_DEVICE_ID_SIIG_1S_20x_650 0x2001
+#define PCI_DEVICE_ID_SIIG_1S_20x_850 0x2002
+#define PCI_DEVICE_ID_SIIG_1P_20x 0x2020
+#define PCI_DEVICE_ID_SIIG_2P_20x 0x2021
+#define PCI_DEVICE_ID_SIIG_2S_20x_550 0x2030
+#define PCI_DEVICE_ID_SIIG_2S_20x_650 0x2031
+#define PCI_DEVICE_ID_SIIG_2S_20x_850 0x2032
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_550 0x2040
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_650 0x2041
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_850 0x2042
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_550 0x2010
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_650 0x2011
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_850 0x2012
+#define PCI_DEVICE_ID_SIIG_4S_20x_550 0x2050
+#define PCI_DEVICE_ID_SIIG_4S_20x_650 0x2051
+#define PCI_DEVICE_ID_SIIG_4S_20x_850 0x2052
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_550 0x2060
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062
+#define PCI_DEVICE_ID_SIIG_8S_20x_550 0x2080
+#define PCI_DEVICE_ID_SIIG_8S_20x_650 0x2081
+#define PCI_DEVICE_ID_SIIG_8S_20x_850 0x2082
+#define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050
+
+#define PCI_VENDOR_ID_RADISYS 0x1331
+
+#define PCI_VENDOR_ID_MICRO_MEMORY 0x1332
+#define PCI_DEVICE_ID_MICRO_MEMORY_5415CN 0x5415
+#define PCI_DEVICE_ID_MICRO_MEMORY_5425CN 0x5425
+#define PCI_DEVICE_ID_MICRO_MEMORY_6155 0x6155
+
+#define PCI_VENDOR_ID_DOMEX 0x134a
+#define PCI_DEVICE_ID_DOMEX_DMX3191D 0x0001
+
+#define PCI_VENDOR_ID_INTASHIELD 0x135a
+#define PCI_DEVICE_ID_INTASHIELD_IS200 0x0d80
+#define PCI_DEVICE_ID_INTASHIELD_IS400 0x0dc0
+
+#define PCI_VENDOR_ID_QUATECH 0x135C
+#define PCI_DEVICE_ID_QUATECH_QSC100 0x0010
+#define PCI_DEVICE_ID_QUATECH_DSC100 0x0020
+#define PCI_DEVICE_ID_QUATECH_ESC100D 0x0050
+#define PCI_DEVICE_ID_QUATECH_ESC100M 0x0060
+#define PCI_DEVICE_ID_QUATECH_SPPXP_100 0x0278
+
+#define PCI_VENDOR_ID_SEALEVEL 0x135e
+#define PCI_DEVICE_ID_SEALEVEL_U530 0x7101
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM2 0x7201
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM422 0x7402
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM232 0x7202
+#define PCI_DEVICE_ID_SEALEVEL_COMM4 0x7401
+#define PCI_DEVICE_ID_SEALEVEL_COMM8 0x7801
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM8 0x7804
+
+#define PCI_VENDOR_ID_HYPERCOPE 0x1365
+#define PCI_DEVICE_ID_HYPERCOPE_PLX 0x9050
+#define PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO 0x0104
+#define PCI_SUBDEVICE_ID_HYPERCOPE_ERGO 0x0106
+#define PCI_SUBDEVICE_ID_HYPERCOPE_METRO 0x0107
+#define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2 0x0108
+
+#define PCI_VENDOR_ID_KAWASAKI 0x136b
+#define PCI_DEVICE_ID_MCHIP_KL5A72002 0xff01
+
+#define PCI_VENDOR_ID_CNET 0x1371
+#define PCI_DEVICE_ID_CNET_GIGACARD 0x434e
+
+#define PCI_VENDOR_ID_LMC 0x1376
+#define PCI_DEVICE_ID_LMC_HSSI 0x0003
+#define PCI_DEVICE_ID_LMC_DS3 0x0004
+#define PCI_DEVICE_ID_LMC_SSI 0x0005
+#define PCI_DEVICE_ID_LMC_T1 0x0006
+
+#define PCI_VENDOR_ID_NETGEAR 0x1385
+#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a
+
+#define PCI_VENDOR_ID_APPLICOM 0x1389
+#define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001
+#define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002
+#define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003
+
+#define PCI_VENDOR_ID_MOXA 0x1393
+#define PCI_DEVICE_ID_MOXA_RC7000 0x0001
+#define PCI_DEVICE_ID_MOXA_CP102 0x1020
+#define PCI_DEVICE_ID_MOXA_CP102UL 0x1021
+#define PCI_DEVICE_ID_MOXA_CP102U 0x1022
+#define PCI_DEVICE_ID_MOXA_C104 0x1040
+#define PCI_DEVICE_ID_MOXA_CP104U 0x1041
+#define PCI_DEVICE_ID_MOXA_CP104JU 0x1042
+#define PCI_DEVICE_ID_MOXA_CP104EL 0x1043
+#define PCI_DEVICE_ID_MOXA_CT114 0x1140
+#define PCI_DEVICE_ID_MOXA_CP114 0x1141
+#define PCI_DEVICE_ID_MOXA_CP118U 0x1180
+#define PCI_DEVICE_ID_MOXA_CP118EL 0x1181
+#define PCI_DEVICE_ID_MOXA_CP132 0x1320
+#define PCI_DEVICE_ID_MOXA_CP132U 0x1321
+#define PCI_DEVICE_ID_MOXA_CP134U 0x1340
+#define PCI_DEVICE_ID_MOXA_C168 0x1680
+#define PCI_DEVICE_ID_MOXA_CP168U 0x1681
+#define PCI_DEVICE_ID_MOXA_CP168EL 0x1682
+#define PCI_DEVICE_ID_MOXA_CP204J 0x2040
+#define PCI_DEVICE_ID_MOXA_C218 0x2180
+#define PCI_DEVICE_ID_MOXA_C320 0x3200
+
+#define PCI_VENDOR_ID_CCD 0x1397
+#define PCI_DEVICE_ID_CCD_HFC4S 0x08B4
+#define PCI_SUBDEVICE_ID_CCD_PMX2S 0x1234
+#define PCI_DEVICE_ID_CCD_HFC8S 0x16B8
+#define PCI_DEVICE_ID_CCD_2BD0 0x2bd0
+#define PCI_DEVICE_ID_CCD_HFCE1 0x30B1
+#define PCI_SUBDEVICE_ID_CCD_SPD4S 0x3136
+#define PCI_SUBDEVICE_ID_CCD_SPDE1 0x3137
+#define PCI_DEVICE_ID_CCD_B000 0xb000
+#define PCI_DEVICE_ID_CCD_B006 0xb006
+#define PCI_DEVICE_ID_CCD_B007 0xb007
+#define PCI_DEVICE_ID_CCD_B008 0xb008
+#define PCI_DEVICE_ID_CCD_B009 0xb009
+#define PCI_DEVICE_ID_CCD_B00A 0xb00a
+#define PCI_DEVICE_ID_CCD_B00B 0xb00b
+#define PCI_DEVICE_ID_CCD_B00C 0xb00c
+#define PCI_DEVICE_ID_CCD_B100 0xb100
+#define PCI_SUBDEVICE_ID_CCD_IOB4ST 0xB520
+#define PCI_SUBDEVICE_ID_CCD_IOB8STR 0xB521
+#define PCI_SUBDEVICE_ID_CCD_IOB8ST 0xB522
+#define PCI_SUBDEVICE_ID_CCD_IOB1E1 0xB523
+#define PCI_SUBDEVICE_ID_CCD_SWYX4S 0xB540
+#define PCI_SUBDEVICE_ID_CCD_JH4S20 0xB550
+#define PCI_SUBDEVICE_ID_CCD_IOB8ST_1 0xB552
+#define PCI_SUBDEVICE_ID_CCD_BN4S 0xB560
+#define PCI_SUBDEVICE_ID_CCD_BN8S 0xB562
+#define PCI_SUBDEVICE_ID_CCD_BNE1 0xB563
+#define PCI_SUBDEVICE_ID_CCD_BNE1D 0xB564
+#define PCI_SUBDEVICE_ID_CCD_BNE1DP 0xB565
+#define PCI_SUBDEVICE_ID_CCD_BN2S 0xB566
+#define PCI_SUBDEVICE_ID_CCD_BN1SM 0xB567
+#define PCI_SUBDEVICE_ID_CCD_BN4SM 0xB568
+#define PCI_SUBDEVICE_ID_CCD_BN2SM 0xB569
+#define PCI_SUBDEVICE_ID_CCD_BNE1M 0xB56A
+#define PCI_SUBDEVICE_ID_CCD_BN8SP 0xB56B
+#define PCI_SUBDEVICE_ID_CCD_HFC4S 0xB620
+#define PCI_SUBDEVICE_ID_CCD_HFC8S 0xB622
+#define PCI_DEVICE_ID_CCD_B700 0xb700
+#define PCI_DEVICE_ID_CCD_B701 0xb701
+#define PCI_SUBDEVICE_ID_CCD_HFCE1 0xC523
+#define PCI_SUBDEVICE_ID_CCD_OV2S 0xE884
+#define PCI_SUBDEVICE_ID_CCD_OV4S 0xE888
+#define PCI_SUBDEVICE_ID_CCD_OV8S 0xE998
+
+#define PCI_VENDOR_ID_EXAR 0x13a8
+#define PCI_DEVICE_ID_EXAR_XR17C152 0x0152
+#define PCI_DEVICE_ID_EXAR_XR17C154 0x0154
+#define PCI_DEVICE_ID_EXAR_XR17C158 0x0158
+
+#define PCI_VENDOR_ID_MICROGATE 0x13c0
+#define PCI_DEVICE_ID_MICROGATE_USC 0x0010
+#define PCI_DEVICE_ID_MICROGATE_SCA 0x0030
+
+#define PCI_VENDOR_ID_3WARE 0x13C1
+#define PCI_DEVICE_ID_3WARE_1000 0x1000
+#define PCI_DEVICE_ID_3WARE_7000 0x1001
+#define PCI_DEVICE_ID_3WARE_9000 0x1002
+
+#define PCI_VENDOR_ID_IOMEGA 0x13ca
+#define PCI_DEVICE_ID_IOMEGA_BUZ 0x4231
+
+#define PCI_VENDOR_ID_ABOCOM 0x13D1
+#define PCI_DEVICE_ID_ABOCOM_2BD1 0x2BD1
+
+#define PCI_VENDOR_ID_SUNDANCE 0x13f0
+
+#define PCI_VENDOR_ID_CMEDIA 0x13f6
+#define PCI_DEVICE_ID_CMEDIA_CM8338A 0x0100
+#define PCI_DEVICE_ID_CMEDIA_CM8338B 0x0101
+#define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111
+#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112
+
+#define PCI_VENDOR_ID_LAVA 0x1407
+#define PCI_DEVICE_ID_LAVA_DSERIAL 0x0100 /* 2x 16550 */
+#define PCI_DEVICE_ID_LAVA_QUATRO_A 0x0101 /* 2x 16550, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_QUATRO_B 0x0102 /* 2x 16550, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_OCTO_A 0x0180 /* 4x 16550A, half of 8 port */
+#define PCI_DEVICE_ID_LAVA_OCTO_B 0x0181 /* 4x 16550A, half of 8 port */
+#define PCI_DEVICE_ID_LAVA_PORT_PLUS 0x0200 /* 2x 16650 */
+#define PCI_DEVICE_ID_LAVA_QUAD_A 0x0201 /* 2x 16650, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_QUAD_B 0x0202 /* 2x 16650, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_SSERIAL 0x0500 /* 1x 16550 */
+#define PCI_DEVICE_ID_LAVA_PORT_650 0x0600 /* 1x 16650 */
+#define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8002 /* The Lava Dual Parallel is */
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8003 /* two PCI devices on a card */
+#define PCI_DEVICE_ID_LAVA_BOCA_IOPPAR 0x8800
+
+#define PCI_VENDOR_ID_TIMEDIA 0x1409
+#define PCI_DEVICE_ID_TIMEDIA_1889 0x7168
+
+#define PCI_VENDOR_ID_ICE 0x1412
+#define PCI_DEVICE_ID_ICE_1712 0x1712
+#define PCI_DEVICE_ID_VT1724 0x1724
+
+#define PCI_VENDOR_ID_OXSEMI 0x1415
+#define PCI_DEVICE_ID_OXSEMI_12PCI840 0x8403
+#define PCI_DEVICE_ID_OXSEMI_PCIe840 0xC000
+#define PCI_DEVICE_ID_OXSEMI_PCIe840_G 0xC004
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_0 0xC100
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_0_G 0xC104
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_1 0xC110
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_G 0xC114
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_U 0xC118
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_GU 0xC11C
+#define PCI_DEVICE_ID_OXSEMI_16PCI954 0x9501
+#define PCI_DEVICE_ID_OXSEMI_16PCI95N 0x9511
+#define PCI_DEVICE_ID_OXSEMI_16PCI954PP 0x9513
+#define PCI_DEVICE_ID_OXSEMI_16PCI952 0x9521
+#define PCI_DEVICE_ID_OXSEMI_16PCI952PP 0x9523
+
+#define PCI_VENDOR_ID_CHELSIO 0x1425
+
+#define PCI_VENDOR_ID_SAMSUNG 0x144d
+
+#define PCI_VENDOR_ID_MYRICOM 0x14c1
+
+#define PCI_VENDOR_ID_TITAN 0x14D2
+#define PCI_DEVICE_ID_TITAN_010L 0x8001
+#define PCI_DEVICE_ID_TITAN_100L 0x8010
+#define PCI_DEVICE_ID_TITAN_110L 0x8011
+#define PCI_DEVICE_ID_TITAN_200L 0x8020
+#define PCI_DEVICE_ID_TITAN_210L 0x8021
+#define PCI_DEVICE_ID_TITAN_400L 0x8040
+#define PCI_DEVICE_ID_TITAN_800L 0x8080
+#define PCI_DEVICE_ID_TITAN_100 0xA001
+#define PCI_DEVICE_ID_TITAN_200 0xA005
+#define PCI_DEVICE_ID_TITAN_400 0xA003
+#define PCI_DEVICE_ID_TITAN_800B 0xA004
+
+#define PCI_VENDOR_ID_PANACOM 0x14d4
+#define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400
+#define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402
+
+#define PCI_VENDOR_ID_SIPACKETS 0x14d9
+#define PCI_DEVICE_ID_SP1011 0x0010
+
+#define PCI_VENDOR_ID_AFAVLAB 0x14db
+#define PCI_DEVICE_ID_AFAVLAB_P028 0x2180
+#define PCI_DEVICE_ID_AFAVLAB_P030 0x2182
+#define PCI_SUBDEVICE_ID_AFAVLAB_P061 0x2150
+
+#define PCI_VENDOR_ID_BROADCOM 0x14e4
+#define PCI_DEVICE_ID_TIGON3_5752 0x1600
+#define PCI_DEVICE_ID_TIGON3_5752M 0x1601
+#define PCI_DEVICE_ID_NX2_5709 0x1639
+#define PCI_DEVICE_ID_NX2_5709S 0x163a
+#define PCI_DEVICE_ID_TIGON3_5700 0x1644
+#define PCI_DEVICE_ID_TIGON3_5701 0x1645
+#define PCI_DEVICE_ID_TIGON3_5702 0x1646
+#define PCI_DEVICE_ID_TIGON3_5703 0x1647
+#define PCI_DEVICE_ID_TIGON3_5704 0x1648
+#define PCI_DEVICE_ID_TIGON3_5704S_2 0x1649
+#define PCI_DEVICE_ID_NX2_5706 0x164a
+#define PCI_DEVICE_ID_NX2_5708 0x164c
+#define PCI_DEVICE_ID_TIGON3_5702FE 0x164d
+#define PCI_DEVICE_ID_NX2_57710 0x164e
+#define PCI_DEVICE_ID_NX2_57711 0x164f
+#define PCI_DEVICE_ID_NX2_57711E 0x1650
+#define PCI_DEVICE_ID_TIGON3_5705 0x1653
+#define PCI_DEVICE_ID_TIGON3_5705_2 0x1654
+#define PCI_DEVICE_ID_TIGON3_5720 0x1658
+#define PCI_DEVICE_ID_TIGON3_5721 0x1659
+#define PCI_DEVICE_ID_TIGON3_5722 0x165a
+#define PCI_DEVICE_ID_TIGON3_5723 0x165b
+#define PCI_DEVICE_ID_TIGON3_5705M 0x165d
+#define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e
+#define PCI_DEVICE_ID_TIGON3_5714 0x1668
+#define PCI_DEVICE_ID_TIGON3_5714S 0x1669
+#define PCI_DEVICE_ID_TIGON3_5780 0x166a
+#define PCI_DEVICE_ID_TIGON3_5780S 0x166b
+#define PCI_DEVICE_ID_TIGON3_5705F 0x166e
+#define PCI_DEVICE_ID_TIGON3_5754M 0x1672
+#define PCI_DEVICE_ID_TIGON3_5755M 0x1673
+#define PCI_DEVICE_ID_TIGON3_5756 0x1674
+#define PCI_DEVICE_ID_TIGON3_5750 0x1676
+#define PCI_DEVICE_ID_TIGON3_5751 0x1677
+#define PCI_DEVICE_ID_TIGON3_5715 0x1678
+#define PCI_DEVICE_ID_TIGON3_5715S 0x1679
+#define PCI_DEVICE_ID_TIGON3_5754 0x167a
+#define PCI_DEVICE_ID_TIGON3_5755 0x167b
+#define PCI_DEVICE_ID_TIGON3_5750M 0x167c
+#define PCI_DEVICE_ID_TIGON3_5751M 0x167d
+#define PCI_DEVICE_ID_TIGON3_5751F 0x167e
+#define PCI_DEVICE_ID_TIGON3_5787F 0x167f
+#define PCI_DEVICE_ID_TIGON3_5761E 0x1680
+#define PCI_DEVICE_ID_TIGON3_5761 0x1681
+#define PCI_DEVICE_ID_TIGON3_5764 0x1684
+#define PCI_DEVICE_ID_TIGON3_5787M 0x1693
+#define PCI_DEVICE_ID_TIGON3_5782 0x1696
+#define PCI_DEVICE_ID_TIGON3_5784 0x1698
+#define PCI_DEVICE_ID_TIGON3_5785 0x1699
+#define PCI_DEVICE_ID_TIGON3_5786 0x169a
+#define PCI_DEVICE_ID_TIGON3_5787 0x169b
+#define PCI_DEVICE_ID_TIGON3_5788 0x169c
+#define PCI_DEVICE_ID_TIGON3_5789 0x169d
+#define PCI_DEVICE_ID_TIGON3_5702X 0x16a6
+#define PCI_DEVICE_ID_TIGON3_5703X 0x16a7
+#define PCI_DEVICE_ID_TIGON3_5704S 0x16a8
+#define PCI_DEVICE_ID_NX2_5706S 0x16aa
+#define PCI_DEVICE_ID_NX2_5708S 0x16ac
+#define PCI_DEVICE_ID_TIGON3_5702A3 0x16c6
+#define PCI_DEVICE_ID_TIGON3_5703A3 0x16c7
+#define PCI_DEVICE_ID_TIGON3_5781 0x16dd
+#define PCI_DEVICE_ID_TIGON3_5753 0x16f7
+#define PCI_DEVICE_ID_TIGON3_5753M 0x16fd
+#define PCI_DEVICE_ID_TIGON3_5753F 0x16fe
+#define PCI_DEVICE_ID_TIGON3_5901 0x170d
+#define PCI_DEVICE_ID_BCM4401B1 0x170c
+#define PCI_DEVICE_ID_TIGON3_5901_2 0x170e
+#define PCI_DEVICE_ID_TIGON3_5906 0x1712
+#define PCI_DEVICE_ID_TIGON3_5906M 0x1713
+#define PCI_DEVICE_ID_BCM4401 0x4401
+#define PCI_DEVICE_ID_BCM4401B0 0x4402
+
+#define PCI_VENDOR_ID_TOPIC 0x151f
+#define PCI_DEVICE_ID_TOPIC_TP560 0x0000
+
+#define PCI_VENDOR_ID_MAINPINE 0x1522
+#define PCI_DEVICE_ID_MAINPINE_PBRIDGE 0x0100
+#define PCI_VENDOR_ID_ENE 0x1524
+#define PCI_DEVICE_ID_ENE_CB712_SD 0x0550
+#define PCI_DEVICE_ID_ENE_CB712_SD_2 0x0551
+#define PCI_DEVICE_ID_ENE_CB714_SD 0x0750
+#define PCI_DEVICE_ID_ENE_CB714_SD_2 0x0751
+#define PCI_DEVICE_ID_ENE_1211 0x1211
+#define PCI_DEVICE_ID_ENE_1225 0x1225
+#define PCI_DEVICE_ID_ENE_1410 0x1410
+#define PCI_DEVICE_ID_ENE_710 0x1411
+#define PCI_DEVICE_ID_ENE_712 0x1412
+#define PCI_DEVICE_ID_ENE_1420 0x1420
+#define PCI_DEVICE_ID_ENE_720 0x1421
+#define PCI_DEVICE_ID_ENE_722 0x1422
+
+#define PCI_SUBVENDOR_ID_PERLE 0x155f
+#define PCI_SUBDEVICE_ID_PCI_RAS4 0xf001
+#define PCI_SUBDEVICE_ID_PCI_RAS8 0xf010
+
+#define PCI_VENDOR_ID_SYBA 0x1592
+#define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782
+#define PCI_DEVICE_ID_SYBA_1P_ECP 0x0783
+
+#define PCI_VENDOR_ID_MORETON 0x15aa
+#define PCI_DEVICE_ID_RASTEL_2PORT 0x2000
+
+#define PCI_VENDOR_ID_ZOLTRIX 0x15b0
+#define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2bd0
+
+#define PCI_VENDOR_ID_MELLANOX 0x15b3
+#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44
+#define PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE 0x5a46
+#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278
+#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282
+#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
+#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274
+
+#define PCI_VENDOR_ID_QUICKNET 0x15e2
+#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500
+
+/*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+#define PCI_VENDOR_ID_ADDIDATA_OLD 0x10E8
+#define PCI_VENDOR_ID_ADDIDATA 0x15B8
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500 0x7000
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420 0x7001
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300 0x7002
+#define PCI_DEVICE_ID_ADDIDATA_APCI7800 0x818E
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500_2 0x7009
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420_2 0x700A
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300_2 0x700B
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500_3 0x700C
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420_3 0x700D
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300_3 0x700E
+#define PCI_DEVICE_ID_ADDIDATA_APCI7800_3 0x700F
+
+#define PCI_VENDOR_ID_PDC 0x15e9
+
+#define PCI_VENDOR_ID_FARSITE 0x1619
+#define PCI_DEVICE_ID_FARSITE_T2P 0x0400
+#define PCI_DEVICE_ID_FARSITE_T4P 0x0440
+#define PCI_DEVICE_ID_FARSITE_T1U 0x0610
+#define PCI_DEVICE_ID_FARSITE_T2U 0x0620
+#define PCI_DEVICE_ID_FARSITE_T4U 0x0640
+#define PCI_DEVICE_ID_FARSITE_TE1 0x1610
+#define PCI_DEVICE_ID_FARSITE_TE1C 0x1612
+
+#define PCI_VENDOR_ID_ARIMA 0x161f
+
+#define PCI_VENDOR_ID_BROCADE 0x1657
+
+#define PCI_VENDOR_ID_SIBYTE 0x166d
+#define PCI_DEVICE_ID_BCM1250_PCI 0x0001
+#define PCI_DEVICE_ID_BCM1250_HT 0x0002
+
+#define PCI_VENDOR_ID_ATHEROS 0x168c
+
+#define PCI_VENDOR_ID_NETCELL 0x169c
+#define PCI_DEVICE_ID_REVOLUTION 0x0044
+
+#define PCI_VENDOR_ID_CENATEK 0x16CA
+#define PCI_DEVICE_ID_CENATEK_IDE 0x0001
+
+#define PCI_VENDOR_ID_VITESSE 0x1725
+#define PCI_DEVICE_ID_VITESSE_VSC7174 0x7174
+
+#define PCI_VENDOR_ID_LINKSYS 0x1737
+#define PCI_DEVICE_ID_LINKSYS_EG1064 0x1064
+
+#define PCI_VENDOR_ID_ALTIMA 0x173b
+#define PCI_DEVICE_ID_ALTIMA_AC1000 0x03e8
+#define PCI_DEVICE_ID_ALTIMA_AC1001 0x03e9
+#define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea
+#define PCI_DEVICE_ID_ALTIMA_AC1003 0x03eb
+
+#define PCI_VENDOR_ID_BELKIN 0x1799
+#define PCI_DEVICE_ID_BELKIN_F5D7010V7 0x701f
+
+#define PCI_VENDOR_ID_RDC 0x17f3
+#define PCI_DEVICE_ID_RDC_R6020 0x6020
+#define PCI_DEVICE_ID_RDC_R6030 0x6030
+#define PCI_DEVICE_ID_RDC_R6040 0x6040
+#define PCI_DEVICE_ID_RDC_R6060 0x6060
+#define PCI_DEVICE_ID_RDC_R6061 0x6061
+
+#define PCI_VENDOR_ID_LENOVO 0x17aa
+
+#define PCI_VENDOR_ID_ARECA 0x17d3
+#define PCI_DEVICE_ID_ARECA_1110 0x1110
+#define PCI_DEVICE_ID_ARECA_1120 0x1120
+#define PCI_DEVICE_ID_ARECA_1130 0x1130
+#define PCI_DEVICE_ID_ARECA_1160 0x1160
+#define PCI_DEVICE_ID_ARECA_1170 0x1170
+#define PCI_DEVICE_ID_ARECA_1200 0x1200
+#define PCI_DEVICE_ID_ARECA_1201 0x1201
+#define PCI_DEVICE_ID_ARECA_1202 0x1202
+#define PCI_DEVICE_ID_ARECA_1210 0x1210
+#define PCI_DEVICE_ID_ARECA_1220 0x1220
+#define PCI_DEVICE_ID_ARECA_1230 0x1230
+#define PCI_DEVICE_ID_ARECA_1260 0x1260
+#define PCI_DEVICE_ID_ARECA_1270 0x1270
+#define PCI_DEVICE_ID_ARECA_1280 0x1280
+#define PCI_DEVICE_ID_ARECA_1380 0x1380
+#define PCI_DEVICE_ID_ARECA_1381 0x1381
+#define PCI_DEVICE_ID_ARECA_1680 0x1680
+#define PCI_DEVICE_ID_ARECA_1681 0x1681
+
+#define PCI_VENDOR_ID_S2IO 0x17d5
+#define PCI_DEVICE_ID_S2IO_WIN 0x5731
+#define PCI_DEVICE_ID_S2IO_UNI 0x5831
+#define PCI_DEVICE_ID_HERC_WIN 0x5732
+#define PCI_DEVICE_ID_HERC_UNI 0x5832
+
+#define PCI_VENDOR_ID_SITECOM 0x182d
+#define PCI_DEVICE_ID_SITECOM_DC105V2 0x3069
+
+#define PCI_VENDOR_ID_TOPSPIN 0x1867
+
+#define PCI_VENDOR_ID_TDI 0x192E
+#define PCI_DEVICE_ID_TDI_EHCI 0x0101
+
+#define PCI_VENDOR_ID_FREESCALE 0x1957
+#define PCI_DEVICE_ID_MPC8548E 0x0012
+#define PCI_DEVICE_ID_MPC8548 0x0013
+#define PCI_DEVICE_ID_MPC8543E 0x0014
+#define PCI_DEVICE_ID_MPC8543 0x0015
+#define PCI_DEVICE_ID_MPC8547E 0x0018
+#define PCI_DEVICE_ID_MPC8545E 0x0019
+#define PCI_DEVICE_ID_MPC8545 0x001a
+#define PCI_DEVICE_ID_MPC8568E 0x0020
+#define PCI_DEVICE_ID_MPC8568 0x0021
+#define PCI_DEVICE_ID_MPC8567E 0x0022
+#define PCI_DEVICE_ID_MPC8567 0x0023
+#define PCI_DEVICE_ID_MPC8533E 0x0030
+#define PCI_DEVICE_ID_MPC8533 0x0031
+#define PCI_DEVICE_ID_MPC8544E 0x0032
+#define PCI_DEVICE_ID_MPC8544 0x0033
+#define PCI_DEVICE_ID_MPC8572E 0x0040
+#define PCI_DEVICE_ID_MPC8572 0x0041
+#define PCI_DEVICE_ID_MPC8536E 0x0050
+#define PCI_DEVICE_ID_MPC8536 0x0051
+#define PCI_DEVICE_ID_MPC8641 0x7010
+#define PCI_DEVICE_ID_MPC8641D 0x7011
+#define PCI_DEVICE_ID_MPC8610 0x7018
+
+#define PCI_VENDOR_ID_PASEMI 0x1959
+
+#define PCI_VENDOR_ID_ATTANSIC 0x1969
+#define PCI_DEVICE_ID_ATTANSIC_L1 0x1048
+#define PCI_DEVICE_ID_ATTANSIC_L2 0x2048
+
+#define PCI_VENDOR_ID_JMICRON 0x197B
+#define PCI_DEVICE_ID_JMICRON_JMB360 0x2360
+#define PCI_DEVICE_ID_JMICRON_JMB361 0x2361
+#define PCI_DEVICE_ID_JMICRON_JMB363 0x2363
+#define PCI_DEVICE_ID_JMICRON_JMB365 0x2365
+#define PCI_DEVICE_ID_JMICRON_JMB366 0x2366
+#define PCI_DEVICE_ID_JMICRON_JMB368 0x2368
+#define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381
+#define PCI_DEVICE_ID_JMICRON_JMB38X_MMC 0x2382
+#define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383
+
+#define PCI_VENDOR_ID_KORENIX 0x1982
+#define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600
+#define PCI_DEVICE_ID_KORENIX_JETCARDF1 0x16ff
+
+#define PCI_VENDOR_ID_REDHAT 0x1b36
+#define PCI_DEVICE_ID_REDHAT_ROOT_PORT 0x000C
+#define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001
+
+#define PCI_VENDOR_ID_TEKRAM 0x1de1
+#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29
+
+#define PCI_VENDOR_ID_TEHUTI 0x1fc9
+#define PCI_DEVICE_ID_TEHUTI_3009 0x3009
+#define PCI_DEVICE_ID_TEHUTI_3010 0x3010
+#define PCI_DEVICE_ID_TEHUTI_3014 0x3014
+
+#define PCI_VENDOR_ID_HINT 0x3388
+#define PCI_DEVICE_ID_HINT_VXPROII_IDE 0x8013
+
+#define PCI_VENDOR_ID_3DLABS 0x3d3d
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA2 0x0007
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA2V 0x0009
+
+#define PCI_VENDOR_ID_NETXEN 0x4040
+#define PCI_DEVICE_ID_NX2031_10GXSR 0x0001
+#define PCI_DEVICE_ID_NX2031_10GCX4 0x0002
+#define PCI_DEVICE_ID_NX2031_4GCU 0x0003
+#define PCI_DEVICE_ID_NX2031_IMEZ 0x0004
+#define PCI_DEVICE_ID_NX2031_HMEZ 0x0005
+#define PCI_DEVICE_ID_NX2031_XG_MGMT 0x0024
+#define PCI_DEVICE_ID_NX2031_XG_MGMT2 0x0025
+#define PCI_DEVICE_ID_NX3031 0x0100
+
+#define PCI_VENDOR_ID_AKS 0x416c
+#define PCI_DEVICE_ID_AKS_ALADDINCARD 0x0100
+
+#define PCI_VENDOR_ID_S3 0x5333
+#define PCI_DEVICE_ID_S3_TRIO 0x8811
+#define PCI_DEVICE_ID_S3_868 0x8880
+#define PCI_DEVICE_ID_S3_968 0x88f0
+#define PCI_DEVICE_ID_S3_SAVAGE4 0x8a25
+#define PCI_DEVICE_ID_S3_PROSAVAGE8 0x8d04
+#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00
+
+#define PCI_VENDOR_ID_DUNORD 0x5544
+#define PCI_DEVICE_ID_DUNORD_I3000 0x0001
+
+#define PCI_VENDOR_ID_DCI 0x6666
+#define PCI_DEVICE_ID_DCI_PCCOM4 0x0001
+#define PCI_DEVICE_ID_DCI_PCCOM8 0x0002
+#define PCI_DEVICE_ID_DCI_PCCOM2 0x0004
+
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_DEVICE_ID_INTEL_EESSC 0x0008
+#define PCI_DEVICE_ID_INTEL_PXHD_0 0x0320
+#define PCI_DEVICE_ID_INTEL_PXHD_1 0x0321
+#define PCI_DEVICE_ID_INTEL_PXH_0 0x0329
+#define PCI_DEVICE_ID_INTEL_PXH_1 0x032A
+#define PCI_DEVICE_ID_INTEL_PXHV 0x032C
+#define PCI_DEVICE_ID_INTEL_82375 0x0482
+#define PCI_DEVICE_ID_INTEL_82424 0x0483
+#define PCI_DEVICE_ID_INTEL_82378 0x0484
+#define PCI_DEVICE_ID_INTEL_I960 0x0960
+#define PCI_DEVICE_ID_INTEL_I960RM 0x0962
+#define PCI_DEVICE_ID_INTEL_82815_MC 0x1130
+#define PCI_DEVICE_ID_INTEL_82815_CGC 0x1132
+#define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221
+#define PCI_DEVICE_ID_INTEL_7505_0 0x2550
+#define PCI_DEVICE_ID_INTEL_7205_0 0x255d
+#define PCI_DEVICE_ID_INTEL_82437 0x122d
+#define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e
+#define PCI_DEVICE_ID_INTEL_82371FB_1 0x1230
+#define PCI_DEVICE_ID_INTEL_82371MX 0x1234
+#define PCI_DEVICE_ID_INTEL_82441 0x1237
+#define PCI_DEVICE_ID_INTEL_82380FB 0x124b
+#define PCI_DEVICE_ID_INTEL_82439 0x1250
+#define PCI_DEVICE_ID_INTEL_80960_RP 0x1960
+#define PCI_DEVICE_ID_INTEL_82840_HB 0x1a21
+#define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30
+#define PCI_DEVICE_ID_INTEL_IOAT 0x1a38
+#define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410
+#define PCI_DEVICE_ID_INTEL_82801AA_1 0x2411
+#define PCI_DEVICE_ID_INTEL_82801AA_3 0x2413
+#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415
+#define PCI_DEVICE_ID_INTEL_82801AA_6 0x2416
+#define PCI_DEVICE_ID_INTEL_82801AA_8 0x2418
+#define PCI_DEVICE_ID_INTEL_82801AB_0 0x2420
+#define PCI_DEVICE_ID_INTEL_82801AB_1 0x2421
+#define PCI_DEVICE_ID_INTEL_82801AB_3 0x2423
+#define PCI_DEVICE_ID_INTEL_82801AB_5 0x2425
+#define PCI_DEVICE_ID_INTEL_82801AB_6 0x2426
+#define PCI_DEVICE_ID_INTEL_82801AB_8 0x2428
+#define PCI_DEVICE_ID_INTEL_82801BA_0 0x2440
+#define PCI_DEVICE_ID_INTEL_82801BA_2 0x2443
+#define PCI_DEVICE_ID_INTEL_82801BA_4 0x2445
+#define PCI_DEVICE_ID_INTEL_82801BA_6 0x2448
+#define PCI_DEVICE_ID_INTEL_82801BA_8 0x244a
+#define PCI_DEVICE_ID_INTEL_82801BA_9 0x244b
+#define PCI_DEVICE_ID_INTEL_82801BA_10 0x244c
+#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e
+#define PCI_DEVICE_ID_INTEL_82801E_0 0x2450
+#define PCI_DEVICE_ID_INTEL_82801E_11 0x245b
+#define PCI_DEVICE_ID_INTEL_82801CA_0 0x2480
+#define PCI_DEVICE_ID_INTEL_82801CA_3 0x2483
+#define PCI_DEVICE_ID_INTEL_82801CA_5 0x2485
+#define PCI_DEVICE_ID_INTEL_82801CA_6 0x2486
+#define PCI_DEVICE_ID_INTEL_82801CA_10 0x248a
+#define PCI_DEVICE_ID_INTEL_82801CA_11 0x248b
+#define PCI_DEVICE_ID_INTEL_82801CA_12 0x248c
+#define PCI_DEVICE_ID_INTEL_82801DB_0 0x24c0
+#define PCI_DEVICE_ID_INTEL_82801DB_1 0x24c1
+#define PCI_DEVICE_ID_INTEL_82801DB_3 0x24c3
+#define PCI_DEVICE_ID_INTEL_82801DB_5 0x24c5
+#define PCI_DEVICE_ID_INTEL_82801DB_6 0x24c6
+#define PCI_DEVICE_ID_INTEL_82801DB_9 0x24c9
+#define PCI_DEVICE_ID_INTEL_82801DB_10 0x24ca
+#define PCI_DEVICE_ID_INTEL_82801DB_11 0x24cb
+#define PCI_DEVICE_ID_INTEL_82801DB_12 0x24cc
+#define PCI_DEVICE_ID_INTEL_82801EB_0 0x24d0
+#define PCI_DEVICE_ID_INTEL_82801EB_1 0x24d1
+#define PCI_DEVICE_ID_INTEL_82801EB_3 0x24d3
+#define PCI_DEVICE_ID_INTEL_82801EB_5 0x24d5
+#define PCI_DEVICE_ID_INTEL_82801EB_6 0x24d6
+#define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db
+#define PCI_DEVICE_ID_INTEL_82801EB_12 0x24dc
+#define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd
+#define PCI_DEVICE_ID_INTEL_ESB_1 0x25a1
+#define PCI_DEVICE_ID_INTEL_ESB_2 0x25a2
+#define PCI_DEVICE_ID_INTEL_ESB_4 0x25a4
+#define PCI_DEVICE_ID_INTEL_ESB_5 0x25a6
+#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab
+#define PCI_DEVICE_ID_INTEL_82820_HB 0x2500
+#define PCI_DEVICE_ID_INTEL_82820_UP_HB 0x2501
+#define PCI_DEVICE_ID_INTEL_82850_HB 0x2530
+#define PCI_DEVICE_ID_INTEL_82860_HB 0x2531
+#define PCI_DEVICE_ID_INTEL_E7501_MCH 0x254c
+#define PCI_DEVICE_ID_INTEL_82845G_HB 0x2560
+#define PCI_DEVICE_ID_INTEL_82845G_IG 0x2562
+#define PCI_DEVICE_ID_INTEL_82865_HB 0x2570
+#define PCI_DEVICE_ID_INTEL_82865_IG 0x2572
+#define PCI_DEVICE_ID_INTEL_82875_HB 0x2578
+#define PCI_DEVICE_ID_INTEL_82915G_HB 0x2580
+#define PCI_DEVICE_ID_INTEL_82915G_IG 0x2582
+#define PCI_DEVICE_ID_INTEL_82915GM_HB 0x2590
+#define PCI_DEVICE_ID_INTEL_82915GM_IG 0x2592
+#define PCI_DEVICE_ID_INTEL_5000_ERR 0x25F0
+#define PCI_DEVICE_ID_INTEL_5000_FBD0 0x25F5
+#define PCI_DEVICE_ID_INTEL_5000_FBD1 0x25F6
+#define PCI_DEVICE_ID_INTEL_82945G_HB 0x2770
+#define PCI_DEVICE_ID_INTEL_82945G_IG 0x2772
+#define PCI_DEVICE_ID_INTEL_3000_HB 0x2778
+#define PCI_DEVICE_ID_INTEL_82945GM_HB 0x27A0
+#define PCI_DEVICE_ID_INTEL_82945GM_IG 0x27A2
+#define PCI_DEVICE_ID_INTEL_ICH6_0 0x2640
+#define PCI_DEVICE_ID_INTEL_ICH6_1 0x2641
+#define PCI_DEVICE_ID_INTEL_ICH6_2 0x2642
+#define PCI_DEVICE_ID_INTEL_ICH6_16 0x266a
+#define PCI_DEVICE_ID_INTEL_ICH6_17 0x266d
+#define PCI_DEVICE_ID_INTEL_ICH6_18 0x266e
+#define PCI_DEVICE_ID_INTEL_ICH6_19 0x266f
+#define PCI_DEVICE_ID_INTEL_ESB2_0 0x2670
+#define PCI_DEVICE_ID_INTEL_ESB2_14 0x2698
+#define PCI_DEVICE_ID_INTEL_ESB2_17 0x269b
+#define PCI_DEVICE_ID_INTEL_ESB2_18 0x269e
+#define PCI_DEVICE_ID_INTEL_ICH7_0 0x27b8
+#define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b9
+#define PCI_DEVICE_ID_INTEL_ICH7_30 0x27b0
+#define PCI_DEVICE_ID_INTEL_ICH7_31 0x27bd
+#define PCI_DEVICE_ID_INTEL_ICH7_17 0x27da
+#define PCI_DEVICE_ID_INTEL_ICH7_19 0x27dd
+#define PCI_DEVICE_ID_INTEL_ICH7_20 0x27de
+#define PCI_DEVICE_ID_INTEL_ICH7_21 0x27df
+#define PCI_DEVICE_ID_INTEL_ICH8_0 0x2810
+#define PCI_DEVICE_ID_INTEL_ICH8_1 0x2811
+#define PCI_DEVICE_ID_INTEL_ICH8_2 0x2812
+#define PCI_DEVICE_ID_INTEL_ICH8_3 0x2814
+#define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815
+#define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e
+#define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850
+#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910
+#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917
+#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912
+#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913
+#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914
+#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919
+#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930
+#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916
+#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918
+#define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG6 0x342b
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG7 0x342c
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG0 0x3430
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG1 0x3431
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG2 0x3432
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG3 0x3433
+#define PCI_DEVICE_ID_INTEL_82830_HB 0x3575
+#define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577
+#define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580
+#define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582
+#define PCI_DEVICE_ID_INTEL_E7520_MCH 0x3590
+#define PCI_DEVICE_ID_INTEL_E7320_MCH 0x3592
+#define PCI_DEVICE_ID_INTEL_MCH_PA 0x3595
+#define PCI_DEVICE_ID_INTEL_MCH_PA1 0x3596
+#define PCI_DEVICE_ID_INTEL_MCH_PB 0x3597
+#define PCI_DEVICE_ID_INTEL_MCH_PB1 0x3598
+#define PCI_DEVICE_ID_INTEL_MCH_PC 0x3599
+#define PCI_DEVICE_ID_INTEL_MCH_PC1 0x359a
+#define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e
+#define PCI_DEVICE_ID_INTEL_IOAT_CNB 0x360b
+#define PCI_DEVICE_ID_INTEL_FBD_CNB 0x360c
+#define PCI_DEVICE_ID_INTEL_ICH10_0 0x3a14
+#define PCI_DEVICE_ID_INTEL_ICH10_1 0x3a16
+#define PCI_DEVICE_ID_INTEL_ICH10_2 0x3a18
+#define PCI_DEVICE_ID_INTEL_ICH10_3 0x3a1a
+#define PCI_DEVICE_ID_INTEL_ICH10_4 0x3a30
+#define PCI_DEVICE_ID_INTEL_ICH10_5 0x3a60
+#define PCI_DEVICE_ID_INTEL_PCH_LPC_MIN 0x3b00
+#define PCI_DEVICE_ID_INTEL_PCH_LPC_MAX 0x3b1f
+#define PCI_DEVICE_ID_INTEL_PCH_SMBUS 0x3b30
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f
+#define PCI_DEVICE_ID_INTEL_5100_16 0x65f0
+#define PCI_DEVICE_ID_INTEL_5100_21 0x65f5
+#define PCI_DEVICE_ID_INTEL_5100_22 0x65f6
+#define PCI_DEVICE_ID_INTEL_5400_ERR 0x4030
+#define PCI_DEVICE_ID_INTEL_5400_FBD0 0x4035
+#define PCI_DEVICE_ID_INTEL_5400_FBD1 0x4036
+#define PCI_DEVICE_ID_INTEL_IOAT_SCNB 0x65ff
+#define PCI_DEVICE_ID_INTEL_TOLAPAI_0 0x5031
+#define PCI_DEVICE_ID_INTEL_TOLAPAI_1 0x5032
+#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
+#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
+#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020
+#define PCI_DEVICE_ID_INTEL_82437VX 0x7030
+#define PCI_DEVICE_ID_INTEL_82439TX 0x7100
+#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
+#define PCI_DEVICE_ID_INTEL_82810_MC1 0x7120
+#define PCI_DEVICE_ID_INTEL_82810_IG1 0x7121
+#define PCI_DEVICE_ID_INTEL_82810_MC3 0x7122
+#define PCI_DEVICE_ID_INTEL_82810_IG3 0x7123
+#define PCI_DEVICE_ID_INTEL_82810E_MC 0x7124
+#define PCI_DEVICE_ID_INTEL_82810E_IG 0x7125
+#define PCI_DEVICE_ID_INTEL_82443LX_0 0x7180
+#define PCI_DEVICE_ID_INTEL_82443LX_1 0x7181
+#define PCI_DEVICE_ID_INTEL_82443BX_0 0x7190
+#define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191
+#define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192
+#define PCI_DEVICE_ID_INTEL_440MX 0x7195
+#define PCI_DEVICE_ID_INTEL_440MX_6 0x7196
+#define PCI_DEVICE_ID_INTEL_82443MX_0 0x7198
+#define PCI_DEVICE_ID_INTEL_82443MX_1 0x7199
+#define PCI_DEVICE_ID_INTEL_82443MX_3 0x719b
+#define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0
+#define PCI_DEVICE_ID_INTEL_82443GX_2 0x71a2
+#define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601
+#define PCI_DEVICE_ID_INTEL_SCH_LPC 0x8119
+#define PCI_DEVICE_ID_INTEL_SCH_IDE 0x811a
+#define PCI_DEVICE_ID_INTEL_82454GX 0x84c4
+#define PCI_DEVICE_ID_INTEL_82450GX 0x84c5
+#define PCI_DEVICE_ID_INTEL_82451NX 0x84ca
+#define PCI_DEVICE_ID_INTEL_82454NX 0x84cb
+#define PCI_DEVICE_ID_INTEL_84460GX 0x84ea
+#define PCI_DEVICE_ID_INTEL_IXP4XX 0x8500
+#define PCI_DEVICE_ID_INTEL_IXP2800 0x9004
+#define PCI_DEVICE_ID_INTEL_S21152BB 0xb152
+
+#define PCI_VENDOR_ID_SCALEMP 0x8686
+#define PCI_DEVICE_ID_SCALEMP_VSMP_CTL 0x1010
+
+#define PCI_VENDOR_ID_COMPUTONE 0x8e0e
+#define PCI_DEVICE_ID_COMPUTONE_IP2EX 0x0291
+#define PCI_DEVICE_ID_COMPUTONE_PG 0x0302
+#define PCI_SUBVENDOR_ID_COMPUTONE 0x8e0e
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG4 0x0001
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG8 0x0002
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG6 0x0003
+
+#define PCI_VENDOR_ID_KTI 0x8e2e
+
+#define PCI_VENDOR_ID_ADAPTEC 0x9004
+#define PCI_DEVICE_ID_ADAPTEC_7810 0x1078
+#define PCI_DEVICE_ID_ADAPTEC_7821 0x2178
+#define PCI_DEVICE_ID_ADAPTEC_38602 0x3860
+#define PCI_DEVICE_ID_ADAPTEC_7850 0x5078
+#define PCI_DEVICE_ID_ADAPTEC_7855 0x5578
+#define PCI_DEVICE_ID_ADAPTEC_3860 0x6038
+#define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075
+#define PCI_DEVICE_ID_ADAPTEC_7860 0x6078
+#define PCI_DEVICE_ID_ADAPTEC_7861 0x6178
+#define PCI_DEVICE_ID_ADAPTEC_7870 0x7078
+#define PCI_DEVICE_ID_ADAPTEC_7871 0x7178
+#define PCI_DEVICE_ID_ADAPTEC_7872 0x7278
+#define PCI_DEVICE_ID_ADAPTEC_7873 0x7378
+#define PCI_DEVICE_ID_ADAPTEC_7874 0x7478
+#define PCI_DEVICE_ID_ADAPTEC_7895 0x7895
+#define PCI_DEVICE_ID_ADAPTEC_7880 0x8078
+#define PCI_DEVICE_ID_ADAPTEC_7881 0x8178
+#define PCI_DEVICE_ID_ADAPTEC_7882 0x8278
+#define PCI_DEVICE_ID_ADAPTEC_7883 0x8378
+#define PCI_DEVICE_ID_ADAPTEC_7884 0x8478
+#define PCI_DEVICE_ID_ADAPTEC_7885 0x8578
+#define PCI_DEVICE_ID_ADAPTEC_7886 0x8678
+#define PCI_DEVICE_ID_ADAPTEC_7887 0x8778
+#define PCI_DEVICE_ID_ADAPTEC_7888 0x8878
+
+#define PCI_VENDOR_ID_ADAPTEC2 0x9005
+#define PCI_DEVICE_ID_ADAPTEC2_2940U2 0x0010
+#define PCI_DEVICE_ID_ADAPTEC2_2930U2 0x0011
+#define PCI_DEVICE_ID_ADAPTEC2_7890B 0x0013
+#define PCI_DEVICE_ID_ADAPTEC2_7890 0x001f
+#define PCI_DEVICE_ID_ADAPTEC2_3940U2 0x0050
+#define PCI_DEVICE_ID_ADAPTEC2_3950U2D 0x0051
+#define PCI_DEVICE_ID_ADAPTEC2_7896 0x005f
+#define PCI_DEVICE_ID_ADAPTEC2_7892A 0x0080
+#define PCI_DEVICE_ID_ADAPTEC2_7892B 0x0081
+#define PCI_DEVICE_ID_ADAPTEC2_7892D 0x0083
+#define PCI_DEVICE_ID_ADAPTEC2_7892P 0x008f
+#define PCI_DEVICE_ID_ADAPTEC2_7899A 0x00c0
+#define PCI_DEVICE_ID_ADAPTEC2_7899B 0x00c1
+#define PCI_DEVICE_ID_ADAPTEC2_7899D 0x00c3
+#define PCI_DEVICE_ID_ADAPTEC2_7899P 0x00cf
+#define PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN 0x0500
+#define PCI_DEVICE_ID_ADAPTEC2_SCAMP 0x0503
+
+#define PCI_VENDOR_ID_HOLTEK 0x9412
+#define PCI_DEVICE_ID_HOLTEK_6565 0x6565
+
+#define PCI_VENDOR_ID_NETMOS 0x9710
+#define PCI_DEVICE_ID_NETMOS_9705 0x9705
+#define PCI_DEVICE_ID_NETMOS_9715 0x9715
+#define PCI_DEVICE_ID_NETMOS_9735 0x9735
+#define PCI_DEVICE_ID_NETMOS_9745 0x9745
+#define PCI_DEVICE_ID_NETMOS_9755 0x9755
+#define PCI_DEVICE_ID_NETMOS_9805 0x9805
+#define PCI_DEVICE_ID_NETMOS_9815 0x9815
+#define PCI_DEVICE_ID_NETMOS_9835 0x9835
+#define PCI_DEVICE_ID_NETMOS_9845 0x9845
+#define PCI_DEVICE_ID_NETMOS_9855 0x9855
+
+#define PCI_VENDOR_ID_3COM_2 0xa727
+
+#define PCI_VENDOR_ID_DIGIUM 0xd161
+#define PCI_DEVICE_ID_DIGIUM_HFC4S 0xb410
+
+#define PCI_SUBVENDOR_ID_EXSYS 0xd84d
+#define PCI_SUBDEVICE_ID_EXSYS_4014 0x4014
+#define PCI_SUBDEVICE_ID_EXSYS_4055 0x4055
+
+#define PCI_VENDOR_ID_TIGERJET 0xe159
+#define PCI_DEVICE_ID_TIGERJET_300 0x0001
+#define PCI_DEVICE_ID_TIGERJET_100 0x0002
+
+#define PCI_VENDOR_ID_XILINX_RME 0xea60
+#define PCI_DEVICE_ID_RME_DIGI32 0x9896
+#define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897
+#define PCI_DEVICE_ID_RME_DIGI32_8 0x9898
+
+#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
+/* 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/roms/seabios-hppa/src/hw/pci_regs.h b/roms/seabios-hppa/src/hw/pci_regs.h
new file mode 100644
index 000000000..e5effd47e
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/pci_regs.h
@@ -0,0 +1,556 @@
+/*
+ * pci_regs.h
+ *
+ * PCI standard defines
+ * Copyright 1994, Drew Eckhardt
+ * Copyright 1997--1999 Martin Mares <mj@ucw.cz>
+ *
+ * For more information, please consult the following manuals (look at
+ * http://www.pcisig.com/ for how to get them):
+ *
+ * PCI BIOS Specification
+ * PCI Local Bus Specification
+ * PCI to PCI Bridge Specification
+ * PCI System Design Guide
+ *
+ * For hypertransport information, please consult the following manuals
+ * from http://www.hypertransport.org
+ *
+ * The Hypertransport I/O Link Specification
+ */
+
+#ifndef LINUX_PCI_REGS_H
+#define LINUX_PCI_REGS_H
+
+/*
+ * Under PCI, each device has 256 bytes of configuration address space,
+ * of which the first 64 bytes are standardized as follows:
+ */
+#define PCI_VENDOR_ID 0x00 /* 16 bits */
+#define PCI_DEVICE_ID 0x02 /* 16 bits */
+#define PCI_COMMAND 0x04 /* 16 bits */
+#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
+#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
+#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
+#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_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_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */
+#define PCI_REVISION_ID 0x08 /* Revision ID */
+#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
+#define PCI_CLASS_DEVICE 0x0a /* Device class */
+
+#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
+#define PCI_LATENCY_TIMER 0x0d /* 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
+
+#define PCI_BIST 0x0f /* 8 bits */
+#define PCI_BIST_CODE_MASK 0x0f /* Return result */
+#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */
+#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */
+
+/*
+ * Base addresses specify locations in memory or I/O space.
+ * Decoded size can be determined by writing a value of
+ * 0xffffffff to the register, and reading it back. Only
+ * 1 bits are decoded.
+ */
+#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
+#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */
+#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */
+#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_PREFETCH 0x08 /* prefetchable? */
+#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL)
+#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL)
+/* bit 1 is reserved if address_space = 1 */
+
+/* Header type 0 (normal devices) */
+#define PCI_CARDBUS_CIS 0x28
+#define PCI_SUBSYSTEM_VENDOR_ID 0x2c
+#define PCI_SUBSYSTEM_ID 0x2e
+#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */
+#define PCI_ROM_ADDRESS_ENABLE 0x01
+#define PCI_ROM_ADDRESS_MASK (~0x7ffUL)
+
+#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */
+
+/* 0x35-0x3b are reserved */
+#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
+#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
+#define PCI_MIN_GNT 0x3e /* 8 bits */
+#define PCI_MAX_LAT 0x3f /* 8 bits */
+
+/* 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 0x0fUL /* I/O bridging type */
+#define PCI_IO_RANGE_TYPE_16 0x00
+#define PCI_IO_RANGE_TYPE_32 0x01
+#define PCI_IO_RANGE_MASK (~0x0fUL)
+#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 0x0fUL
+#define PCI_MEMORY_RANGE_MASK (~0x0fUL)
+#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */
+#define PCI_PREF_MEMORY_LIMIT 0x26
+#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL
+#define PCI_PREF_RANGE_TYPE_32 0x00
+#define PCI_PREF_RANGE_TYPE_64 0x01
+#define PCI_PREF_RANGE_MASK (~0x0fUL)
+#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_ISA 0x04 /* Enable ISA mode */
+#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 */
+
+/* Header type 2 (CardBus bridges) */
+#define PCI_CB_CAPABILITY_LIST 0x14
+/* 0x15 reserved */
+#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */
+#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */
+#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */
+#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */
+#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */
+#define PCI_CB_MEMORY_BASE_0 0x1c
+#define PCI_CB_MEMORY_LIMIT_0 0x20
+#define PCI_CB_MEMORY_BASE_1 0x24
+#define PCI_CB_MEMORY_LIMIT_1 0x28
+#define PCI_CB_IO_BASE_0 0x2c
+#define PCI_CB_IO_BASE_0_HI 0x2e
+#define PCI_CB_IO_LIMIT_0 0x30
+#define PCI_CB_IO_LIMIT_0_HI 0x32
+#define PCI_CB_IO_BASE_1 0x34
+#define PCI_CB_IO_BASE_1_HI 0x36
+#define PCI_CB_IO_LIMIT_1 0x38
+#define PCI_CB_IO_LIMIT_1_HI 0x3a
+#define PCI_CB_IO_RANGE_MASK (~0x03UL)
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_CB_BRIDGE_CONTROL 0x3e
+#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */
+#define PCI_CB_BRIDGE_CTL_SERR 0x02
+#define PCI_CB_BRIDGE_CTL_ISA 0x04
+#define PCI_CB_BRIDGE_CTL_VGA 0x08
+#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20
+#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */
+#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */
+#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */
+#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
+#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400
+#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40
+#define PCI_CB_SUBSYSTEM_ID 0x42
+#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */
+/* 0x48-0x7f reserved */
+
+/* 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_PCIX 0x07 /* PCI-X */
+#define PCI_CAP_ID_HT 0x08 /* HyperTransport */
+#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */
+#define PCI_CAP_ID_DBG 0x0A /* Debug port */
+#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */
+#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */
+#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */
+#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */
+#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
+#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
+#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 /* Auxilliary 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_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */
+#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_NO_SOFT_RESET 0x0004 /* No reset for D3hot->D0 */
+#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
+
+/* Vital Product Data */
+
+#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */
+#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */
+#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */
+#define PCI_VPD_DATA 4 /* 32-bits of data returned here */
+
+/* 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_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */
+#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 */
+#define PCI_MSI_MASK_BIT 16 /* Mask bits register */
+
+/* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */
+#define PCI_MSIX_FLAGS 2
+#define PCI_MSIX_FLAGS_QSIZE 0x7FF
+#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
+#define PCI_MSIX_FLAGS_MASKALL (1 << 14)
+#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
+#define PCI_MSIX_FLAGS_BITMASK (1 << 0)
+
+/* CompactPCI Hotswap Register */
+
+#define PCI_CHSWP_CSR 2 /* Control and Status Register */
+#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */
+#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */
+#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */
+#define PCI_CHSWP_LOO 0x08 /* LED On / Off */
+#define PCI_CHSWP_PI 0x30 /* Programming Interface */
+#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */
+#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */
+
+/* PCI-X registers */
+
+#define PCI_X_CMD 2 /* Modes & Features */
+#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */
+#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */
+#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */
+#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */
+#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */
+#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */
+#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */
+ /* Max # of outstanding split transactions */
+#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */
+#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */
+#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */
+#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */
+#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */
+#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */
+#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */
+#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */
+#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */
+#define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */
+#define PCI_X_STATUS 4 /* PCI-X capabilities */
+#define PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */
+#define PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */
+#define PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */
+#define PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */
+#define PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded */
+#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split Completion */
+#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity */
+#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read Count */
+#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max Outstanding Split Transactions */
+#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative Read Size */
+#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */
+#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */
+#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */
+
+/* PCI Express capability registers */
+
+#define PCI_EXP_FLAGS 2 /* Capabilities register */
+#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */
+#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */
+#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */
+#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */
+#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */
+#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */
+#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */
+#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */
+#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */
+#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */
+#define PCI_EXP_DEVCAP 4 /* Device capabilities */
+#define PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */
+#define PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */
+#define PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */
+#define PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */
+#define PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */
+#define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */
+#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */
+#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */
+#define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */
+#define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */
+#define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */
+#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */
+#define PCI_EXP_DEVCTL 8 /* Device Control */
+#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */
+#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */
+#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */
+#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */
+#define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */
+#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */
+#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */
+#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */
+#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */
+#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */
+#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */
+#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */
+#define PCI_EXP_DEVSTA 10 /* Device Status */
+#define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */
+#define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */
+#define PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */
+#define PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */
+#define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */
+#define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */
+#define PCI_EXP_LNKCAP 12 /* Link Capabilities */
+#define PCI_EXP_LNKCAP_ASPMS 0xc00 /* ASPM Support */
+#define PCI_EXP_LNKCAP_L0SEL 0x7000 /* L0s Exit Latency */
+#define PCI_EXP_LNKCAP_L1EL 0x38000 /* L1 Exit Latency */
+#define PCI_EXP_LNKCAP_CLKPM 0x40000 /* L1 Clock Power Management */
+#define PCI_EXP_LNKCTL 16 /* Link Control */
+#define PCI_EXP_LNKCTL_RL 0x20 /* Retrain Link */
+#define PCI_EXP_LNKCTL_CCC 0x40 /* Common Clock COnfiguration */
+#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */
+#define PCI_EXP_LNKSTA 18 /* Link Status */
+#define PCI_EXP_LNKSTA_LT 0x800 /* Link Training */
+#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */
+#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */
+#define PCI_EXP_SLTCTL 24 /* Slot Control */
+#define PCI_EXP_SLTSTA 26 /* Slot Status */
+#define PCI_EXP_RTCTL 28 /* Root Control */
+#define PCI_EXP_RTCTL_SECEE 0x01 /* System Error on Correctable Error */
+#define PCI_EXP_RTCTL_SENFEE 0x02 /* System Error on Non-Fatal Error */
+#define PCI_EXP_RTCTL_SEFEE 0x04 /* System Error on Fatal Error */
+#define PCI_EXP_RTCTL_PMEIE 0x08 /* PME Interrupt Enable */
+#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */
+#define PCI_EXP_RTCAP 30 /* Root Capabilities */
+#define PCI_EXP_RTSTA 32 /* Root Status */
+#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */
+#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */
+#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */
+#define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */
+
+/* Extended Capabilities (PCI-X 2.0 and Express) */
+#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff)
+#define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf)
+#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc)
+
+#define PCI_EXT_CAP_ID_ERR 1
+#define PCI_EXT_CAP_ID_VC 2
+#define PCI_EXT_CAP_ID_DSN 3
+#define PCI_EXT_CAP_ID_PWR 4
+#define PCI_EXT_CAP_ID_ARI 14
+
+/* 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 */
+#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */
+#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */
+#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */
+#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */
+#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */
+#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */
+#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */
+#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */
+/* Correctable Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001
+/* Non-fatal Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002
+/* Fatal Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004
+#define PCI_ERR_ROOT_STATUS 48
+#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */
+/* Multi ERR_COR Received */
+#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002
+/* ERR_FATAL/NONFATAL Recevied */
+#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004
+/* Multi ERR_FATAL/NONFATAL Recevied */
+#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008
+#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Fatal */
+#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */
+#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */
+#define PCI_ERR_ROOT_COR_SRC 52
+#define PCI_ERR_ROOT_SRC 54
+
+/* Virtual Channel */
+#define PCI_VC_PORT_REG1 4
+#define PCI_VC_PORT_REG2 8
+#define PCI_VC_PORT_CTRL 12
+#define PCI_VC_PORT_STATUS 14
+#define PCI_VC_RES_CAP 16
+#define PCI_VC_RES_CTRL 20
+#define PCI_VC_RES_STATUS 26
+
+/* Power Budgeting */
+#define PCI_PWR_DSR 4 /* Data Select Register */
+#define PCI_PWR_DATA 8 /* Data Register */
+#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */
+#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */
+#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */
+#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */
+#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */
+#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */
+#define PCI_PWR_CAP 12 /* Capability */
+#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */
+
+/*
+ * Hypertransport sub capability types
+ *
+ * Unfortunately there are both 3 bit and 5 bit capability types defined
+ * in the HT spec, catering for that is a little messy. You probably don't
+ * want to use these directly, just use pci_find_ht_capability() and it
+ * will do the right thing for you.
+ */
+#define HT_3BIT_CAP_MASK 0xE0
+#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */
+#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */
+
+#define HT_5BIT_CAP_MASK 0xF8
+#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */
+#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */
+#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */
+#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */
+#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */
+#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */
+#define HT_MSI_FLAGS 0x02 /* Offset to flags */
+#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */
+#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */
+#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */
+#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr bits */
+#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */
+#define HT_MSI_ADDR_HI 0x08 /* Offset to high addr bits */
+#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */
+#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */
+#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */
+#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */
+#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */
+
+/* Alternative Routing-ID Interpretation */
+#define PCI_ARI_CAP 0x04 /* ARI Capability Register */
+#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */
+#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */
+#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */
+#define PCI_ARI_CTRL 0x06 /* ARI Control Register */
+#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */
+#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */
+#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */
+
+#endif /* LINUX_PCI_REGS_H */
diff --git a/roms/seabios-hppa/src/hw/pcidevice.c b/roms/seabios-hppa/src/hw/pcidevice.c
new file mode 100644
index 000000000..8853cf72f
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/pcidevice.c
@@ -0,0 +1,192 @@
+// Code to maintain and access the pci_device cache
+//
+// Copyright (C) 2008-2016 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "malloc.h" // malloc_tmp
+#include "output.h" // dprintf
+#include "pci.h" // pci_config_writel
+#include "pcidevice.h" // pci_probe_devices
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "romfile.h" // romfile_loadint
+#include "stacks.h" // wait_preempt
+#include "string.h" // memset
+
+struct hlist_head PCIDevices VARVERIFY32INIT;
+int MaxPCIBus VARFSEG;
+
+// Find all PCI devices and populate PCIDevices linked list.
+void
+pci_probe_devices(void)
+{
+ dprintf(3, "PCI probe\n");
+ struct pci_device *busdevs[256];
+ memset(busdevs, 0, sizeof(busdevs));
+ struct hlist_node **pprev = &PCIDevices.first;
+ int extraroots = romfile_loadint("etc/extra-pci-roots", 0);
+ int bus = -1, lastbus = 0, rootbuses = 0, count=0;
+ while (bus < 0xff && (bus < MaxPCIBus || rootbuses < extraroots)) {
+ bus++;
+ int bdf;
+ foreachbdf(bdf, bus) {
+ // Create new pci_device struct and add to list.
+ struct pci_device *dev = malloc_tmp(sizeof(*dev));
+ if (!dev) {
+ warn_noalloc();
+ return;
+ }
+ memset(dev, 0, sizeof(*dev));
+ hlist_add(&dev->node, pprev);
+ pprev = &dev->node.next;
+ count++;
+
+ // Find parent device.
+ int rootbus;
+ struct pci_device *parent = busdevs[bus];
+ if (!parent) {
+ if (bus != lastbus)
+ rootbuses++;
+ lastbus = bus;
+ rootbus = rootbuses;
+ if (bus > MaxPCIBus)
+ MaxPCIBus = bus;
+ } else {
+ rootbus = parent->rootbus;
+ }
+
+ // Populate pci_device info.
+ dev->bdf = bdf;
+ dev->parent = parent;
+ dev->rootbus = rootbus;
+ u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
+ dev->vendor = vendev & 0xffff;
+ dev->device = vendev >> 16;
+ u32 classrev = pci_config_readl(bdf, PCI_CLASS_REVISION);
+ dev->class = classrev >> 16;
+ dev->prog_if = classrev >> 8;
+ dev->revision = classrev & 0xff;
+ dev->header_type = pci_config_readb(bdf, PCI_HEADER_TYPE);
+ u8 v = dev->header_type & 0x7f;
+ if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
+ u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
+ dev->secondary_bus = secbus;
+ if (secbus > bus && !busdevs[secbus])
+ busdevs[secbus] = dev;
+ if (secbus > MaxPCIBus)
+ MaxPCIBus = secbus;
+ }
+ dprintf(4, "PCI device %pP (vd=%04x:%04x c=%04x)\n"
+ , dev, dev->vendor, dev->device, dev->class);
+ }
+ }
+ dprintf(1, "Found %d PCI devices (max PCI bus is %02x)\n", count, MaxPCIBus);
+}
+
+// Search for a device with the specified vendor and device ids.
+struct pci_device *
+pci_find_device(u16 vendid, u16 devid)
+{
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->vendor == vendid && pci->device == devid)
+ return pci;
+ }
+ return NULL;
+}
+
+// Search for a device with the specified class id.
+struct pci_device *
+pci_find_class(u16 classid)
+{
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->class == classid)
+ return pci;
+ }
+ return NULL;
+}
+
+int pci_init_device(const struct pci_device_id *ids
+ , struct pci_device *pci, void *arg)
+{
+ while (ids->vendid || ids->class_mask) {
+ if ((ids->vendid == PCI_ANY_ID || ids->vendid == pci->vendor) &&
+ (ids->devid == PCI_ANY_ID || ids->devid == pci->device) &&
+ !((ids->class ^ pci->class) & ids->class_mask)) {
+ if (ids->func)
+ ids->func(pci, arg);
+ return 0;
+ }
+ ids++;
+ }
+ return -1;
+}
+
+struct pci_device *
+pci_find_init_device(const struct pci_device_id *ids, void *arg)
+{
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci_init_device(ids, pci, arg) == 0)
+ return pci;
+ }
+ return NULL;
+}
+
+// Enable PCI bus-mastering (ie, DMA) support on a pci device
+void
+pci_enable_busmaster(struct pci_device *pci)
+{
+ wait_preempt();
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+ pci->have_driver = 1;
+}
+
+// Verify an IO bar and return it to the caller
+u16
+pci_enable_iobar(struct pci_device *pci, u32 addr)
+{
+ wait_preempt();
+ u32 bar = pci_config_readl(pci->bdf, addr);
+ if (!(bar & PCI_BASE_ADDRESS_SPACE_IO)) {
+ warn_internalerror();
+ return 0;
+ }
+ bar &= PCI_BASE_ADDRESS_IO_MASK;
+ if (bar == 0 || bar > 0xffff) {
+ warn_internalerror();
+ return 0;
+ }
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_IO);
+ pci->have_driver = 1;
+ return bar;
+}
+
+// Verify a memory bar and return it to the caller
+void *
+pci_enable_membar(struct pci_device *pci, u32 addr)
+{
+ wait_preempt();
+ u32 bar = pci_config_readl(pci->bdf, addr);
+ if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
+ warn_internalerror();
+ return NULL;
+ }
+ if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ u32 high = pci_config_readl(pci->bdf, addr+4);
+ if (high) {
+ dprintf(1, "Can not map memory bar over 4Gig\n");
+ return NULL;
+ }
+ }
+ bar &= PCI_BASE_ADDRESS_MEM_MASK;
+ if (bar + 4*1024*1024 < 20*1024*1024) {
+ // Bar doesn't look valid (it is in last 4M or first 16M)
+ warn_internalerror();
+ return NULL;
+ }
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
+ pci->have_driver = 1;
+ return (void*)bar;
+}
diff --git a/roms/seabios-hppa/src/hw/pcidevice.h b/roms/seabios-hppa/src/hw/pcidevice.h
new file mode 100644
index 000000000..225d54510
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/pcidevice.h
@@ -0,0 +1,76 @@
+#ifndef __PCIDEVICE_H
+#define __PCIDEVICE_H
+
+#include "types.h" // u32
+#include "list.h" // hlist_node
+
+struct pci_device {
+ u16 bdf;
+ u8 rootbus;
+ struct hlist_node node;
+ struct pci_device *parent;
+
+ // Configuration space device information
+ u16 vendor, device;
+ u16 class;
+ u8 prog_if, revision;
+ u8 header_type;
+ u8 secondary_bus;
+
+ // Local information on device.
+ int have_driver;
+};
+extern struct hlist_head PCIDevices;
+extern int MaxPCIBus;
+
+static inline u32 pci_classprog(struct pci_device *pci) {
+ return (pci->class << 8) | pci->prog_if;
+}
+
+#define foreachpci(PCI) \
+ hlist_for_each_entry(PCI, &PCIDevices, node)
+
+#define PCI_ANY_ID (~0)
+struct pci_device_id {
+ u32 vendid;
+ u32 devid;
+ u32 class;
+ u32 class_mask;
+ void (*func)(struct pci_device *pci, void *arg);
+};
+
+#define PCI_DEVICE(vendor_id, device_id, init_func) \
+ { \
+ .vendid = (vendor_id), \
+ .devid = (device_id), \
+ .class = PCI_ANY_ID, \
+ .class_mask = 0, \
+ .func = (init_func) \
+ }
+
+#define PCI_DEVICE_CLASS(vendor_id, device_id, class_code, init_func) \
+ { \
+ .vendid = (vendor_id), \
+ .devid = (device_id), \
+ .class = (class_code), \
+ .class_mask = ~0, \
+ .func = (init_func) \
+ }
+
+#define PCI_DEVICE_END \
+ { \
+ .vendid = 0, \
+ }
+
+void pci_probe_devices(void);
+struct pci_device *pci_find_device(u16 vendid, u16 devid);
+struct pci_device *pci_find_class(u16 classid);
+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);
+void pci_enable_busmaster(struct pci_device *pci);
+u16 pci_enable_iobar(struct pci_device *pci, u32 addr);
+void *pci_enable_membar(struct pci_device *pci, u32 addr);
+
+#endif // pcidevice.h
diff --git a/roms/seabios-hppa/src/hw/pic.c b/roms/seabios-hppa/src/hw/pic.c
new file mode 100644
index 000000000..a13564aeb
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/pic.c
@@ -0,0 +1,115 @@
+// Helpers for working with i8259 interrupt controller.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // SET_IVT
+#include "config.h" // CONFIG_*
+#include "output.h" // dprintf
+#include "pic.h" // pic_*
+
+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);
+}
+
+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);
+}
+
+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);
+ // Send ICW2 (base irqs: 0x08-0x0f for irq0-7, 0x70-0x77 for irq8-15)
+ outb(irq0, PORT_PIC1_DATA);
+ outb(irq8, PORT_PIC2_DATA);
+ // Send ICW3 (cascaded pic ids)
+ outb(0x04, PORT_PIC1_DATA);
+ outb(0x02, PORT_PIC2_DATA);
+ // Send ICW4 (enable 8086 mode)
+ outb(0x01, PORT_PIC1_DATA);
+ outb(0x01, PORT_PIC2_DATA);
+ // Mask all irqs (except cascaded PIC2 irq)
+ pic_irqmask_write(PIC_IRQMASK_DEFAULT);
+}
+
+void
+pic_setup(void)
+{
+ dprintf(3, "init pic\n");
+ pic_reset(BIOS_HWIRQ0_VECTOR, BIOS_HWIRQ8_VECTOR);
+}
+
+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)
+ vector = BIOS_HWIRQ0_VECTOR + hwirq;
+ else
+ vector = BIOS_HWIRQ8_VECTOR + hwirq - 8;
+ SET_IVT(vector, 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);
+}
+
+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);
+}
+
+// Handler for otherwise unused hardware irqs.
+void VISIBLE16
+handle_hwpic1(void)
+{
+ dprintf(DEBUG_ISR_hwpic1, "handle_hwpic1 irq=%x\n", pic_isr1_read());
+ pic_eoi1();
+}
+
+void VISIBLE16
+handle_hwpic2(void)
+{
+ dprintf(DEBUG_ISR_hwpic2, "handle_hwpic2 irq=%x\n", pic_isr2_read());
+ pic_eoi2();
+}
diff --git a/roms/seabios-hppa/src/hw/pic.h b/roms/seabios-hppa/src/hw/pic.h
new file mode 100644
index 000000000..f2d9f6130
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/pic.h
@@ -0,0 +1,60 @@
+// Helpers for working with i8259 interrupt controller.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __PIC_H
+#define __PIC_H
+
+#include "x86.h" // outb
+
+#define PORT_PIC1_CMD 0x0020
+#define PORT_PIC1_DATA 0x0021
+#define PORT_PIC2_CMD 0x00a0
+#define PORT_PIC2_DATA 0x00a1
+
+// PORT_PIC1 bitdefs
+#define PIC1_IRQ0 (1<<0)
+#define PIC1_IRQ1 (1<<1)
+#define PIC1_IRQ2 (1<<2)
+#define PIC1_IRQ5 (1<<5)
+#define PIC1_IRQ6 (1<<6)
+// PORT_PIC2 bitdefs
+#define PIC2_IRQ8 (1<<8)
+#define PIC2_IRQ12 (1<<12)
+#define PIC2_IRQ13 (1<<13)
+#define PIC2_IRQ14 (1<<14)
+
+#define PIC_IRQMASK_DEFAULT ((u16)~PIC1_IRQ2)
+
+#define BIOS_HWIRQ0_VECTOR 0x08
+#define BIOS_HWIRQ8_VECTOR 0x70
+
+static inline void
+pic_eoi1(void)
+{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
+ // Send eoi (select OCW2 + eoi)
+ outb(0x20, PORT_PIC1_CMD);
+}
+
+static inline void
+pic_eoi2(void)
+{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
+ // Send eoi (select OCW2 + eoi)
+ outb(0x20, PORT_PIC2_CMD);
+ pic_eoi1();
+}
+
+u16 pic_irqmask_read(void);
+void pic_irqmask_write(u16 mask);
+void pic_irqmask_mask(u16 off, u16 on);
+void pic_reset(u8 irq0, u8 irq8);
+void pic_setup(void);
+void enable_hwirq(int hwirq, struct segoff_s func);
+
+#endif // pic.h
diff --git a/roms/seabios-hppa/src/hw/ps2port.c b/roms/seabios-hppa/src/hw/ps2port.c
new file mode 100644
index 000000000..9b099e827
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/ps2port.c
@@ -0,0 +1,547 @@
+// Support for handling the PS/2 mouse/keyboard ports.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Several ideas taken from code Copyright (c) 1999-2004 Vojtech Pavlik
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_LOW
+#include "output.h" // dprintf
+#include "pic.h" // pic_eoi1
+#include "ps2port.h" // ps2_kbd_command
+#include "romfile.h" // romfile_loadint
+#include "stacks.h" // yield
+#include "util.h" // udelay
+#include "x86.h" // inb
+
+
+/****************************************************************
+ * Low level i8042 commands.
+ ****************************************************************/
+
+// Timeout value.
+#define I8042_CTL_TIMEOUT 10000
+
+#define I8042_BUFFER_SIZE 16
+
+static int
+i8042_wait_read(void)
+{
+ dprintf(7, "i8042_wait_read\n");
+ int i;
+ for (i=0; i<I8042_CTL_TIMEOUT; i++) {
+ u8 status = inb(PORT_PS2_STATUS);
+ if (status & I8042_STR_OBF)
+ return 0;
+ udelay(50);
+ }
+ warn_timeout();
+ return -1;
+}
+
+static int
+i8042_wait_write(void)
+{
+ dprintf(7, "i8042_wait_write\n");
+ int i;
+ for (i=0; i<I8042_CTL_TIMEOUT; i++) {
+ u8 status = inb(PORT_PS2_STATUS);
+ if (! (status & I8042_STR_IBF))
+ return 0;
+ udelay(50);
+ }
+ warn_timeout();
+ return -1;
+}
+
+static int
+i8042_flush(void)
+{
+ dprintf(7, "i8042_flush\n");
+ int i;
+ for (i=0; i<I8042_BUFFER_SIZE; i++) {
+ u8 status = inb(PORT_PS2_STATUS);
+ if (! (status & I8042_STR_OBF))
+ return 0;
+ udelay(50);
+ u8 data = inb(PORT_PS2_DATA);
+ dprintf(7, "i8042 flushed %x (status=%x)\n", data, status);
+ }
+
+ warn_timeout();
+ return -1;
+}
+
+static int
+__i8042_command(int command, u8 *param)
+{
+ int receive = (command >> 8) & 0xf;
+ int send = (command >> 12) & 0xf;
+
+ // Send the command.
+ int ret = i8042_wait_write();
+ if (ret)
+ return ret;
+ outb(command, PORT_PS2_STATUS);
+
+ // Send parameters (if any).
+ int i;
+ for (i = 0; i < send; i++) {
+ ret = i8042_wait_write();
+ if (ret)
+ return ret;
+ outb(param[i], PORT_PS2_DATA);
+ }
+
+ // Receive parameters (if any).
+ for (i = 0; i < receive; i++) {
+ ret = i8042_wait_read();
+ if (ret)
+ return ret;
+ param[i] = inb(PORT_PS2_DATA);
+ dprintf(7, "i8042 param=%x\n", param[i]);
+ }
+
+ return 0;
+}
+
+static int
+i8042_command(int command, u8 *param)
+{
+ dprintf(7, "i8042_command cmd=%x\n", command);
+ int ret = __i8042_command(command, param);
+ if (ret)
+ dprintf(2, "i8042 command %x failed\n", command);
+ return ret;
+}
+
+static int
+i8042_kbd_write(u8 c)
+{
+ dprintf(7, "i8042_kbd_write c=%d\n", c);
+ int ret = i8042_wait_write();
+ if (! ret)
+ outb(c, PORT_PS2_DATA);
+ return ret;
+}
+
+static int
+i8042_aux_write(u8 c)
+{
+ return i8042_command(I8042_CMD_AUX_SEND, &c);
+}
+
+void
+i8042_reboot(void)
+{
+ if (! CONFIG_PS2PORT)
+ return;
+ int i;
+ for (i=0; i<10; i++) {
+ i8042_wait_write();
+ udelay(50);
+ outb(0xfe, PORT_PS2_STATUS); /* pulse reset low */
+ udelay(50);
+ }
+}
+
+
+/****************************************************************
+ * Device commands.
+ ****************************************************************/
+
+#define PS2_RET_ACK 0xfa
+#define PS2_RET_NAK 0xfe
+
+static int
+ps2_recvbyte(int aux, int needack, int timeout)
+{
+ u32 end = timer_calc(timeout);
+ for (;;) {
+ u8 status = inb(PORT_PS2_STATUS);
+ if (status & I8042_STR_OBF) {
+ u8 data = inb(PORT_PS2_DATA);
+ dprintf(7, "ps2 read %x\n", data);
+
+ if (!!(status & I8042_STR_AUXDATA) == aux) {
+ if (!needack)
+ return data;
+ if (data == PS2_RET_ACK)
+ return data;
+ if (data == PS2_RET_NAK) {
+ dprintf(1, "Got ps2 nak (status=%x)\n", status);
+ return data;
+ }
+ }
+
+ // This data not part of command - just discard it.
+ dprintf(1, "Discarding ps2 data %02x (status=%02x)\n", data, status);
+ }
+
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+}
+
+static int
+ps2_sendbyte(int aux, u8 command, int timeout)
+{
+ dprintf(7, "ps2_sendbyte aux=%d cmd=%x\n", aux, command);
+ int ret;
+ if (aux)
+ ret = i8042_aux_write(command);
+ else
+ ret = i8042_kbd_write(command);
+ if (ret)
+ return ret;
+
+ // Read ack.
+ ret = ps2_recvbyte(aux, 1, timeout);
+ if (ret < 0)
+ return ret;
+ if (ret != PS2_RET_ACK)
+ return -1;
+
+ return 0;
+}
+
+u8 Ps2ctr VARLOW = I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
+
+static int
+__ps2_command(int aux, int command, u8 *param)
+{
+ int ret2;
+ int receive = (command >> 8) & 0xf;
+ int send = (command >> 12) & 0xf;
+
+ // Disable interrupts and keyboard/mouse.
+ u8 ps2ctr = GET_LOW(Ps2ctr);
+ u8 newctr = ((ps2ctr | I8042_CTR_AUXDIS | I8042_CTR_KBDDIS)
+ & ~(I8042_CTR_KBDINT|I8042_CTR_AUXINT));
+ dprintf(6, "i8042 ctr old=%x new=%x\n", ps2ctr, newctr);
+ int ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr);
+ if (ret)
+ return ret;
+
+ // Flush any interrupts already pending.
+ yield();
+
+ // Enable port command is being sent to.
+ SET_LOW(Ps2ctr, newctr);
+ if (aux)
+ newctr &= ~I8042_CTR_AUXDIS;
+ else
+ newctr &= ~I8042_CTR_KBDDIS;
+ ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr);
+ if (ret)
+ goto fail;
+
+ if ((u8)command == (u8)ATKBD_CMD_RESET_BAT) {
+ // Reset is special wrt timeouts.
+
+ // Send command.
+ ret = ps2_sendbyte(aux, command, 1000);
+ if (ret)
+ goto fail;
+
+ // Receive parameters.
+ ret = ps2_recvbyte(aux, 0, 4000);
+ if (ret < 0)
+ goto fail;
+ param[0] = 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.
+
+ // Send command.
+ ret = ps2_sendbyte(aux, command, 200);
+ if (ret)
+ goto fail;
+
+ // Receive parameters.
+ ret = ps2_recvbyte(aux, 0, 500);
+ if (ret < 0)
+ goto fail;
+ param[0] = ret;
+ if (ret == 0xab || ret == 0xac || ret == 0x2b || ret == 0x5d
+ || ret == 0x60 || ret == 0x47) {
+ // These ids (keyboards) return two bytes.
+ ret = ps2_recvbyte(aux, 0, 500);
+ if (ret < 0)
+ goto fail;
+ param[1] = ret;
+ } else {
+ param[1] = 0;
+ }
+ } else {
+ // Send command.
+ ret = ps2_sendbyte(aux, command, 200);
+ if (ret)
+ goto fail;
+
+ // Send parameters (if any).
+ int i;
+ for (i = 0; i < send; i++) {
+ ret = ps2_sendbyte(aux, param[i], 200);
+ if (ret)
+ goto fail;
+ }
+
+ // Receive parameters (if any).
+ for (i = 0; i < receive; i++) {
+ ret = ps2_recvbyte(aux, 0, 500);
+ if (ret < 0)
+ goto fail;
+ param[i] = ret;
+ }
+ }
+
+ ret = 0;
+
+fail:
+ // Restore interrupts and keyboard/mouse.
+ SET_LOW(Ps2ctr, ps2ctr);
+ ret2 = i8042_command(I8042_CMD_CTL_WCTR, &ps2ctr);
+ if (ret2)
+ return ret2;
+
+ return ret;
+}
+
+static int
+ps2_command(int aux, int command, u8 *param)
+{
+ dprintf(7, "ps2_command aux=%d cmd=%x\n", aux, command);
+ int ret = __ps2_command(aux, command, param);
+ if (ret)
+ dprintf(2, "ps2 command %x failed (aux=%d)\n", command, aux);
+ return ret;
+}
+
+int
+ps2_kbd_command(int command, u8 *param)
+{
+ if (! CONFIG_PS2PORT)
+ return -1;
+ return ps2_command(0, command, param);
+}
+
+int
+ps2_mouse_command(int command, u8 *param)
+{
+ if (! CONFIG_PS2PORT)
+ return -1;
+
+ // Update ps2ctr for mouse enable/disable.
+ if (command == PSMOUSE_CMD_ENABLE || command == PSMOUSE_CMD_DISABLE) {
+ u8 ps2ctr = GET_LOW(Ps2ctr);
+ if (command == PSMOUSE_CMD_ENABLE)
+ 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);
+ }
+
+ return ps2_command(1, command, param);
+}
+
+
+/****************************************************************
+ * IRQ handlers
+ ****************************************************************/
+
+// INT74h : PS/2 mouse hardware interrupt
+void VISIBLE16
+handle_74(void)
+{
+ if (! CONFIG_PS2PORT)
+ return;
+
+ debug_isr(DEBUG_ISR_74);
+
+ u8 v = inb(PORT_PS2_STATUS);
+ if ((v & (I8042_STR_OBF|I8042_STR_AUXDATA))
+ != (I8042_STR_OBF|I8042_STR_AUXDATA)) {
+ dprintf(1, "ps2 mouse irq but no mouse data.\n");
+ goto done;
+ }
+ v = inb(PORT_PS2_DATA);
+
+ if (!(GET_LOW(Ps2ctr) & I8042_CTR_AUXINT))
+ // Interrupts not enabled.
+ goto done;
+
+ process_mouse(v);
+
+done:
+ pic_eoi2();
+}
+
+// INT09h : Keyboard Hardware Service Entry Point
+void VISIBLE16
+handle_09(void)
+{
+ if (! CONFIG_PS2PORT)
+ return;
+
+ debug_isr(DEBUG_ISR_09);
+
+ // read key from keyboard controller
+ u8 v = inb(PORT_PS2_STATUS);
+ if (v & I8042_STR_AUXDATA) {
+ dprintf(1, "ps2 keyboard irq but found mouse data?!\n");
+ goto done;
+ }
+ v = inb(PORT_PS2_DATA);
+
+ if (!(GET_LOW(Ps2ctr) & I8042_CTR_KBDINT))
+ // Interrupts not enabled.
+ goto done;
+
+ process_key(v);
+
+ // Some old programs expect ISR to turn keyboard back on.
+ i8042_command(I8042_CMD_KBD_ENABLE, NULL);
+
+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
+ ****************************************************************/
+
+static void
+ps2_keyboard_setup(void *data)
+{
+ // flush incoming keys (also verifies port is likely present)
+ int ret = i8042_flush();
+ if (ret)
+ return;
+
+ // Disable keyboard / mouse and drain any input they may have sent
+ ret = i8042_command(I8042_CMD_KBD_DISABLE, NULL);
+ if (ret)
+ return;
+ ret = i8042_command(I8042_CMD_AUX_DISABLE, NULL);
+ if (ret)
+ return;
+ ret = i8042_flush();
+ if (ret)
+ return;
+
+ // Controller self-test.
+ u8 param[2];
+ ret = i8042_command(I8042_CMD_CTL_TEST, param);
+ if (ret)
+ return;
+ if (param[0] != 0x55) {
+ dprintf(1, "i8042 self test failed (got %x not 0x55)\n", param[0]);
+ return;
+ }
+
+ // Controller keyboard test.
+ ret = i8042_command(I8042_CMD_KBD_TEST, param);
+ if (ret)
+ return;
+ if (param[0] != 0x00) {
+ dprintf(1, "i8042 keyboard test failed (got %x not 0x00)\n", param[0]);
+ return;
+ }
+
+
+ /* ------------------- keyboard side ------------------------*/
+ /* reset keyboard and self test (keyboard side) */
+ int spinupdelay = romfile_loadint("etc/ps2-keyboard-spinup", 0);
+ u32 end = timer_calc(spinupdelay);
+ for (;;) {
+ ret = ps2_kbd_command(ATKBD_CMD_RESET_BAT, param);
+ if (!ret)
+ break;
+ if (timer_check(end)) {
+ if (spinupdelay)
+ warn_timeout();
+ return;
+ }
+ yield();
+ }
+ if (param[0] != 0xaa) {
+ dprintf(1, "keyboard self test failed (got %x not 0xaa)\n", param[0]);
+ return;
+ }
+
+ /* Disable keyboard */
+ ret = ps2_kbd_command(ATKBD_CMD_RESET_DIS, NULL);
+ if (ret)
+ return;
+
+ // Set scancode command (mode 2)
+ param[0] = 0x02;
+ ret = ps2_kbd_command(ATKBD_CMD_SSCANSET, param);
+ if (ret)
+ return;
+
+ // Keyboard Mode: disable mouse, scan code convert, enable kbd IRQ
+ Ps2ctr = (I8042_CTR_AUXDIS | I8042_CTR_XLATE
+ | (CONFIG_HARDWARE_IRQ ? I8042_CTR_KBDINT : 0));
+
+ /* Enable keyboard */
+ ret = ps2_kbd_command(ATKBD_CMD_ENABLE, NULL);
+ if (ret)
+ return;
+
+ dprintf(1, "PS2 keyboard initialized\n");
+}
+
+void
+ps2port_setup(void)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_PS2PORT)
+ return;
+ if (acpi_dsdt_present_eisaid(0x0303) == 0) {
+ dprintf(1, "ACPI: no PS/2 keyboard present\n");
+ return;
+ }
+ dprintf(3, "init ps2port\n");
+
+ enable_hwirq(1, FUNC16(entry_09));
+ enable_hwirq(12, FUNC16(entry_74));
+
+ run_thread(ps2_keyboard_setup, NULL);
+}
diff --git a/roms/seabios-hppa/src/hw/ps2port.h b/roms/seabios-hppa/src/hw/ps2port.h
new file mode 100644
index 000000000..1338406ac
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/ps2port.h
@@ -0,0 +1,67 @@
+// Basic ps2 port (keyboard/mouse) command handling.
+#ifndef __PS2PORT_H
+#define __PS2PORT_H
+
+#include "types.h" // u8
+
+#define PORT_PS2_DATA 0x0060
+#define PORT_PS2_STATUS 0x0064
+
+// Standard commands.
+#define I8042_CMD_CTL_RCTR 0x0120
+#define I8042_CMD_CTL_WCTR 0x1060
+#define I8042_CMD_CTL_TEST 0x01aa
+
+#define I8042_CMD_KBD_TEST 0x01ab
+#define I8042_CMD_KBD_DISABLE 0x00ad
+#define I8042_CMD_KBD_ENABLE 0x00ae
+
+#define I8042_CMD_AUX_DISABLE 0x00a7
+#define I8042_CMD_AUX_ENABLE 0x00a8
+#define I8042_CMD_AUX_SEND 0x10d4
+
+// Keyboard commands
+#define ATKBD_CMD_SETLEDS 0x10ed
+#define ATKBD_CMD_SSCANSET 0x10f0
+#define ATKBD_CMD_GETID 0x02f2
+#define ATKBD_CMD_ENABLE 0x00f4
+#define ATKBD_CMD_RESET_DIS 0x00f5
+#define ATKBD_CMD_RESET_BAT 0x01ff
+
+// Mouse commands
+#define PSMOUSE_CMD_SETSCALE11 0x00e6
+#define PSMOUSE_CMD_SETSCALE21 0x00e7
+#define PSMOUSE_CMD_SETRES 0x10e8
+#define PSMOUSE_CMD_GETINFO 0x03e9
+#define PSMOUSE_CMD_GETID 0x02f2
+#define PSMOUSE_CMD_SETRATE 0x10f3
+#define PSMOUSE_CMD_ENABLE 0x00f4
+#define PSMOUSE_CMD_DISABLE 0x00f5
+#define PSMOUSE_CMD_RESET_BAT 0x02ff
+
+// Status register bits.
+#define I8042_STR_PARITY 0x80
+#define I8042_STR_TIMEOUT 0x40
+#define I8042_STR_AUXDATA 0x20
+#define I8042_STR_KEYLOCK 0x10
+#define I8042_STR_CMDDAT 0x08
+#define I8042_STR_MUXERR 0x04
+#define I8042_STR_IBF 0x02
+#define I8042_STR_OBF 0x01
+
+// Control register bits.
+#define I8042_CTR_KBDINT 0x01
+#define I8042_CTR_AUXINT 0x02
+#define I8042_CTR_IGNKEYLOCK 0x08
+#define I8042_CTR_KBDDIS 0x10
+#define I8042_CTR_AUXDIS 0x20
+#define I8042_CTR_XLATE 0x40
+
+// ps2port.c
+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/roms/seabios-hppa/src/hw/pvscsi.c b/roms/seabios-hppa/src/hw/pvscsi.c
new file mode 100644
index 000000000..f2e6fa922
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/pvscsi.c
@@ -0,0 +1,334 @@
+// QEMU VMWARE Paravirtualized SCSI boot support.
+//
+// Copyright (c) 2013 Ravello Systems LTD (http://ravellosystems.com)
+//
+// Authors:
+// Evgeny Budilovsky <evgeny.budilovsky@ravellosystems.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "block.h" // struct drive_s
+#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 "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_DEVICE_ID_VMWARE_PVSCSI
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "pvscsi.h" // pvscsi_setup
+#include "stacks.h" // run_thread
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // usleep
+#include "x86.h" // writel
+
+#define MASK(n) ((1 << (n)) - 1)
+
+#define SIMPLE_QUEUE_TAG 0x20
+
+#define PVSCSI_INTR_CMPL_0 (1 << 0)
+#define PVSCSI_INTR_CMPL_1 (1 << 1)
+#define PVSCSI_INTR_CMPL_MASK MASK(2)
+
+#define PVSCSI_INTR_MSG_0 (1 << 2)
+#define PVSCSI_INTR_MSG_1 (1 << 3)
+#define PVSCSI_INTR_MSG_MASK (MASK(2) << 2)
+#define PVSCSI_INTR_ALL_SUPPORTED MASK(4)
+
+#define PVSCSI_FLAG_CMD_WITH_SG_LIST (1 << 0)
+#define PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB (1 << 1)
+#define PVSCSI_FLAG_CMD_DIR_NONE (1 << 2)
+#define PVSCSI_FLAG_CMD_DIR_TOHOST (1 << 3)
+#define PVSCSI_FLAG_CMD_DIR_TODEVICE (1 << 4)
+
+enum PVSCSIRegOffset {
+ PVSCSI_REG_OFFSET_COMMAND = 0x0,
+ PVSCSI_REG_OFFSET_COMMAND_DATA = 0x4,
+ PVSCSI_REG_OFFSET_COMMAND_STATUS = 0x8,
+ PVSCSI_REG_OFFSET_LAST_STS_0 = 0x100,
+ PVSCSI_REG_OFFSET_LAST_STS_1 = 0x104,
+ PVSCSI_REG_OFFSET_LAST_STS_2 = 0x108,
+ PVSCSI_REG_OFFSET_LAST_STS_3 = 0x10c,
+ PVSCSI_REG_OFFSET_INTR_STATUS = 0x100c,
+ PVSCSI_REG_OFFSET_INTR_MASK = 0x2010,
+ PVSCSI_REG_OFFSET_KICK_NON_RW_IO = 0x3014,
+ PVSCSI_REG_OFFSET_DEBUG = 0x3018,
+ PVSCSI_REG_OFFSET_KICK_RW_IO = 0x4018,
+};
+
+enum PVSCSICommands {
+ PVSCSI_CMD_FIRST = 0,
+ PVSCSI_CMD_ADAPTER_RESET = 1,
+ PVSCSI_CMD_ISSUE_SCSI = 2,
+ PVSCSI_CMD_SETUP_RINGS = 3,
+ PVSCSI_CMD_RESET_BUS = 4,
+ PVSCSI_CMD_RESET_DEVICE = 5,
+ PVSCSI_CMD_ABORT_CMD = 6,
+ PVSCSI_CMD_CONFIG = 7,
+ PVSCSI_CMD_SETUP_MSG_RING = 8,
+ PVSCSI_CMD_DEVICE_UNPLUG = 9,
+ PVSCSI_CMD_LAST = 10
+};
+
+#define PVSCSI_SETUP_RINGS_MAX_NUM_PAGES 32
+struct PVSCSICmdDescSetupRings {
+ u32 reqRingNumPages;
+ u32 cmpRingNumPages;
+ u64 ringsStatePPN;
+ u64 reqRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
+ u64 cmpRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
+} PACKED;
+
+struct PVSCSIRingCmpDesc {
+ u64 context;
+ u64 dataLen;
+ u32 senseLen;
+ u16 hostStatus;
+ u16 scsiStatus;
+ u32 pad[2];
+} PACKED;
+
+struct PVSCSIRingsState {
+ u32 reqProdIdx;
+ u32 reqConsIdx;
+ u32 reqNumEntriesLog2;
+
+ u32 cmpProdIdx;
+ u32 cmpConsIdx;
+ u32 cmpNumEntriesLog2;
+
+ u8 pad[104];
+
+ u32 msgProdIdx;
+ u32 msgConsIdx;
+ u32 msgNumEntriesLog2;
+} PACKED;
+
+struct PVSCSIRingReqDesc {
+ u64 context;
+ u64 dataAddr;
+ u64 dataLen;
+ u64 senseAddr;
+ u32 senseLen;
+ u32 flags;
+ u8 cdb[16];
+ u8 cdbLen;
+ u8 lun[8];
+ u8 tag;
+ u8 bus;
+ u8 target;
+ u8 vcpuHint;
+ u8 unused[59];
+} PACKED;
+
+struct pvscsi_ring_dsc_s {
+ struct PVSCSIRingsState *ring_state;
+ struct PVSCSIRingReqDesc *ring_reqs;
+ struct PVSCSIRingCmpDesc *ring_cmps;
+};
+
+struct pvscsi_lun_s {
+ struct drive_s drive;
+ void *iobase;
+ u8 target;
+ u8 lun;
+ struct pvscsi_ring_dsc_s *ring_dsc;
+};
+
+static void
+pvscsi_write_cmd_desc(void *iobase, u32 cmd, const void *desc, size_t len)
+{
+ const u32 *ptr = desc;
+ size_t i;
+
+ len /= sizeof(*ptr);
+ writel(iobase + PVSCSI_REG_OFFSET_COMMAND, cmd);
+ for (i = 0; i < len; i++)
+ writel(iobase + PVSCSI_REG_OFFSET_COMMAND_DATA, ptr[i]);
+}
+
+static void
+pvscsi_kick_rw_io(void *iobase)
+{
+ writel(iobase + PVSCSI_REG_OFFSET_KICK_RW_IO, 0);
+}
+
+static void
+pvscsi_wait_intr_cmpl(void *iobase)
+{
+ while (!(readl(iobase + PVSCSI_REG_OFFSET_INTR_STATUS) & PVSCSI_INTR_CMPL_MASK))
+ usleep(5);
+ writel(iobase + PVSCSI_REG_OFFSET_INTR_STATUS, PVSCSI_INTR_CMPL_MASK);
+}
+
+static void
+pvscsi_init_rings(void *iobase, struct pvscsi_ring_dsc_s **ring_dsc)
+{
+ struct PVSCSICmdDescSetupRings cmd = {0,};
+
+ struct pvscsi_ring_dsc_s *dsc = malloc_high(sizeof(*dsc));
+ if (!dsc) {
+ warn_noalloc();
+ return;
+ }
+
+ dsc->ring_state =
+ (struct PVSCSIRingsState *)memalign_high(PAGE_SIZE, PAGE_SIZE);
+ dsc->ring_reqs =
+ (struct PVSCSIRingReqDesc *)memalign_high(PAGE_SIZE, PAGE_SIZE);
+ dsc->ring_cmps =
+ (struct PVSCSIRingCmpDesc *)memalign_high(PAGE_SIZE, PAGE_SIZE);
+ if (!dsc->ring_state || !dsc->ring_reqs || !dsc->ring_cmps) {
+ warn_noalloc();
+ return;
+ }
+ memset(dsc->ring_state, 0, PAGE_SIZE);
+ memset(dsc->ring_reqs, 0, PAGE_SIZE);
+ memset(dsc->ring_cmps, 0, PAGE_SIZE);
+
+ cmd.reqRingNumPages = 1;
+ cmd.cmpRingNumPages = 1;
+ cmd.ringsStatePPN = virt_to_phys(dsc->ring_state) >> PAGE_SHIFT;
+ cmd.reqRingPPNs[0] = virt_to_phys(dsc->ring_reqs) >> PAGE_SHIFT;
+ cmd.cmpRingPPNs[0] = virt_to_phys(dsc->ring_cmps) >> PAGE_SHIFT;
+
+ pvscsi_write_cmd_desc(iobase, PVSCSI_CMD_SETUP_RINGS,
+ &cmd, sizeof(cmd));
+ *ring_dsc = dsc;
+}
+
+static u32
+pvscsi_get_rsp(struct PVSCSIRingsState *s,
+ struct PVSCSIRingCmpDesc *rsp)
+{
+ u32 status = rsp->hostStatus;
+ s->cmpConsIdx = s->cmpConsIdx + 1;
+ return status;
+}
+
+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_fl, 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;
+ u32 cmp_entries = s->cmpNumEntriesLog2;
+ struct PVSCSIRingReqDesc *req;
+ struct PVSCSIRingCmpDesc *rsp;
+ u32 status;
+
+ if (s->reqProdIdx - s->cmpConsIdx >= 1 << req_entries) {
+ dprintf(1, "pvscsi: ring full: reqProdIdx=%d cmpConsIdx=%d\n",
+ s->reqProdIdx, s->cmpConsIdx);
+ return DISK_RET_EBADTRACK;
+ }
+
+ req = ring_dsc->ring_reqs + (s->reqProdIdx & MASK(req_entries));
+ 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);
+
+ rsp = ring_dsc->ring_cmps + (s->cmpConsIdx & MASK(cmp_entries));
+ status = pvscsi_get_rsp(s, rsp);
+
+ return status == 0 ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
+}
+
+static int
+pvscsi_add_lun(struct pci_device *pci, void *iobase,
+ struct pvscsi_ring_dsc_s *ring_dsc, u8 target, u8 lun)
+{
+ struct pvscsi_lun_s *plun = malloc_fseg(sizeof(*plun));
+ if (!plun) {
+ warn_noalloc();
+ return -1;
+ }
+ memset(plun, 0, sizeof(*plun));
+ plun->drive.type = DTYPE_PVSCSI;
+ plun->drive.cntl_id = pci->bdf;
+ plun->target = target;
+ plun->lun = lun;
+ plun->iobase = iobase;
+ plun->ring_dsc = ring_dsc;
+
+ boot_lchs_find_scsi_device(pci, target, lun, &(plun->drive.lchs));
+ char *name = znprintf(MAXDESCSIZE, "pvscsi %pP %d:%d", pci, target, lun);
+ int prio = bootprio_find_scsi_device(pci, target, lun);
+ int ret = scsi_drive_setup(&plun->drive, name, prio, target, lun);
+ free(name);
+ if (ret)
+ goto fail;
+ return 0;
+
+fail:
+ free(plun);
+ return -1;
+}
+
+static void
+pvscsi_scan_target(struct pci_device *pci, void *iobase,
+ struct pvscsi_ring_dsc_s *ring_dsc, u8 target)
+{
+ /* pvscsi has no more than a single lun per target */
+ pvscsi_add_lun(pci, iobase, ring_dsc, target, 0);
+}
+
+static void
+init_pvscsi(void *data)
+{
+ struct pci_device *pci = data;
+ void *iobase = pci_enable_membar(pci, PCI_BASE_ADDRESS_0);
+ if (!iobase)
+ return;
+ pci_enable_busmaster(pci);
+
+ dprintf(1, "found pvscsi at %pP, io @ %p\n", pci, iobase);
+
+ pvscsi_write_cmd_desc(iobase, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
+
+ struct pvscsi_ring_dsc_s *ring_dsc = NULL;
+ pvscsi_init_rings(iobase, &ring_dsc);
+ int i;
+ for (i = 0; i < 64; i++)
+ pvscsi_scan_target(pci, iobase, ring_dsc, i);
+}
+
+void
+pvscsi_setup(void)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_PVSCSI)
+ return;
+
+ dprintf(3, "init pvscsi\n");
+
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->vendor != PCI_VENDOR_ID_VMWARE
+ || pci->device != PCI_DEVICE_ID_VMWARE_PVSCSI)
+ continue;
+ run_thread(init_pvscsi, pci);
+ }
+}
diff --git a/roms/seabios-hppa/src/hw/pvscsi.h b/roms/seabios-hppa/src/hw/pvscsi.h
new file mode 100644
index 000000000..5af7dcb0e
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/pvscsi.h
@@ -0,0 +1,8 @@
+#ifndef _PVSCSI_H_
+#define _PVSCSI_H_
+
+struct disk_op_s;
+int pvscsi_process_op(struct disk_op_s *op);
+void pvscsi_setup(void);
+
+#endif /* _PVSCSI_H_ */
diff --git a/roms/seabios-hppa/src/hw/ramdisk.c b/roms/seabios-hppa/src/hw/ramdisk.c
new file mode 100644
index 000000000..b9e9baabc
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/ramdisk.c
@@ -0,0 +1,108 @@
+// Code for emulating a drive via high-memory accesses.
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBALFLAT
+#include "block.h" // struct drive_s
+#include "bregs.h" // struct bregs
+#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
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // process_ramdisk_op
+
+void
+ramdisk_setup(void)
+{
+ if (!CONFIG_FLASH_FLOPPY)
+ return;
+
+ // Find image.
+ struct romfile_s *file = romfile_findprefix("floppyimg/", NULL);
+ if (!file)
+ return;
+ const char *filename = file->name;
+ u32 size = file->size;
+ dprintf(3, "Found floppy file %s of size %d\n", filename, size);
+ int ftype = find_floppy_type(size);
+ if (ftype < 0) {
+ dprintf(3, "No floppy type found for ramdisk size\n");
+ return;
+ }
+
+ // Allocate ram for image.
+ void *pos = memalign_tmphigh(PAGE_SIZE, size);
+ if (!pos) {
+ warn_noalloc();
+ return;
+ }
+ e820_add((u32)pos, size, E820_RESERVED);
+
+ // Copy image into ram.
+ int ret = file->copy(file, pos, size);
+ if (ret < 0)
+ return;
+
+ // Setup driver.
+ struct drive_s *drive = init_floppy((u32)pos, ftype);
+ if (!drive)
+ return;
+ drive->type = DTYPE_RAMDISK;
+ 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));
+}
+
+static int
+ramdisk_copy(struct disk_op_s *op, int iswrite)
+{
+ u32 offset = GET_GLOBALFLAT(op->drive_fl->cntl_id);
+ offset += (u32)op->lba * DISK_SECTOR_SIZE;
+ u64 opd = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE((u32)op->buf_fl);
+ u64 ramd = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE(offset);
+
+ u64 gdt[6];
+ if (iswrite) {
+ gdt[2] = opd;
+ gdt[3] = ramd;
+ } else {
+ gdt[2] = ramd;
+ gdt[3] = opd;
+ }
+
+ // Call int 1587 to copy data.
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_CF|F_IF;
+ br.ah = 0x87;
+ br.es = GET_SEG(SS);
+ br.si = (u32)gdt;
+ br.cx = op->count * DISK_SECTOR_SIZE / 2;
+ call16_int(0x15, &br);
+
+ if (br.flags & F_CF)
+ return DISK_RET_EBADTRACK;
+ return DISK_RET_SUCCESS;
+}
+
+int
+ramdisk_process_op(struct disk_op_s *op)
+{
+ if (!CONFIG_FLASH_FLOPPY)
+ return 0;
+
+ switch (op->command) {
+ case CMD_READ:
+ return ramdisk_copy(op, 0);
+ case CMD_WRITE:
+ return ramdisk_copy(op, 1);
+ default:
+ return default_process_op(op);
+ }
+}
diff --git a/roms/seabios-hppa/src/hw/rtc.c b/roms/seabios-hppa/src/hw/rtc.c
new file mode 100644
index 000000000..9649a5a79
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/rtc.c
@@ -0,0 +1,100 @@
+// Support for MC146818 Real Time Clock chip.
+//
+// Copyright (C) 2008-2013 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_LOW
+#include "rtc.h" // rtc_read
+#include "stacks.h" // yield
+#include "util.h" // timer_calc
+#include "x86.h" // inb
+
+u8
+rtc_read(u8 index)
+{
+ index |= NMI_DISABLE_BIT;
+ outb(index, PORT_CMOS_INDEX);
+ return inb(PORT_CMOS_DATA);
+}
+
+void
+rtc_write(u8 index, u8 val)
+{
+ index |= NMI_DISABLE_BIT;
+ outb(index, PORT_CMOS_INDEX);
+ outb(val, PORT_CMOS_DATA);
+}
+
+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);
+}
+
+int
+rtc_updating(void)
+{
+ // This function checks to see if the update-in-progress bit
+ // is set in CMOS Status Register A. If not, it returns 0.
+ // If it is set, it tries to wait until there is a transition
+ // to 0, and will return 0 if such a transition occurs. A -1
+ // is returned only after timing out. The maximum period
+ // that this bit should be set is constrained to (1984+244)
+ // useconds, but we wait for longer just to be sure.
+
+ if ((rtc_read(CMOS_STATUS_A) & RTC_A_UIP) == 0)
+ return 0;
+ u32 end = timer_calc(15);
+ for (;;) {
+ if ((rtc_read(CMOS_STATUS_A) & RTC_A_UIP) == 0)
+ return 0;
+ if (timer_check(end))
+ // update-in-progress never transitioned to 0
+ return -1;
+ yield();
+ }
+}
+
+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);
+ rtc_read(CMOS_STATUS_D);
+}
+
+int RTCusers VARLOW;
+
+void
+rtc_use(void)
+{
+ if (!CONFIG_RTC_TIMER)
+ return;
+ int count = GET_LOW(RTCusers);
+ SET_LOW(RTCusers, count+1);
+ if (count)
+ return;
+ // Turn on the Periodic Interrupt timer
+ rtc_mask(CMOS_STATUS_B, 0, RTC_B_PIE);
+}
+
+void
+rtc_release(void)
+{
+ if (!CONFIG_RTC_TIMER)
+ return;
+ int count = GET_LOW(RTCusers);
+ SET_LOW(RTCusers, count-1);
+ if (count != 1)
+ return;
+ // Clear the Periodic Interrupt.
+ rtc_mask(CMOS_STATUS_B, RTC_B_PIE, 0);
+}
diff --git a/roms/seabios-hppa/src/hw/rtc.h b/roms/seabios-hppa/src/hw/rtc.h
new file mode 100644
index 000000000..7bacc49ef
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/rtc.h
@@ -0,0 +1,82 @@
+#ifndef __RTC_H
+#define __RTC_H
+
+#if CONFIG_X86
+#define PORT_CMOS_INDEX 0x0070
+#define PORT_CMOS_DATA 0x0071
+#elif CONFIG_PARISC
+#include "parisc/hppa_hardware.h"
+#define PORT_CMOS_INDEX (IDE_HPA+0x0070)
+#define PORT_CMOS_DATA (IDE_HPA+0x0071)
+#endif
+
+
+// PORT_CMOS_INDEX nmi disable bit
+#define NMI_DISABLE_BIT 0x80
+
+// Standard BIOS RTC chip entries
+#define CMOS_RTC_SECONDS 0x00
+#define CMOS_RTC_SECONDS_ALARM 0x01
+#define CMOS_RTC_MINUTES 0x02
+#define CMOS_RTC_MINUTES_ALARM 0x03
+#define CMOS_RTC_HOURS 0x04
+#define CMOS_RTC_HOURS_ALARM 0x05
+#define CMOS_RTC_DAY_WEEK 0x06
+#define CMOS_RTC_DAY_MONTH 0x07
+#define CMOS_RTC_MONTH 0x08
+#define CMOS_RTC_YEAR 0x09
+#define CMOS_STATUS_A 0x0a
+#define CMOS_STATUS_B 0x0b
+#define CMOS_STATUS_C 0x0c
+#define CMOS_STATUS_D 0x0d
+#define CMOS_RESET_CODE 0x0f
+
+// QEMU cmos config fields. DO NOT ADD MORE. (All new content should
+// be passed via the fw_cfg "file" interface.)
+#define CMOS_FLOPPY_DRIVE_TYPE 0x10
+#define CMOS_DISK_DATA 0x12
+#define CMOS_EQUIPMENT_INFO 0x14
+#define CMOS_DISK_DRIVE1_TYPE 0x19
+#define CMOS_DISK_DRIVE2_TYPE 0x1a
+#define CMOS_DISK_DRIVE1_CYL 0x1b
+#define CMOS_DISK_DRIVE2_CYL 0x24
+#define CMOS_MEM_EXTMEM_LOW 0x30
+#define CMOS_MEM_EXTMEM_HIGH 0x31
+#define CMOS_CENTURY 0x32
+#define CMOS_MEM_EXTMEM2_LOW 0x34
+#define CMOS_MEM_EXTMEM2_HIGH 0x35
+#define CMOS_BIOS_BOOTFLAG1 0x38
+#define CMOS_BIOS_DISKTRANSFLAG 0x39
+#define CMOS_BIOS_BOOTFLAG2 0x3d
+#define CMOS_MEM_HIGHMEM_LOW 0x5b
+#define CMOS_MEM_HIGHMEM_MID 0x5c
+#define CMOS_MEM_HIGHMEM_HIGH 0x5d
+#define CMOS_BIOS_SMP_COUNT 0x5f
+
+// RTC register flags
+#define RTC_A_UIP 0x80
+
+#define RTC_B_SET 0x80
+#define RTC_B_PIE 0x40
+#define RTC_B_AIE 0x20
+#define RTC_B_UIE 0x10
+#define RTC_B_BIN 0x04
+#define RTC_B_24HR 0x02
+#define RTC_B_DSE 0x01
+
+#ifndef __ASSEMBLY__
+
+#include "types.h" // u8
+
+// rtc.c
+u8 rtc_read(u8 index);
+void rtc_write(u8 index, u8 val);
+void rtc_mask(u8 index, u8 off, u8 on);
+int rtc_updating(void);
+void rtc_setup(void);
+void rtc_use(void);
+void rtc_release(void);
+
+#endif // !__ASSEMBLY__
+
+#endif // rtc.h
diff --git a/roms/seabios-hppa/src/hw/sdcard.c b/roms/seabios-hppa/src/hw/sdcard.c
new file mode 100644
index 000000000..ab7007bcf
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/sdcard.c
@@ -0,0 +1,572 @@
+// PCI SD Host Controller Interface
+//
+// Copyright (C) 2014 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "block.h" // struct drive_s
+#include "malloc.h" // malloc_fseg
+#include "output.h" // znprintf
+#include "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_CLASS_SYSTEM_SDHCI
+#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "romfile.h" // romfile_findprefix
+#include "stacks.h" // yield
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // boot_add_hd
+#include "x86.h" // writel
+
+// SDHCI MMIO registers
+struct sdhci_s {
+ u32 sdma_addr;
+ u16 block_size;
+ u16 block_count;
+ u32 arg;
+ u16 transfer_mode;
+ u16 cmd;
+ u32 response[4];
+ u32 data;
+ u32 present_state;
+ u8 host_control;
+ u8 power_control;
+ u8 block_gap_control;
+ u8 wakeup_control;
+ u16 clock_control;
+ u8 timeout_control;
+ u8 software_reset;
+ u16 irq_status;
+ u16 error_irq_status;
+ u16 irq_enable;
+ u16 error_irq_enable;
+ u16 irq_signal;
+ u16 error_signal;
+ u16 auto_cmd12;
+ u16 host_control2;
+ u32 cap_lo, cap_hi;
+ u64 max_current;
+ u16 force_auto_cmd12;
+ u16 force_error;
+ u8 adma_error;
+ u8 pad_55[3];
+ u64 adma_addr;
+ u8 pad_60[156];
+ u16 slot_irq;
+ u16 controller_version;
+} PACKED;
+
+// SDHCI commands
+#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_CARD_INSERTED (1<<16)
+
+// SDHCI transfer_mode flags
+#define ST_BLOCKCOUNT (1<<1)
+#define ST_AUTO_CMD12 (1<<2)
+#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_NOTBUSY (1<<31)
+
+// SDHCI timeouts
+#define SDHCI_POWER_OFF_TIME 1
+#define SDHCI_POWER_ON_TIME 5
+#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 {
+ struct drive_s drive;
+ struct sdhci_s *regs;
+ int card_type;
+};
+
+// SD card types
+#define SF_MMC (1<<0)
+#define SF_HIGHCAPACITY (1<<1)
+
+// Repeatedly read a u16 register until any bit in a given mask is set
+static int
+sdcard_waitw(u16 *reg, u16 mask)
+{
+ u32 end = timer_calc(SDHCI_PIO_TIMEOUT);
+ for (;;) {
+ u16 v = readw(reg);
+ if (v & mask)
+ return v;
+ if (timer_check(end)) {
+ dprintf(1, "scard_waitw: %p %x %x\n", reg, mask, v);
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+}
+
+// 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 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);
+ 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;
+}
+
+// Send an "app specific" command to the card.
+static int
+sdcard_pio_app(struct sdhci_s *regs, int cmd, u32 *param)
+{
+ u32 aparam[4] = {};
+ int ret = sdcard_pio(regs, SC_APP_CMD, aparam);
+ if (ret)
+ return ret;
+ return sdcard_pio(regs, cmd, param);
+}
+
+// Send a command to the card which transfers data.
+static int
+sdcard_pio_transfer(struct sddrive_s *drive, int cmd, u32 addr
+ , void *data, int count)
+{
+ // Send command
+ 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_HIGHCAPACITY))
+ addr *= DISK_SECTOR_SIZE;
+ u32 param[4] = { addr };
+ int ret = sdcard_pio(drive->regs, cmd, param);
+ if (ret)
+ return ret;
+ // Read/write data
+ u16 cbit = isread ? SI_READ_READY : SI_WRITE_READY;
+ while (count--) {
+ ret = sdcard_waitw(&drive->regs->irq_status, cbit);
+ if (ret < 0)
+ return ret;
+ writew(&drive->regs->irq_status, cbit);
+ int i;
+ for (i=0; i<DISK_SECTOR_SIZE/4; i++) {
+ if (isread)
+ *(u32*)data = readl(&drive->regs->data);
+ else
+ writel(&drive->regs->data, *(u32*)data);
+ data += 4;
+ }
+ }
+ // Complete command
+ 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;
+}
+
+// Read/write a block of data to/from the card.
+static int
+sdcard_readwrite(struct disk_op_s *op, int iswrite)
+{
+ struct sddrive_s *drive = container_of(
+ op->drive_fl, struct sddrive_s, drive);
+ int cmd = iswrite ? SC_WRITE_SINGLE : SC_READ_SINGLE;
+ if (op->count > 1)
+ cmd = iswrite ? SC_WRITE_MULTIPLE : SC_READ_MULTIPLE;
+ int ret = sdcard_pio_transfer(drive, cmd, op->lba, op->buf_fl, op->count);
+ if (ret)
+ return DISK_RET_EBADTRACK;
+ return DISK_RET_SUCCESS;
+}
+
+int
+sdcard_process_op(struct disk_op_s *op)
+{
+ if (!CONFIG_SDCARD)
+ return 0;
+ switch (op->command) {
+ case CMD_READ:
+ return sdcard_readwrite(op, 0);
+ case CMD_WRITE:
+ return sdcard_readwrite(op, 1);
+ default:
+ return default_process_op(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 sddrive_s *drive, int volt, int prio)
+{
+ 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;
+ // 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;
+ 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 = 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;
+ // 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(struct sdhci_s *regs, int prio)
+{
+ // Initialize controller
+ 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, 0x01ff);
+ writew(&regs->irq_status, readw(&regs->irq_status));
+ writew(&regs->error_signal, 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;
+
+ // Initialize card
+ struct sddrive_s *drive = malloc_fseg(sizeof(*drive));
+ if (!drive) {
+ warn_noalloc();
+ goto fail;
+ }
+ memset(drive, 0, sizeof(*drive));
+ drive->drive.type = DTYPE_SDCARD;
+ drive->regs = regs;
+ 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);
+}
+
+static void
+sdcard_pci_setup(void *data)
+{
+ struct pci_device *pci = data;
+ // XXX - bars dependent on slot index register in pci config space
+ struct sdhci_s *regs = pci_enable_membar(pci, PCI_BASE_ADDRESS_0);
+ if (!regs)
+ return;
+ int prio = bootprio_find_pci_device(pci);
+ sdcard_controller_setup(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
+sdcard_setup(void)
+{
+ if (!CONFIG_SDCARD)
+ return;
+
+ struct romfile_s *file = NULL;
+ int num_romfiles = 0;
+ for (;;) {
+ file = romfile_findprefix("etc/sdcard", file);
+ if (!file)
+ break;
+ run_thread(sdcard_romfile_setup, file);
+ num_romfiles++;
+ }
+ if (num_romfiles)
+ // only scan for PCI controllers if etc/sdcard not used
+ return;
+
+ 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_pci_setup, pci);
+ }
+}
diff --git a/roms/seabios-hppa/src/hw/serialio.c b/roms/seabios-hppa/src/hw/serialio.c
new file mode 100644
index 000000000..07958b300
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/serialio.c
@@ -0,0 +1,129 @@
+// Low-level serial (and serial-like) device access.
+//
+// Copyright (C) 2008-1013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_DEBUG_SERIAL
+#include "fw/paravirt.h" // RunningOnQEMU
+#include "output.h" // dprintf
+#include "serialio.h" // serial_debug_preinit
+#include "x86.h" // outb
+
+
+/****************************************************************
+ * Serial port debug output
+ ****************************************************************/
+
+#define DEBUG_TIMEOUT 100000
+
+// Write to a serial port register
+static void
+serial_debug_write(u8 offset, u8 val)
+{
+ if (CONFIG_DEBUG_SERIAL) {
+ outb(val, CONFIG_DEBUG_SERIAL_PORT + offset);
+ } else if (CONFIG_DEBUG_SERIAL_MMIO) {
+ ASSERT32FLAT();
+ writeb((void*)CONFIG_DEBUG_SERIAL_MEM_ADDRESS + 4*offset, val);
+ }
+}
+
+// Read from a serial port register
+static u8
+serial_debug_read(u8 offset)
+{
+ if (CONFIG_DEBUG_SERIAL)
+ return inb(CONFIG_DEBUG_SERIAL_PORT + offset);
+ if (CONFIG_DEBUG_SERIAL_MMIO) {
+ ASSERT32FLAT();
+ return readb((void*)CONFIG_DEBUG_SERIAL_MEM_ADDRESS + 4*offset);
+ }
+}
+
+// Setup the debug serial port for output.
+void
+serial_debug_preinit(void)
+{
+ if (!CONFIG_DEBUG_SERIAL && (!CONFIG_DEBUG_SERIAL_MMIO || MODESEGMENT))
+ return;
+ // setup for serial logging: 8N1
+ u8 oldparam, newparam = 0x03;
+ oldparam = serial_debug_read(SEROFF_LCR);
+ serial_debug_write(SEROFF_LCR, newparam);
+ // Disable irqs
+ u8 oldier, newier = 0;
+ oldier = serial_debug_read(SEROFF_IER);
+ serial_debug_write(SEROFF_IER, newier);
+
+ if (oldparam != newparam || oldier != newier)
+ dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
+ , oldparam, oldier, newparam, newier);
+}
+
+// Write a character to the serial port.
+static void
+serial_debug(char c)
+{
+ if (!CONFIG_DEBUG_SERIAL && (!CONFIG_DEBUG_SERIAL_MMIO || MODESEGMENT))
+ return;
+ int timeout = DEBUG_TIMEOUT;
+ while ((serial_debug_read(SEROFF_LSR) & 0x20) != 0x20)
+ if (!timeout--)
+ // Ran out of time.
+ return;
+ serial_debug_write(SEROFF_DATA, c);
+}
+
+void
+serial_debug_putc(char c)
+{
+ if (c == '\n')
+ serial_debug('\r');
+ serial_debug(c);
+}
+
+// Make sure all serial port writes have been completely sent.
+void
+serial_debug_flush(void)
+{
+ if (!CONFIG_DEBUG_SERIAL && (!CONFIG_DEBUG_SERIAL_MMIO || MODESEGMENT))
+ return;
+ int timeout = DEBUG_TIMEOUT;
+ while ((serial_debug_read(SEROFF_LSR) & 0x60) != 0x60)
+ if (!timeout--)
+ // Ran out of time.
+ return;
+}
+
+
+/****************************************************************
+ * QEMU debug port
+ ****************************************************************/
+
+portaddr_t DebugOutputPort VARFSEG = 0x402;
+
+void
+qemu_debug_preinit(void)
+{
+ /* Xen doesn't support checking if debug output is active. */
+ if (runningOnXen())
+ return;
+
+ /* Check if the QEMU debug output port is active */
+ if (CONFIG_DEBUG_IO &&
+ inb(GET_GLOBAL(DebugOutputPort)) != QEMU_DEBUGCON_READBACK)
+ DebugOutputPort = 0;
+}
+
+// Write a character to the special debugging port.
+void
+qemu_debug_putc(char c)
+{
+ if (!CONFIG_DEBUG_IO || !runningOnQEMU())
+ return;
+ u16 port = GET_GLOBAL(DebugOutputPort);
+ if (port)
+ // Send character to debug port.
+ outb(c, port);
+}
diff --git a/roms/seabios-hppa/src/hw/serialio.h b/roms/seabios-hppa/src/hw/serialio.h
new file mode 100644
index 000000000..2fef437ae
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/serialio.h
@@ -0,0 +1,38 @@
+#ifndef __SERIALIO_H
+#define __SERIALIO_H
+
+#include "types.h" // u16
+
+#if CONFIG_X86
+#define PORT_LPT2 0x0278
+#define PORT_SERIAL4 0x02e8
+#define PORT_SERIAL2 0x02f8
+#define PORT_LPT1 0x0378
+#define PORT_SERIAL3 0x03e8
+#define PORT_SERIAL1 0x03f8
+#elif CONFIG_PARISC
+#include "parisc/hppa_hardware.h"
+#define PORT_LPT2 0
+#define PORT_SERIAL4 0
+#define PORT_LPT1 0
+#define PORT_SERIAL3 0
+#endif
+
+// Serial port offsets
+#define SEROFF_DATA 0
+#define SEROFF_DLL 0
+#define SEROFF_IER 1
+#define SEROFF_DLH 1
+#define SEROFF_IIR 2
+#define SEROFF_LCR 3
+#define SEROFF_LSR 5
+#define SEROFF_MSR 6
+
+void serial_debug_preinit(void);
+void serial_debug_putc(char c);
+void serial_debug_flush(void);
+extern portaddr_t DebugOutputPort;
+void qemu_debug_preinit(void);
+void qemu_debug_putc(char c);
+
+#endif // serialio.h
diff --git a/roms/seabios-hppa/src/hw/timer.c b/roms/seabios-hppa/src/hw/timer.c
new file mode 100644
index 000000000..b6f102e39
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/timer.c
@@ -0,0 +1,283 @@
+// Internal timer and Intel 8253 Programmable Interrupt Timer (PIT) support.
+//
+// Copyright (C) 2008-2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_LOW
+#include "config.h" // CONFIG_*
+#include "output.h" // dprintf
+#include "stacks.h" // yield
+#include "util.h" // timer_setup
+#include "x86.h" // cpuid
+
+#define PORT_PIT_COUNTER0 0x0040
+#define PORT_PIT_COUNTER1 0x0041
+#define PORT_PIT_COUNTER2 0x0042
+#define PORT_PIT_MODE 0x0043
+#define PORT_PS2_CTRLB 0x0061
+
+// Bits for PORT_PIT_MODE
+#define PM_SEL_TIMER0 (0<<6)
+#define PM_SEL_TIMER1 (1<<6)
+#define PM_SEL_TIMER2 (2<<6)
+#define PM_SEL_READBACK (3<<6)
+#define PM_ACCESS_LATCH (0<<4)
+#define PM_ACCESS_LOBYTE (1<<4)
+#define PM_ACCESS_HIBYTE (2<<4)
+#define PM_ACCESS_WORD (3<<4)
+#define PM_MODE0 (0<<1)
+#define PM_MODE1 (1<<1)
+#define PM_MODE2 (2<<1)
+#define PM_MODE3 (3<<1)
+#define PM_MODE4 (4<<1)
+#define PM_MODE5 (5<<1)
+#define PM_CNT_BINARY (0<<0)
+#define PM_CNT_BCD (1<<0)
+#define PM_READ_COUNTER0 (1<<1)
+#define PM_READ_COUNTER1 (1<<2)
+#define PM_READ_COUNTER2 (1<<3)
+#define PM_READ_STATUSVALUE (0<<4)
+#define PM_READ_VALUE (1<<4)
+#define PM_READ_STATUS (2<<4)
+
+// Bits for PORT_PS2_CTRLB
+#define PPCB_T2GATE (1<<0)
+#define PPCB_SPKR (1<<1)
+#define PPCB_T2OUT (1<<5)
+
+#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 = DIV_ROUND_UP(PMTIMER_HZ, 1000 * PMTIMER_TO_PIT);
+u16 TimerPort VARFSEG = PORT_PIT_COUNTER0;
+u8 ShiftTSC VARFSEG;
+
+
+/****************************************************************
+ * Internal timer setup
+ ****************************************************************/
+
+#define CALIBRATE_COUNT 0x800 // Approx 1.7ms
+
+// Calibrate the CPU time-stamp-counter
+static void
+tsctimer_setup(void)
+{
+ // Setup "timer2"
+ u8 orig = inb(PORT_PS2_CTRLB);
+ outb((orig & ~PPCB_SPKR) | PPCB_T2GATE, PORT_PS2_CTRLB);
+ /* binary, mode 0, LSB/MSB, Ch 2 */
+ outb(PM_SEL_TIMER2|PM_ACCESS_WORD|PM_MODE0|PM_CNT_BINARY, PORT_PIT_MODE);
+ /* LSB of ticks */
+ outb(CALIBRATE_COUNT & 0xFF, PORT_PIT_COUNTER2);
+ /* MSB of ticks */
+ outb(CALIBRATE_COUNT >> 8, PORT_PIT_COUNTER2);
+
+ u64 start = rdtscll();
+ while ((inb(PORT_PS2_CTRLB) & PPCB_T2OUT) == 0)
+ ;
+ u64 end = rdtscll();
+
+ // Restore PORT_PS2_CTRLB
+ outb(orig, PORT_PS2_CTRLB);
+
+ // Store calibrated cpu khz.
+ u64 diff = end - start;
+ dprintf(6, "tsc calibrate start=%u end=%u diff=%u\n"
+ , (u32)start, (u32)end, (u32)diff);
+ u64 t = DIV_ROUND_UP(diff * PMTIMER_HZ, CALIBRATE_COUNT);
+ while (t >= (1<<24)) {
+ ShiftTSC++;
+ 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);
+}
+
+// Setup internal timers.
+void
+timer_setup(void)
+{
+ if (!CONFIG_TSC_TIMER)
+ return;
+ if (TimerPort != PORT_PIT_COUNTER0)
+ return; // have timer already
+
+ // 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)
+ tsctimer_setup();
+}
+
+void
+tsctimer_setfreq(u32 khz, const char *src)
+{
+ if (!CONFIG_TSC_TIMER)
+ return;
+ if (TimerPort != PORT_PIT_COUNTER0)
+ return; // have timer already
+
+ TimerKHz = khz;
+ ShiftTSC = 0;
+ while (TimerKHz >= 6000) {
+ ShiftTSC++;
+ TimerKHz = (TimerKHz + 1) >> 1;
+ }
+ TimerPort = 0;
+
+ dprintf(1, "CPU Mhz=%u (%s)\n", (TimerKHz << ShiftTSC) / 1000, src);
+}
+
+void
+pmtimer_setup(u16 ioport)
+{
+ if (!CONFIG_PMTIMER)
+ return;
+ if (TimerPort != PORT_PIT_COUNTER0)
+ return; // have timer already
+
+ dprintf(1, "Using pmtimer, ioport 0x%x\n", ioport);
+ TimerPort = ioport;
+ TimerKHz = DIV_ROUND_UP(PMTIMER_HZ, 1000);
+}
+
+
+/****************************************************************
+ * Internal timer reading
+ ****************************************************************/
+
+u32 TimerLast VARLOW;
+
+// Add extra high bits to timers that have less than 32bits of precision.
+static u32
+timer_adjust_bits(u32 value, u32 validbits)
+{
+ u32 last = GET_LOW(TimerLast);
+ value = (last & ~validbits) | (value & validbits);
+ if (value < last)
+ value += validbits + 1;
+ SET_LOW(TimerLast, value);
+ return value;
+}
+
+// Sample the current timer value.
+static u32
+timer_read(void)
+{
+ u16 port = GET_GLOBAL(TimerPort);
+ if (CONFIG_TSC_TIMER && !port)
+ // Read from CPU TSC
+ return rdtscll() >> GET_GLOBAL(ShiftTSC);
+ if (CONFIG_PMTIMER && port != PORT_PIT_COUNTER0)
+ // Read from PMTIMER
+ return timer_adjust_bits(inl(port), 0xffffff);
+ // Read from PIT.
+ outb(PM_SEL_READBACK | PM_READ_VALUE | PM_READ_COUNTER0, PORT_PIT_MODE);
+ u16 v = inb(PORT_PIT_COUNTER0) | (inb(PORT_PIT_COUNTER0) << 8);
+ return timer_adjust_bits(-v, 0xffff);
+}
+
+// Return the TSC value that is 'msecs' time in the future.
+u32
+timer_calc(u32 msecs)
+{
+ return timer_read() + (GET_GLOBAL(TimerKHz) * msecs);
+}
+u32
+timer_calc_usec(u32 usecs)
+{
+ u32 cur = timer_read(), khz = GET_GLOBAL(TimerKHz);
+ if (usecs > 500000)
+ return cur + DIV_ROUND_UP(usecs, 1000) * khz;
+ return cur + DIV_ROUND_UP(usecs * khz, 1000);
+}
+static u32
+timer_calc_nsec(u32 nsecs)
+{
+ u32 cur = timer_read(), khz = GET_GLOBAL(TimerKHz);
+ if (nsecs > 500000)
+ return cur + DIV_ROUND_UP(nsecs, 1000000) * khz;
+ return cur + DIV_ROUND_UP(nsecs * khz, 1000000);
+}
+
+// Check if the current time is past a previously calculated end time.
+int
+timer_check(u32 end)
+{
+ return (s32)(timer_read() - end) > 0;
+}
+
+static void
+timer_delay(u32 end)
+{
+ while (!timer_check(end))
+ cpu_relax();
+}
+
+static void
+timer_sleep(u32 end)
+{
+ while (!timer_check(end))
+ yield();
+}
+
+void ndelay(u32 count) {
+ timer_delay(timer_calc_nsec(count));
+}
+void udelay(u32 count) {
+ timer_delay(timer_calc_usec(count));
+}
+void mdelay(u32 count) {
+ timer_delay(timer_calc(count));
+}
+
+void nsleep(u32 count) {
+ timer_sleep(timer_calc_nsec(count));
+}
+void usleep(u32 count) {
+ timer_sleep(timer_calc_usec(count));
+}
+void msleep(u32 count) {
+ timer_sleep(timer_calc(count));
+}
+
+
+/****************************************************************
+ * PIT setup
+ ****************************************************************/
+
+#define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer
+
+// Return the number of milliseconds in 'ticks' number of timer irqs.
+u32
+ticks_to_ms(u32 ticks)
+{
+ u32 t = PIT_TICK_INTERVAL * 1000 * PMTIMER_TO_PIT * ticks;
+ return DIV_ROUND_UP(t, PMTIMER_HZ);
+}
+
+// Return the number of timer irqs in 'ms' number of milliseconds.
+u32
+ticks_from_ms(u32 ms)
+{
+ u32 t = DIV_ROUND_UP((u64)ms * PMTIMER_HZ, PIT_TICK_INTERVAL);
+ return DIV_ROUND_UP(t, 1000 * PMTIMER_TO_PIT);
+}
+
+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
+ outb(0x0, PORT_PIT_COUNTER0);
+ outb(0x0, PORT_PIT_COUNTER0);
+}
diff --git a/roms/seabios-hppa/src/hw/tpm_drivers.c b/roms/seabios-hppa/src/hw/tpm_drivers.c
new file mode 100644
index 000000000..2b5753c13
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/tpm_drivers.c
@@ -0,0 +1,637 @@
+// 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 "byteorder.h" // be32_to_cpu
+#include "config.h" // CONFIG_TPM_TIS_SHA1THRESHOLD
+#include "hw/tpm_drivers.h" // struct tpm_driver
+#include "std/tcg.h" // TCG_RESPONSE_TIMEOUT
+#include "output.h" // warn_timeout
+#include "stacks.h" // yield
+#include "string.h" // memcpy
+#include "util.h" // timer_calc_usec
+#include "x86.h" // readl
+
+/* low level driver implementation */
+struct tpm_driver {
+ u32 *timeouts;
+ u32 *durations;
+ void (*set_timeouts)(u32 timeouts[4], u32 durations[3]);
+ u32 (*probe)(void);
+ TPMVersion (*get_tpm_version)(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);
+};
+
+extern struct tpm_driver tpm_drivers[];
+
+#define TIS_DRIVER_IDX 0
+#define CRB_DRIVER_IDX 1
+#define TPM_NUM_DRIVERS 2
+
+#define TPM_INVALID_DRIVER 0xf
+
+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];
+
+static u32 crb_cmd_size;
+static void *crb_cmd;
+static u32 crb_resp_size;
+static void *crb_resp;
+
+static u32 wait_reg8(u8* reg, u32 time, u8 mask, u8 expect)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 1;
+ u32 end = timer_calc_usec(time);
+
+ for (;;) {
+ u8 value = readl(reg);
+ if ((value & mask) == expect) {
+ rc = 0;
+ break;
+ }
+ if (timer_check(end)) {
+ warn_timeout();
+ break;
+ }
+ yield();
+ }
+ return rc;
+}
+
+static u32 tis_wait_access(u8 locty, u32 time, u8 mask, u8 expect)
+{
+ return wait_reg8(TIS_REG(locty, TIS_REG_ACCESS), time, mask, expect);
+}
+
+static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect)
+{
+ return wait_reg8(TIS_REG(locty, TIS_REG_STS), time, mask, expect);
+}
+
+static u32 crb_wait_reg(u8 locty, u16 reg, u32 time, u8 mask, u8 expect)
+{
+ return wait_reg8(CRB_REG(locty, reg), time, mask, expect);
+}
+
+/* if device is not there, return '0', '1' otherwise */
+static u32 tis_probe(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ /* Wait for the interface to report it's ready */
+ u32 rc = tis_wait_access(0, TIS_DEFAULT_TIMEOUT_A,
+ TIS_ACCESS_TPM_REG_VALID_STS,
+ TIS_ACCESS_TPM_REG_VALID_STS);
+ if (rc)
+ return 0;
+
+ u32 didvid = readl(TIS_REG(0, TIS_REG_DID_VID));
+
+ if ((didvid != 0) && (didvid != 0xffffffff))
+ rc = 1;
+
+ /* TPM 2 has an interface register */
+ u32 ifaceid = readl(TIS_REG(0, TIS_REG_IFACE_ID));
+
+ if ((ifaceid & 0xf) != 0xf) {
+ if ((ifaceid & 0xf) == 1) {
+ /* CRB is active; no TIS */
+ return 0;
+ }
+ if ((ifaceid & (1 << 13)) == 0) {
+ /* TIS cannot be selected */
+ return 0;
+ }
+ /* write of 0 to bits 17-18 selects TIS */
+ writel(TIS_REG(0, TIS_REG_IFACE_ID), 0);
+ /* since we only support TIS, we lock it */
+ writel(TIS_REG(0, TIS_REG_IFACE_ID), (1 << 19));
+ }
+
+ return rc;
+}
+
+static TPMVersion tis_get_tpm_version(void)
+{
+ u32 reg = readl(TIS_REG(0, TIS_REG_IFACE_ID));
+
+ /*
+ * FIFO interface as defined in TIS1.3 is active
+ * Interface capabilities are defined in TIS_REG_INTF_CAPABILITY
+ */
+ if ((reg & 0xf) == 0xf) {
+ reg = readl(TIS_REG(0, TIS_REG_INTF_CAPABILITY));
+ /* Interface 1.3 for TPM 2.0 */
+ if (((reg >> 28) & 0x7) == 3)
+ return TPM_VERSION_2;
+ }
+ /* FIFO interface as defined in PTP for TPM 2.0 is active */
+ else if ((reg & 0xf) == 0) {
+ return TPM_VERSION_2;
+ }
+
+ return TPM_VERSION_1_2;
+}
+
+static void init_timeout(int driver)
+{
+ if (tpm_drivers[driver].durations == NULL) {
+ u32 *durations = tpm_default_dur;
+ memcpy(durations, tpm_default_durations,
+ sizeof(tpm_default_durations));
+ tpm_drivers[driver].durations = durations;
+ }
+
+ if (tpm_drivers[driver].timeouts == NULL) {
+ u32 *timeouts = tpm_default_to;
+ memcpy(timeouts, tis_default_timeouts,
+ sizeof(tis_default_timeouts));
+ tpm_drivers[driver].timeouts = timeouts;
+ }
+}
+
+static u32 tis_init(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 1;
+
+ writeb(TIS_REG(0, TIS_REG_INT_ENABLE), 0);
+
+ init_timeout(TIS_DRIVER_IDX);
+
+ 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_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_loop = 0;
+ u16 burst = 0;
+ u8 locty = tis_find_active_locality();
+ u32 timeout_d = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_D];
+ u32 end = timer_calc_usec(timeout_d);
+
+ do {
+ while (burst == 0) {
+ burst = readl(TIS_REG(locty, TIS_REG_STS)) >> 8;
+ if (burst == 0) {
+ if (timer_check(end)) {
+ warn_timeout();
+ break;
+ }
+ yield();
+ }
+ }
+
+ 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_loop = 1;
+ } while (end_loop == 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 = 1;
+
+ 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 = 1;
+
+ return rc;
+}
+
+#define CRB_STATE_VALID_STS 0b10000000
+#define CRB_STATE_LOC_ASSIGNED 0x00000010
+#define CRB_STATE_READY_MASK (CRB_STATE_VALID_STS | CRB_STATE_LOC_ASSIGNED)
+
+/* if device is not there, return '0', '1' otherwise */
+static u32 crb_probe(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ /* Wait for the interface to report it's ready */
+ u32 rc = crb_wait_reg(0, CRB_REG_LOC_STATE, TIS2_DEFAULT_TIMEOUT_D,
+ CRB_STATE_READY_MASK, CRB_STATE_VALID_STS);
+ if (rc)
+ return 0;
+
+ u32 ifaceid = readl(CRB_REG(0, CRB_REG_INTF_ID));
+
+ if ((ifaceid & 0xf) != 0xf) {
+ if ((ifaceid & 0xf) == 1) {
+ /* CRB is active */
+ } else if ((ifaceid & (1 << 14)) == 0) {
+ /* CRB cannot be selected */
+ return 0;
+ }
+ /* write of 1 to bits 17-18 selects CRB */
+ writel(CRB_REG(0, CRB_REG_INTF_ID), (1 << 17));
+ /* lock it */
+ writel(CRB_REG(0, CRB_REG_INTF_ID), (1 << 19));
+ }
+
+ /* no support for 64 bit addressing yet */
+ if (readl(CRB_REG(0, CRB_REG_CTRL_CMD_HADDR)))
+ return 0;
+
+ u64 addr = readq(CRB_REG(0, CRB_REG_CTRL_RSP_ADDR));
+ if (addr > 0xffffffff)
+ return 0;
+
+ return 1;
+}
+
+static TPMVersion crb_get_tpm_version(void)
+{
+ /* CRB is supposed to be TPM 2.0 only */
+ return TPM_VERSION_2;
+}
+
+static u32 crb_init(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 1;
+
+ crb_cmd = (void*)readl(CRB_REG(0, CRB_REG_CTRL_CMD_LADDR));
+ crb_cmd_size = readl(CRB_REG(0, CRB_REG_CTRL_CMD_SIZE));
+ crb_resp = (void*)readl(CRB_REG(0, CRB_REG_CTRL_RSP_ADDR));
+ crb_resp_size = readl(CRB_REG(0, CRB_REG_CTRL_RSP_SIZE));
+
+ init_timeout(CRB_DRIVER_IDX);
+
+ return 0;
+}
+
+static u32 crb_activate(u8 locty)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ writeb(CRB_REG(locty, CRB_REG_LOC_CTRL), 1);
+
+ return 0;
+}
+
+static u32 crb_find_active_locality(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ return 0;
+}
+
+#define CRB_CTRL_REQ_CMD_READY 0b1
+#define CRB_START_INVOKE 0b1
+#define CRB_CTRL_STS_ERROR 0b1
+
+static u32 crb_ready(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u8 locty = crb_find_active_locality();
+ u32 timeout_c = tpm_drivers[CRB_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_C];
+
+ writel(CRB_REG(locty, CRB_REG_CTRL_REQ), CRB_CTRL_REQ_CMD_READY);
+ rc = crb_wait_reg(locty, CRB_REG_CTRL_REQ, timeout_c,
+ CRB_CTRL_REQ_CMD_READY, 0);
+
+ return rc;
+}
+
+static u32 crb_senddata(const u8 *const data, u32 len)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (len > crb_cmd_size)
+ return 1;
+
+ u8 locty = crb_find_active_locality();
+ memcpy(crb_cmd, data, len);
+ writel(CRB_REG(locty, CRB_REG_CTRL_START), CRB_START_INVOKE);
+
+ return 0;
+}
+
+static u32 crb_readresp(u8 *buffer, u32 *len)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u8 locty = crb_find_active_locality();
+ if (readl(CRB_REG(locty, CRB_REG_CTRL_STS)) & CRB_CTRL_STS_ERROR)
+ return 1;
+
+ if (*len < 6)
+ return 1;
+
+ memcpy(buffer, crb_resp, 6);
+ u32 expected = be32_to_cpu(*(u32 *) &buffer[2]);
+ if (expected < 6)
+ return 1;
+
+ *len = (*len < expected) ? *len : expected;
+
+ memcpy(buffer + 6, crb_resp + 6, *len - 6);
+
+ return 0;
+}
+
+
+static u32 crb_waitdatavalid(void)
+{
+ return 0;
+}
+
+static u32 crb_waitrespready(enum tpmDurationType to_t)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u8 locty = crb_find_active_locality();
+ u32 timeout = tpm_drivers[CRB_DRIVER_IDX].durations[to_t];
+
+ rc = crb_wait_reg(locty, CRB_REG_CTRL_START, timeout,
+ CRB_START_INVOKE, 0);
+
+ return rc;
+}
+
+struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
+ [TIS_DRIVER_IDX] =
+ {
+ .timeouts = NULL,
+ .durations = NULL,
+ .set_timeouts = set_timeouts,
+ .probe = tis_probe,
+ .get_tpm_version = tis_get_tpm_version,
+ .init = tis_init,
+ .activate = tis_activate,
+ .ready = tis_ready,
+ .senddata = tis_senddata,
+ .readresp = tis_readresp,
+ .waitdatavalid = tis_waitdatavalid,
+ .waitrespready = tis_waitrespready,
+ },
+ [CRB_DRIVER_IDX] =
+ {
+ .timeouts = NULL,
+ .durations = NULL,
+ .set_timeouts = set_timeouts,
+ .probe = crb_probe,
+ .get_tpm_version = crb_get_tpm_version,
+ .init = crb_init,
+ .activate = crb_activate,
+ .ready = crb_ready,
+ .senddata = crb_senddata,
+ .readresp = crb_readresp,
+ .waitdatavalid = crb_waitdatavalid,
+ .waitrespready = crb_waitrespready,
+ },
+};
+
+static u8 TPMHW_driver_to_use = TPM_INVALID_DRIVER;
+
+TPMVersion
+tpmhw_probe(void)
+{
+ unsigned int i;
+ for (i = 0; i < TPM_NUM_DRIVERS; i++) {
+ struct tpm_driver *td = &tpm_drivers[i];
+ if (td->probe() != 0) {
+ td->init();
+ TPMHW_driver_to_use = i;
+ return td->get_tpm_version();
+ }
+ }
+ return TPM_VERSION_NONE;
+}
+
+int
+tpmhw_is_present(void)
+{
+ return TPMHW_driver_to_use != TPM_INVALID_DRIVER;
+}
+
+int
+tpmhw_transmit(u8 locty, struct tpm_req_header *req,
+ void *respbuffer, u32 *respbufferlen,
+ enum tpmDurationType to_t)
+{
+ if (TPMHW_driver_to_use == TPM_INVALID_DRIVER)
+ return -1;
+
+ struct tpm_driver *td = &tpm_drivers[TPMHW_driver_to_use];
+
+ u32 irc = td->activate(locty);
+ if (irc != 0) {
+ /* tpm could not be activated */
+ return -1;
+ }
+
+ irc = td->senddata((void*)req, be32_to_cpu(req->totlen));
+ if (irc != 0)
+ return -1;
+
+ irc = td->waitdatavalid();
+ if (irc != 0)
+ return -1;
+
+ irc = td->waitrespready(to_t);
+ if (irc != 0)
+ return -1;
+
+ irc = td->readresp(respbuffer, respbufferlen);
+ if (irc != 0 ||
+ *respbufferlen < sizeof(struct tpm_rsp_header))
+ return -1;
+
+ td->ready();
+
+ return 0;
+}
+
+void
+tpmhw_set_timeouts(u32 timeouts[4], u32 durations[3])
+{
+ struct tpm_driver *td = &tpm_drivers[TPMHW_driver_to_use];
+ td->set_timeouts(timeouts, durations);
+}
diff --git a/roms/seabios-hppa/src/hw/tpm_drivers.h b/roms/seabios-hppa/src/hw/tpm_drivers.h
new file mode 100644
index 000000000..adf183969
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/tpm_drivers.h
@@ -0,0 +1,127 @@
+#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,
+};
+
+typedef u8 TPMVersion;
+
+#define TPM_VERSION_NONE 0
+#define TPM_VERSION_1_2 1
+#define TPM_VERSION_2 2
+
+TPMVersion tpmhw_probe(void);
+int tpmhw_is_present(void);
+struct tpm_req_header;
+int tpmhw_transmit(u8 locty, struct tpm_req_header *req,
+ void *respbuffer, u32 *respbufferlen,
+ enum tpmDurationType to_t);
+void tpmhw_set_timeouts(u32 timeouts[4], u32 durations[3]);
+
+/* CRB driver */
+/* address of locality 0 (CRB) */
+#define TPM_CRB_BASE_ADDRESS 0xfed40000
+
+#define CRB_REG(LOCTY, REG) \
+ (void *)(TPM_CRB_BASE_ADDRESS + (LOCTY << 12) + REG)
+
+/* hardware registers */
+#define CRB_REG_LOC_STATE 0x0
+#define CRB_REG_LOC_CTRL 0x8
+#define CRB_REG_LOC_STS 0xC
+#define CRB_REG_INTF_ID 0x30
+#define CRB_REG_CTRL_EXT 0x38
+#define CRB_REG_CTRL_REQ 0x40
+#define CRB_REG_CTRL_STS 0x44
+#define CRB_REG_CTRL_CANCEL 0x48
+#define CRB_REG_CTRL_START 0x4C
+#define CRB_REG_INT_ENABLE 0x50
+#define CRB_REG_INT_STS 0x54
+#define CRB_REG_CTRL_CMD_SIZE 0x58
+#define CRB_REG_CTRL_CMD_LADDR 0x5C
+#define CRB_REG_CTRL_CMD_HADDR 0x60
+#define CRB_REG_CTRL_RSP_SIZE 0x64
+#define CRB_REG_CTRL_RSP_ADDR 0x68
+#define CRB_REG_DATA_BUFFER 0x80
+
+/* 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_IFACE_ID 0x30
+#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 */
+
+/*
+ * Default TIS timeouts used before getting them from the TPM itself
+ */
+#define TIS_DEFAULT_TIMEOUT_A 750000 /* us */
+#define TIS_DEFAULT_TIMEOUT_B 2000000 /* us */
+#define TIS_DEFAULT_TIMEOUT_C 750000 /* us */
+#define TIS_DEFAULT_TIMEOUT_D 750000 /* us */
+
+/*
+ * Default TIS 2 timeouts given in TPM Profile (TPT) Spec
+ */
+#define TIS2_DEFAULT_TIMEOUT_A 750000 /* us */
+#define TIS2_DEFAULT_TIMEOUT_B 2000000 /* us */
+#define TIS2_DEFAULT_TIMEOUT_C 200000 /* us */
+#define TIS2_DEFAULT_TIMEOUT_D 30000 /* us */
+
+enum tisTimeoutType {
+ TIS_TIMEOUT_TYPE_A = 0,
+ TIS_TIMEOUT_TYPE_B,
+ TIS_TIMEOUT_TYPE_C,
+ TIS_TIMEOUT_TYPE_D,
+};
+
+/*
+ * Default command durations used before getting them from the
+ * TPM itself
+ */
+#define TPM_DEFAULT_DURATION_SHORT 2000000 /* us */
+#define TPM_DEFAULT_DURATION_MEDIUM 20000000 /* us */
+#define TPM_DEFAULT_DURATION_LONG 60000000 /* us */
+
+/*
+ * TPM 2 command durations; we set them to the timeout values
+ * given in TPM Profile (PTP) Specification; exceeding those
+ * timeout values indicates a faulty TPM.
+ */
+#define TPM2_DEFAULT_DURATION_SHORT 750000 /* us */
+#define TPM2_DEFAULT_DURATION_MEDIUM 2000000 /* us */
+#define TPM2_DEFAULT_DURATION_LONG 2000000 /* us */
+
+#endif /* TPM_DRIVERS_H */
diff --git a/roms/seabios-hppa/src/hw/usb-ehci.c b/roms/seabios-hppa/src/hw/usb-ehci.c
new file mode 100644
index 000000000..d01fa853e
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-ehci.c
@@ -0,0 +1,650 @@
+// Code for handling EHCI USB controllers.
+//
+// Copyright (C) 2010-2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_LOWFLAT
+#include "config.h" // CONFIG_*
+#include "output.h" // dprintf
+#include "malloc.h" // free
+#include "memmap.h" // PAGE_SIZE
+#include "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI
+#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "string.h" // memset
+#include "usb.h" // struct usb_s
+#include "usb-ehci.h" // struct ehci_qh
+#include "util.h" // msleep
+#include "x86.h" // readl
+
+struct usb_ehci_s {
+ struct usb_s usb;
+ struct ehci_caps *caps;
+ struct ehci_regs *regs;
+ struct ehci_qh *async_qh;
+ int checkports;
+};
+
+struct ehci_pipe {
+ struct ehci_qh qh;
+ struct ehci_qtd *next_td, *tds;
+ void *data;
+ struct usb_pipe pipe;
+};
+
+static int PendingEHCI;
+
+
+/****************************************************************
+ * Root hub
+ ****************************************************************/
+
+#define EHCI_TIME_POSTPOWER 20
+#define EHCI_TIME_POSTRESET 2
+
+// Check if device attached to port
+static int
+ehci_hub_detect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb);
+ u32 *portreg = &cntl->regs->portsc[port];
+ u32 portsc = readl(portreg);
+
+ if (!(portsc & PORT_CONNECT))
+ // No device present
+ return 0;
+
+ if ((portsc & PORT_LINESTATUS_MASK) == PORT_LINESTATUS_KSTATE) {
+ // low speed device
+ writel(portreg, portsc | PORT_OWNER);
+ return -1;
+ }
+
+ // XXX - if just powered up, need to wait for USB_TIME_ATTDB?
+
+ // Begin reset on port
+ portsc = (portsc & ~PORT_PE) | PORT_RESET;
+ writel(portreg, portsc);
+ msleep(USB_TIME_DRSTR);
+ return 1;
+}
+
+// Reset device on port
+static int
+ehci_hub_reset(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb);
+ u32 *portreg = &cntl->regs->portsc[port];
+ u32 portsc = readl(portreg);
+
+ // Finish reset on port
+ portsc &= ~PORT_RESET;
+ writel(portreg, portsc);
+ msleep(EHCI_TIME_POSTRESET);
+
+ portsc = readl(portreg);
+ if (!(portsc & PORT_CONNECT))
+ // No longer connected
+ return -1;
+ if (!(portsc & PORT_PE)) {
+ // full speed device
+ writel(portreg, portsc | PORT_OWNER);
+ return -1;
+ }
+
+ return USB_HIGHSPEED;
+}
+
+// Disable port
+static void
+ehci_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb);
+ u32 *portreg = &cntl->regs->portsc[port];
+ u32 portsc = readl(portreg);
+ writel(portreg, portsc & ~PORT_PE);
+}
+
+static struct usbhub_op_s ehci_HubOp = {
+ .detect = ehci_hub_detect,
+ .reset = ehci_hub_reset,
+ .disconnect = ehci_hub_disconnect,
+};
+
+// Find any devices connected to the root hub.
+static int
+check_ehci_ports(struct usb_ehci_s *cntl)
+{
+ // Power up ports.
+ int i;
+ for (i=0; i<cntl->checkports; i++) {
+ u32 *portreg = &cntl->regs->portsc[i];
+ u32 portsc = readl(portreg);
+ if (!(portsc & PORT_POWER)) {
+ portsc |= PORT_POWER;
+ writel(portreg, portsc);
+ }
+ }
+ msleep(EHCI_TIME_POSTPOWER);
+
+ struct usbhub_s hub;
+ memset(&hub, 0, sizeof(hub));
+ hub.cntl = &cntl->usb;
+ hub.portcount = cntl->checkports;
+ hub.op = &ehci_HubOp;
+ usb_enumerate(&hub);
+ return hub.devcount;
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+// Wait for next USB async frame to start - for ensuring safe memory release.
+static void
+ehci_waittick(struct usb_ehci_s *cntl)
+{
+ if (MODE16) {
+ msleep(10);
+ return;
+ }
+ // Wait for access to "doorbell"
+ barrier();
+ u32 cmd, sts;
+ u32 end = timer_calc(100);
+ for (;;) {
+ sts = readl(&cntl->regs->usbsts);
+ if (!(sts & STS_IAA)) {
+ cmd = readl(&cntl->regs->usbcmd);
+ if (!(cmd & CMD_IAAD))
+ break;
+ }
+ if (timer_check(end)) {
+ warn_timeout();
+ return;
+ }
+ yield();
+ }
+ // Ring "doorbell"
+ writel(&cntl->regs->usbcmd, cmd | CMD_IAAD);
+ // Wait for completion
+ for (;;) {
+ sts = readl(&cntl->regs->usbsts);
+ if (sts & STS_IAA)
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ return;
+ }
+ yield();
+ }
+ // Ack completion
+ writel(&cntl->regs->usbsts, STS_IAA);
+}
+
+static void
+ehci_free_pipes(struct usb_ehci_s *cntl)
+{
+ dprintf(7, "ehci_free_pipes %p\n", cntl);
+
+ struct ehci_qh *start = cntl->async_qh;
+ struct ehci_qh *pos = start;
+ for (;;) {
+ struct ehci_qh *next = (void*)(pos->next & ~EHCI_PTR_BITS);
+ if (next == start)
+ break;
+ struct ehci_pipe *pipe = container_of(next, struct ehci_pipe, qh);
+ if (usb_is_freelist(&cntl->usb, &pipe->pipe))
+ pos->next = next->next;
+ else
+ pos = next;
+ }
+ ehci_waittick(cntl);
+ for (;;) {
+ struct usb_pipe *usbpipe = cntl->usb.freelist;
+ if (!usbpipe)
+ break;
+ cntl->usb.freelist = usbpipe->freenext;
+ struct ehci_pipe *pipe = container_of(usbpipe, struct ehci_pipe, pipe);
+ free(pipe);
+ }
+}
+
+static void
+configure_ehci(void *data)
+{
+ struct usb_ehci_s *cntl = data;
+
+ // Allocate ram for schedule storage
+ struct ehci_framelist *fl = memalign_high(sizeof(*fl), sizeof(*fl));
+ struct ehci_qh *intr_qh = memalign_high(EHCI_QH_ALIGN, sizeof(*intr_qh));
+ struct ehci_qh *async_qh = memalign_high(EHCI_QH_ALIGN, sizeof(*async_qh));
+ if (!fl || !intr_qh || !async_qh) {
+ warn_noalloc();
+ PendingEHCI--;
+ goto fail;
+ }
+
+ // XXX - check for halted?
+
+ // Reset the HC
+ u32 cmd = readl(&cntl->regs->usbcmd);
+ writel(&cntl->regs->usbcmd, (cmd & ~(CMD_ASE | CMD_PSE)) | CMD_HCRESET);
+ u32 end = timer_calc(250);
+ for (;;) {
+ cmd = readl(&cntl->regs->usbcmd);
+ if (!(cmd & CMD_HCRESET))
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ PendingEHCI--;
+ goto fail;
+ }
+ yield();
+ }
+
+ // Disable interrupts (just to be safe).
+ writel(&cntl->regs->usbintr, 0);
+
+ // Set schedule to point to primary intr queue head
+ memset(intr_qh, 0, sizeof(*intr_qh));
+ intr_qh->next = EHCI_PTR_TERM;
+ intr_qh->info2 = (0x01 << QH_SMASK_SHIFT);
+ intr_qh->token = QTD_STS_HALT;
+ intr_qh->qtd_next = intr_qh->alt_next = EHCI_PTR_TERM;
+ int i;
+ for (i=0; i<ARRAY_SIZE(fl->links); i++)
+ fl->links[i] = (u32)intr_qh | EHCI_PTR_QH;
+ writel(&cntl->regs->periodiclistbase, (u32)fl);
+
+ // Set async list to point to primary async queue head
+ memset(async_qh, 0, sizeof(*async_qh));
+ async_qh->next = (u32)async_qh | EHCI_PTR_QH;
+ async_qh->info1 = QH_HEAD;
+ async_qh->token = QTD_STS_HALT;
+ async_qh->qtd_next = async_qh->alt_next = EHCI_PTR_TERM;
+ cntl->async_qh = async_qh;
+ writel(&cntl->regs->asynclistbase, (u32)async_qh);
+
+ // Enable queues
+ writel(&cntl->regs->usbcmd, cmd | CMD_ASE | CMD_PSE | CMD_RUN);
+
+ // Set default of high speed for root hub.
+ writel(&cntl->regs->configflag, 1);
+ PendingEHCI--;
+
+ // Find devices
+ int count = check_ehci_ports(cntl);
+ ehci_free_pipes(cntl);
+ if (count)
+ // Success
+ return;
+
+ // No devices found - shutdown and free controller.
+ writel(&cntl->regs->usbcmd, cmd & ~CMD_RUN);
+ msleep(4); // 2ms to stop reading memory - XXX
+fail:
+ free(fl);
+ free(intr_qh);
+ free(async_qh);
+ free(cntl);
+}
+
+static void
+ehci_controller_setup(struct pci_device *pci)
+{
+ struct ehci_caps *caps = pci_enable_membar(pci, PCI_BASE_ADDRESS_0);
+ if (!caps)
+ return;
+ u32 hcc_params = readl(&caps->hccparams);
+
+ struct usb_ehci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+ if (!cntl) {
+ warn_noalloc();
+ return;
+ }
+ memset(cntl, 0, sizeof(*cntl));
+ cntl->usb.pci = pci;
+ cntl->usb.type = USB_TYPE_EHCI;
+ cntl->caps = caps;
+ cntl->checkports = readl(&cntl->caps->hcsparams) & HCS_N_PORTS_MASK;
+ cntl->regs = (void*)caps + readb(&caps->caplength);
+ if (hcc_params & HCC_64BIT_ADDR)
+ cntl->regs->ctrldssegment = 0;
+ PendingEHCI++;
+
+ dprintf(1, "EHCI init on dev %pP (regs=%p)\n", pci, cntl->regs);
+
+ pci_enable_busmaster(pci);
+
+ // XXX - check for and disable SMM control?
+
+ run_thread(configure_ehci, cntl);
+}
+
+void
+ehci_setup(void)
+{
+ if (! CONFIG_USB_EHCI)
+ return;
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_EHCI)
+ ehci_controller_setup(pci);
+ }
+}
+
+// Wait for all EHCI controllers to initialize. This forces OHCI/UHCI
+// setup to always be after any EHCI ports are routed to EHCI.
+void
+ehci_wait_controllers(void)
+{
+ while (CONFIG_USB_EHCI && CONFIG_THREADS && PendingEHCI)
+ yield();
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+// Setup fields in qh
+static void
+ehci_desc2pipe(struct ehci_pipe *pipe, struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
+
+ pipe->qh.info1 = ((pipe->pipe.maxpacket << QH_MAXPACKET_SHIFT)
+ | (pipe->pipe.speed << QH_SPEED_SHIFT)
+ | (pipe->pipe.ep << QH_EP_SHIFT)
+ | (pipe->pipe.devaddr << QH_DEVADDR_SHIFT));
+
+ pipe->qh.info2 = (1 << QH_MULT_SHIFT);
+ struct usbdevice_s *hubdev = usbdev->hub->usbdev;
+ if (hubdev) {
+ struct ehci_pipe *hpipe = container_of(
+ hubdev->defpipe, struct ehci_pipe, pipe);
+ if (hpipe->pipe.speed == USB_HIGHSPEED)
+ pipe->qh.info2 |= (((usbdev->port+1) << QH_HUBPORT_SHIFT)
+ | (hpipe->pipe.devaddr << QH_HUBADDR_SHIFT));
+ else
+ pipe->qh.info2 = hpipe->qh.info2;
+ }
+
+ u8 eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ if (eptype == USB_ENDPOINT_XFER_CONTROL)
+ pipe->qh.info1 |= ((pipe->pipe.speed != USB_HIGHSPEED ? QH_CONTROL : 0)
+ | QH_TOGGLECONTROL);
+ else if (eptype == USB_ENDPOINT_XFER_INT)
+ pipe->qh.info2 |= (0x01 << QH_SMASK_SHIFT) | (0x1c << QH_CMASK_SHIFT);
+}
+
+static struct usb_pipe *
+ehci_alloc_intr_pipe(struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ struct usb_ehci_s *cntl = container_of(
+ usbdev->hub->cntl, struct usb_ehci_s, usb);
+ int frameexp = usb_get_period(usbdev, epdesc);
+ dprintf(7, "ehci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
+
+ if (frameexp > 10)
+ frameexp = 10;
+ int maxpacket = epdesc->wMaxPacketSize;
+ // Determine number of entries needed for 2 timer ticks.
+ int ms = 1<<frameexp;
+ int count = DIV_ROUND_UP(ticks_to_ms(2), ms);
+ struct ehci_pipe *pipe = memalign_low(EHCI_QH_ALIGN, sizeof(*pipe));
+ struct ehci_qtd *tds = memalign_low(EHCI_QTD_ALIGN, sizeof(*tds) * count);
+ void *data = malloc_low(maxpacket * count);
+ if (!pipe || !tds || !data) {
+ warn_noalloc();
+ goto fail;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ memset(tds, 0, sizeof(*tds) * count);
+ memset(data, 0, maxpacket * count);
+ ehci_desc2pipe(pipe, usbdev, epdesc);
+ pipe->next_td = pipe->tds = tds;
+ pipe->data = data;
+ pipe->qh.qtd_next = (u32)tds;
+
+ int i;
+ for (i=0; i<count; i++) {
+ struct ehci_qtd *td = &tds[i];
+ td->qtd_next = (i==count-1 ? (u32)tds : (u32)&td[1]);
+ td->alt_next = EHCI_PTR_TERM;
+ td->token = (ehci_explen(maxpacket) | QTD_STS_ACTIVE
+ | QTD_PID_IN | ehci_maxerr(3));
+ td->buf[0] = (u32)data + maxpacket * i;
+ }
+
+ // Add to interrupt schedule.
+ struct ehci_framelist *fl = (void*)readl(&cntl->regs->periodiclistbase);
+ if (frameexp == 0) {
+ // Add to existing interrupt entry.
+ struct ehci_qh *intr_qh = (void*)(fl->links[0] & ~EHCI_PTR_BITS);
+ pipe->qh.next = intr_qh->next;
+ barrier();
+ intr_qh->next = (u32)&pipe->qh | EHCI_PTR_QH;
+ } else {
+ int startpos = 1<<(frameexp-1);
+ pipe->qh.next = fl->links[startpos];
+ barrier();
+ for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms)
+ fl->links[i] = (u32)&pipe->qh | EHCI_PTR_QH;
+ }
+
+ return &pipe->pipe;
+fail:
+ free(pipe);
+ free(tds);
+ free(data);
+ return NULL;
+}
+
+struct usb_pipe *
+ehci_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *upipe
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ if (! CONFIG_USB_EHCI)
+ return NULL;
+ usb_add_freelist(upipe);
+ if (!epdesc)
+ return NULL;
+ u8 eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ if (eptype == USB_ENDPOINT_XFER_INT)
+ return ehci_alloc_intr_pipe(usbdev, epdesc);
+ struct usb_ehci_s *cntl = container_of(
+ usbdev->hub->cntl, struct usb_ehci_s, usb);
+ dprintf(7, "ehci_alloc_async_pipe %p %d\n", &cntl->usb, eptype);
+
+ struct usb_pipe *usbpipe = usb_get_freelist(&cntl->usb, eptype);
+ if (usbpipe) {
+ // Use previously allocated pipe.
+ struct ehci_pipe *pipe = container_of(usbpipe, struct ehci_pipe, pipe);
+ ehci_desc2pipe(pipe, usbdev, epdesc);
+ pipe->qh.token = 0;
+ return usbpipe;
+ }
+
+ // Allocate a new queue head.
+ struct ehci_pipe *pipe;
+ if (eptype == USB_ENDPOINT_XFER_CONTROL)
+ pipe = memalign_tmphigh(EHCI_QH_ALIGN, sizeof(*pipe));
+ else
+ pipe = memalign_low(EHCI_QH_ALIGN, sizeof(*pipe));
+ if (!pipe) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ ehci_desc2pipe(pipe, usbdev, epdesc);
+ pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM;
+
+ // Add queue head to controller list.
+ struct ehci_qh *async_qh = cntl->async_qh;
+ pipe->qh.next = async_qh->next;
+ barrier();
+ async_qh->next = (u32)&pipe->qh | EHCI_PTR_QH;
+ return &pipe->pipe;
+}
+
+static void
+ehci_reset_pipe(struct ehci_pipe *pipe)
+{
+ SET_LOWFLAT(pipe->qh.qtd_next, EHCI_PTR_TERM);
+ SET_LOWFLAT(pipe->qh.alt_next, EHCI_PTR_TERM);
+ barrier();
+ SET_LOWFLAT(pipe->qh.token, GET_LOWFLAT(pipe->qh.token) & QTD_TOGGLE);
+}
+
+static int
+ehci_wait_td(struct ehci_pipe *pipe, struct ehci_qtd *td, u32 end)
+{
+ u32 status;
+ for (;;) {
+ status = td->token;
+ if (!(status & QTD_STS_ACTIVE))
+ break;
+ if (timer_check(end)) {
+ u32 cur = GET_LOWFLAT(pipe->qh.current);
+ u32 tok = GET_LOWFLAT(pipe->qh.token);
+ u32 next = GET_LOWFLAT(pipe->qh.qtd_next);
+ warn_timeout();
+ dprintf(1, "ehci pipe=%p cur=%08x tok=%08x next=%x td=%p status=%x\n"
+ , pipe, cur, tok, next, td, status);
+ ehci_reset_pipe(pipe);
+ struct usb_ehci_s *cntl = container_of(
+ GET_LOWFLAT(pipe->pipe.cntl), struct usb_ehci_s, usb);
+ ehci_waittick(cntl);
+ return -1;
+ }
+ yield();
+ }
+ if (status & QTD_STS_HALT) {
+ dprintf(1, "ehci_wait_td error - status=%x\n", status);
+ ehci_reset_pipe(pipe);
+ return -2;
+ }
+ return 0;
+}
+
+static void
+ehci_fill_tdbuf(struct ehci_qtd *td, u32 dest, int transfer)
+{
+ u32 *pos = td->buf, end = dest + transfer;
+ for (; dest < end; dest = ALIGN_DOWN(dest + PAGE_SIZE, PAGE_SIZE))
+ *pos++ = dest;
+}
+
+#define STACKQTDS 6
+
+int
+ehci_send_pipe(struct usb_pipe *p, int dir, const void *cmd
+ , void *data, int datasize)
+{
+ if (! CONFIG_USB_EHCI)
+ return -1;
+ struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
+ dprintf(7, "ehci_send_pipe qh=%p dir=%d data=%p size=%d\n"
+ , &pipe->qh, dir, data, datasize);
+
+ // Allocate tds on stack (with required alignment)
+ u8 tdsbuf[sizeof(struct ehci_qtd) * STACKQTDS + EHCI_QTD_ALIGN - 1];
+ struct ehci_qtd *tds = (void*)ALIGN((u32)tdsbuf, EHCI_QTD_ALIGN), *td = tds;
+ memset(tds, 0, sizeof(*tds) * STACKQTDS);
+
+ // Setup transfer descriptors
+ u16 maxpacket = GET_LOWFLAT(pipe->pipe.maxpacket);
+ u32 toggle = 0;
+ if (cmd) {
+ // Send setup pid on control transfers
+ td->qtd_next = (u32)MAKE_FLATPTR(GET_SEG(SS), td+1);
+ td->alt_next = EHCI_PTR_TERM;
+ td->token = (ehci_explen(USB_CONTROL_SETUP_SIZE) | QTD_STS_ACTIVE
+ | QTD_PID_SETUP | ehci_maxerr(3));
+ ehci_fill_tdbuf(td, (u32)cmd, USB_CONTROL_SETUP_SIZE);
+ td++;
+ toggle = QTD_TOGGLE;
+ }
+ u32 dest = (u32)data, dataend = dest + datasize;
+ while (dest < dataend) {
+ // Send data pids
+ if (td >= &tds[STACKQTDS]) {
+ warn_noalloc();
+ return -1;
+ }
+ int maxtransfer = 5*PAGE_SIZE - (dest & (PAGE_SIZE-1));
+ int transfer = dataend - dest;
+ if (transfer > maxtransfer)
+ transfer = ALIGN_DOWN(maxtransfer, maxpacket);
+ td->qtd_next = (u32)MAKE_FLATPTR(GET_SEG(SS), td+1);
+ td->alt_next = EHCI_PTR_TERM;
+ td->token = (ehci_explen(transfer) | toggle | QTD_STS_ACTIVE
+ | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3));
+ ehci_fill_tdbuf(td, dest, transfer);
+ td++;
+ dest += transfer;
+ }
+ if (cmd) {
+ // Send status pid on control transfers
+ if (td >= &tds[STACKQTDS]) {
+ warn_noalloc();
+ return -1;
+ }
+ td->qtd_next = EHCI_PTR_TERM;
+ td->alt_next = EHCI_PTR_TERM;
+ td->token = (QTD_TOGGLE | QTD_STS_ACTIVE
+ | (dir ? QTD_PID_OUT : QTD_PID_IN) | ehci_maxerr(3));
+ td++;
+ }
+
+ // Transfer data
+ (td-1)->qtd_next = EHCI_PTR_TERM;
+ barrier();
+ SET_LOWFLAT(pipe->qh.qtd_next, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
+ u32 end = timer_calc(usb_xfer_time(p, datasize));
+ int i;
+ for (i=0, td=tds; i<STACKQTDS; i++, td++) {
+ int ret = ehci_wait_td(pipe, td, end);
+ if (ret)
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ehci_poll_intr(struct usb_pipe *p, void *data)
+{
+ ASSERT16();
+ if (! CONFIG_USB_EHCI)
+ return -1;
+ struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
+ struct ehci_qtd *td = GET_LOWFLAT(pipe->next_td);
+ u32 token = GET_LOWFLAT(td->token);
+ if (token & QTD_STS_ACTIVE)
+ // No intrs found.
+ return -1;
+ // XXX - check for errors.
+
+ // Copy data.
+ int maxpacket = GET_LOWFLAT(pipe->pipe.maxpacket);
+ int pos = td - GET_LOWFLAT(pipe->tds);
+ void *tddata = GET_LOWFLAT(pipe->data) + maxpacket * pos;
+ memcpy_far(GET_SEG(SS), data, SEG_LOW, LOWFLAT2LOW(tddata), maxpacket);
+
+ // Reenable this td.
+ struct ehci_qtd *next = (void*)(GET_LOWFLAT(td->qtd_next) & ~EHCI_PTR_BITS);
+ SET_LOWFLAT(pipe->next_td, next);
+ SET_LOWFLAT(td->buf[0], (u32)tddata);
+ barrier();
+ SET_LOWFLAT(td->token, (ehci_explen(maxpacket) | QTD_STS_ACTIVE
+ | QTD_PID_IN | ehci_maxerr(3)));
+
+ return 0;
+}
diff --git a/roms/seabios-hppa/src/hw/usb-ehci.h b/roms/seabios-hppa/src/hw/usb-ehci.h
new file mode 100644
index 000000000..0442188b2
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-ehci.h
@@ -0,0 +1,177 @@
+#ifndef __USB_EHCI_H
+#define __USB_EHCI_H
+
+// usb-ehci.c
+void ehci_setup(void);
+void ehci_wait_controllers(void);
+struct usbdevice_s;
+struct usb_endpoint_descriptor;
+struct usb_pipe;
+struct usb_pipe *ehci_realloc_pipe(struct usbdevice_s *usbdev
+ , struct usb_pipe *upipe
+ , struct usb_endpoint_descriptor *epdesc);
+int ehci_send_pipe(struct usb_pipe *p, int dir, const void *cmd
+ , void *data, int datasize);
+int ehci_poll_intr(struct usb_pipe *p, void *data);
+
+
+/****************************************************************
+ * ehci structs and flags
+ ****************************************************************/
+
+struct ehci_caps {
+ u8 caplength;
+ u8 reserved_01;
+ u16 hciversion;
+ u32 hcsparams;
+ u32 hccparams;
+ u64 portroute;
+} PACKED;
+
+#define HCC_64BIT_ADDR 1
+
+#define HCS_N_PORTS_MASK 0xf
+
+struct ehci_regs {
+ u32 usbcmd;
+ u32 usbsts;
+ u32 usbintr;
+ u32 frindex;
+ u32 ctrldssegment;
+ u32 periodiclistbase;
+ u32 asynclistbase;
+ u32 reserved[9];
+ u32 configflag;
+ u32 portsc[0];
+} PACKED;
+
+#define CMD_PARK (1<<11)
+#define CMD_PARK_CNT(c) (((c)>>8)&3)
+#define CMD_LRESET (1<<7)
+#define CMD_IAAD (1<<6)
+#define CMD_ASE (1<<5)
+#define CMD_PSE (1<<4)
+#define CMD_HCRESET (1<<1)
+#define CMD_RUN (1<<0)
+
+#define STS_ASS (1<<15)
+#define STS_PSS (1<<14)
+#define STS_RECL (1<<13)
+#define STS_HALT (1<<12)
+#define STS_IAA (1<<5)
+#define STS_FATAL (1<<4)
+#define STS_FLR (1<<3)
+#define STS_PCD (1<<2)
+#define STS_ERR (1<<1)
+#define STS_INT (1<<0)
+
+#define FLAG_CF (1<<0)
+
+#define PORT_WKOC_E (1<<22)
+#define PORT_WKDISC_E (1<<21)
+#define PORT_WKCONN_E (1<<20)
+#define PORT_TEST_PKT (0x4<<16)
+#define PORT_LED_OFF (0<<14)
+#define PORT_LED_AMBER (1<<14)
+#define PORT_LED_GREEN (2<<14)
+#define PORT_LED_MASK (3<<14)
+#define PORT_OWNER (1<<13)
+#define PORT_POWER (1<<12)
+#define PORT_LINESTATUS_MASK (3<<10)
+#define PORT_LINESTATUS_KSTATE (1<<10)
+#define PORT_RESET (1<<8)
+#define PORT_SUSPEND (1<<7)
+#define PORT_RESUME (1<<6)
+#define PORT_OCC (1<<5)
+#define PORT_OC (1<<4)
+#define PORT_PEC (1<<3)
+#define PORT_PE (1<<2)
+#define PORT_CSC (1<<1)
+#define PORT_CONNECT (1<<0)
+#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
+
+
+#define EHCI_QH_ALIGN 128 // Can't span a 4K boundary, so increase from 32
+
+struct ehci_qh {
+ u32 next;
+ u32 info1;
+ u32 info2;
+ u32 current;
+
+ u32 qtd_next;
+ u32 alt_next;
+ u32 token;
+ u32 buf[5];
+ u32 buf_hi[5];
+} PACKED;
+
+#define QH_CONTROL (1 << 27)
+#define QH_MAXPACKET_SHIFT 16
+#define QH_MAXPACKET_MASK (0x7ff << QH_MAXPACKET_SHIFT)
+#define QH_HEAD (1 << 15)
+#define QH_TOGGLECONTROL (1 << 14)
+#define QH_SPEED_SHIFT 12
+#define QH_SPEED_MASK (0x3 << QH_SPEED_SHIFT)
+#define QH_EP_SHIFT 8
+#define QH_EP_MASK (0xf << QH_EP_SHIFT)
+#define QH_DEVADDR_SHIFT 0
+#define QH_DEVADDR_MASK (0x7f << QH_DEVADDR_SHIFT)
+
+#define QH_SMASK_SHIFT 0
+#define QH_SMASK_MASK (0xff << QH_SMASK_SHIFT)
+#define QH_CMASK_SHIFT 8
+#define QH_CMASK_MASK (0xff << QH_CMASK_SHIFT)
+#define QH_HUBADDR_SHIFT 16
+#define QH_HUBADDR_MASK (0x7f << QH_HUBADDR_SHIFT)
+#define QH_HUBPORT_SHIFT 23
+#define QH_HUBPORT_MASK (0x7f << QH_HUBPORT_SHIFT)
+#define QH_MULT_SHIFT 30
+#define QH_MULT_MASK (0x3 << QH_MULT_SHIFT)
+
+#define EHCI_PTR_BITS 0x001F
+#define EHCI_PTR_TERM 0x0001
+#define EHCI_PTR_QH 0x0002
+
+
+#define EHCI_QTD_ALIGN 64 // Can't span a 4K boundary, so increase from 32
+
+struct ehci_qtd {
+ u32 qtd_next;
+ u32 alt_next;
+ u32 token;
+ u32 buf[5];
+ u32 buf_hi[5];
+ /* keep struct size a multiple of 64 bytes, as we're allocating
+ arrays. Without this padding, the second qtd could have the
+ wrong alignment. */
+} PACKED __aligned(EHCI_QTD_ALIGN);
+
+#define QTD_TOGGLE (1 << 31)
+#define QTD_LENGTH_SHIFT 16
+#define QTD_LENGTH_MASK (0x7fff << QTD_LENGTH_SHIFT)
+#define QTD_CERR_SHIFT 10
+#define QTD_CERR_MASK (0x3 << QTD_CERR_SHIFT)
+#define QTD_IOC (1 << 15)
+#define QTD_PID_OUT (0x0 << 8)
+#define QTD_PID_IN (0x1 << 8)
+#define QTD_PID_SETUP (0x2 << 8)
+#define QTD_STS_ACTIVE (1 << 7)
+#define QTD_STS_HALT (1 << 6)
+#define QTD_STS_DBE (1 << 5)
+#define QTD_STS_BABBLE (1 << 4)
+#define QTD_STS_XACT (1 << 3)
+#define QTD_STS_MMF (1 << 2)
+#define QTD_STS_STS (1 << 1)
+#define QTD_STS_PING (1 << 0)
+
+#define ehci_explen(len) (((len) << QTD_LENGTH_SHIFT) & QTD_LENGTH_MASK)
+
+#define ehci_maxerr(err) (((err) << QTD_CERR_SHIFT) & QTD_CERR_MASK)
+
+
+struct ehci_framelist {
+ u32 links[1024];
+} PACKED;
+
+#endif // usb-ehci.h
diff --git a/roms/seabios-hppa/src/hw/usb-hid.c b/roms/seabios-hppa/src/hw/usb-hid.c
new file mode 100644
index 000000000..92c6b197b
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-hid.c
@@ -0,0 +1,453 @@
+// Code for handling USB Human Interface Devices (HID).
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "config.h" // CONFIG_*
+#include "output.h" // dprintf
+#include "ps2port.h" // ATKBD_CMD_GETID
+#include "usb.h" // usb_ctrlrequest
+#include "usb-hid.h" // usb_keyboard_setup
+#include "util.h" // process_key
+
+struct usb_pipe *keyboard_pipe VARFSEG;
+struct usb_pipe *mouse_pipe VARFSEG;
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+// Send USB HID protocol message.
+static int
+set_protocol(struct usb_pipe *pipe, u16 val)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ req.bRequest = HID_REQ_SET_PROTOCOL;
+ req.wValue = val;
+ req.wIndex = 0;
+ req.wLength = 0;
+ return usb_send_default_control(pipe, &req, NULL);
+}
+
+// Send USB HID SetIdle request.
+static int
+set_idle(struct usb_pipe *pipe, int ms)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ req.bRequest = HID_REQ_SET_IDLE;
+ req.wValue = (ms/4)<<8;
+ req.wIndex = 0;
+ req.wLength = 0;
+ return usb_send_default_control(pipe, &req, NULL);
+}
+
+#define KEYREPEATWAITMS 500
+#define KEYREPEATMS 33
+
+// Format of USB keyboard event data
+struct keyevent {
+ u8 modifiers;
+ u8 reserved;
+ u8 keys[6];
+};
+
+#define MAX_KBD_EVENT 16
+
+static int
+usb_kbd_setup(struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ if (! CONFIG_USB_KEYBOARD)
+ return -1;
+ if (keyboard_pipe)
+ // XXX - this enables the first found keyboard (could be random)
+ return -1;
+
+ if (epdesc->wMaxPacketSize < sizeof(struct keyevent)
+ || epdesc->wMaxPacketSize > MAX_KBD_EVENT) {
+ dprintf(1, "USB keyboard wMaxPacketSize=%d; aborting\n"
+ , epdesc->wMaxPacketSize);
+ return -1;
+ }
+
+ // Enable "boot" protocol.
+ int ret = set_protocol(usbdev->defpipe, 0);
+ if (ret)
+ return -1;
+ // Periodically send reports to enable key repeat.
+ ret = set_idle(usbdev->defpipe, KEYREPEATMS);
+ if (ret)
+ dprintf(3, "Warning: Failed to set key repeat rate\n");
+
+ keyboard_pipe = usb_alloc_pipe(usbdev, epdesc);
+ if (!keyboard_pipe)
+ return -1;
+
+ dprintf(1, "USB keyboard initialized\n");
+ return 0;
+}
+
+// Format of USB mouse event data
+struct mouseevent {
+ u8 buttons;
+ u8 x, y;
+};
+
+#define MAX_MOUSE_EVENT 8
+
+static int
+usb_mouse_setup(struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ if (! CONFIG_USB_MOUSE)
+ return -1;
+ if (mouse_pipe)
+ // XXX - this enables the first found mouse (could be random)
+ return -1;
+
+ if (epdesc->wMaxPacketSize < sizeof(struct mouseevent)
+ || epdesc->wMaxPacketSize > MAX_MOUSE_EVENT) {
+ dprintf(1, "USB mouse wMaxPacketSize=%d; aborting\n"
+ , epdesc->wMaxPacketSize);
+ return -1;
+ }
+
+ // Enable "boot" protocol.
+ int ret = set_protocol(usbdev->defpipe, 0);
+ if (ret)
+ return -1;
+
+ mouse_pipe = usb_alloc_pipe(usbdev, epdesc);
+ if (!mouse_pipe)
+ return -1;
+
+ dprintf(1, "USB mouse initialized\n");
+ return 0;
+}
+
+// Initialize a found USB HID device (if applicable).
+int
+usb_hid_setup(struct usbdevice_s *usbdev)
+{
+ if (! CONFIG_USB_KEYBOARD && ! CONFIG_USB_MOUSE)
+ return -1;
+ dprintf(2, "usb_hid_setup %p\n", usbdev->defpipe);
+
+ struct usb_interface_descriptor *iface = usbdev->iface;
+ if (iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT)
+ // Doesn't support boot protocol.
+ return -1;
+
+ // Find intr in endpoint.
+ struct usb_endpoint_descriptor *epdesc = usb_find_desc(
+ usbdev, USB_ENDPOINT_XFER_INT, USB_DIR_IN);
+ if (!epdesc) {
+ dprintf(1, "No usb hid intr in?\n");
+ return -1;
+ }
+
+ if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD)
+ return usb_kbd_setup(usbdev, epdesc);
+ if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
+ return usb_mouse_setup(usbdev, epdesc);
+ return -1;
+}
+
+
+/****************************************************************
+ * Keyboard events
+ ****************************************************************/
+
+// Mapping from USB key id to ps2 key sequence.
+static u16 KeyToScanCode[] VAR16 = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020,
+ 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
+ 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014,
+ 0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
+ 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b,
+ 0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
+ 0x001b, 0x002b, 0x0000, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034,
+ 0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xe037, 0x0046,
+ 0xe145, 0xe052, 0xe047, 0xe049, 0xe053, 0xe04f, 0xe051, 0xe04d,
+ 0xe04b, 0xe050, 0xe048, 0x0045, 0xe035, 0x0037, 0x004a, 0x004e,
+ 0xe01c, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
+ 0x0048, 0x0049, 0x0052, 0x0053
+};
+
+// Mapping from USB modifier id to ps2 key sequence.
+static u16 ModifierToScanCode[] VAR16 = {
+ //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
+ 0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
+};
+
+#define RELEASEBIT 0x80
+
+// Translate data from KeyToScanCode[] to calls to process_key().
+static void
+prockeys(u16 scancode, u8 key_release, u8 mods)
+{
+ if (scancode > 0xff) {
+ if (scancode == 0xe145) {
+ // XXX - a real AT keyboard would immediately send the key release
+ if (mods & ((1<<0) | (1<<4))) {
+ // Cntr+Break key
+ process_key(0xe0);
+ process_key(0x46 | key_release);
+ } else {
+ // Pause key
+ process_key(0xe1);
+ process_key(0x1d | key_release);
+ process_key(0x45 | key_release);
+ }
+ return;
+ } else if (scancode == 0xe037 && mods & ((1<<2) | (1<<6))) {
+ // Alt+SysReq key
+ process_key(0x54 | key_release);
+ return;
+ }
+ process_key(0xe0);
+ }
+ process_key(scancode | key_release);
+}
+
+// Handle a USB key press/release event.
+static void
+procscankey(u8 key, u8 key_release, u8 mods)
+{
+ if (key >= ARRAY_SIZE(KeyToScanCode))
+ return;
+ u16 scancode = GET_GLOBAL(KeyToScanCode[key]);
+ if (scancode)
+ prockeys(scancode, key_release, mods);
+}
+
+// Handle a USB modifier press/release event.
+static void
+procmodkey(u8 mods, u8 key_release)
+{
+ int i;
+ for (i=0; mods; i++)
+ if (mods & (1<<i)) {
+ // Modifier key change.
+ prockeys(GET_GLOBAL(ModifierToScanCode[i]), key_release, 0);
+ mods &= ~(1<<i);
+ }
+}
+
+struct usbkeyinfo {
+ union {
+ struct {
+ u8 modifiers;
+ u8 repeatcount;
+ u8 keys[6];
+ };
+ u64 data;
+ };
+};
+struct usbkeyinfo LastUSBkey VARLOW;
+
+// Process USB keyboard data.
+static void
+handle_key(struct keyevent *data)
+{
+ dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
+
+ // Load old keys.
+ struct usbkeyinfo old;
+ old.data = GET_LOW(LastUSBkey.data);
+
+ // Check for keys no longer pressed.
+ int addpos = 0;
+ int i;
+ for (i=0; i<ARRAY_SIZE(old.keys); i++) {
+ u8 key = old.keys[i];
+ if (!key)
+ break;
+ int j;
+ for (j=0;; j++) {
+ if (j>=ARRAY_SIZE(data->keys)) {
+ // Key released.
+ procscankey(key, RELEASEBIT, data->modifiers);
+ if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1])
+ // Last pressed key released - disable repeat.
+ old.repeatcount = 0xff;
+ break;
+ }
+ if (data->keys[j] == key) {
+ // Key still pressed.
+ data->keys[j] = 0;
+ old.keys[addpos++] = key;
+ break;
+ }
+ }
+ }
+ procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT);
+
+ // Process new keys
+ procmodkey(data->modifiers & ~old.modifiers, 0);
+ old.modifiers = data->modifiers;
+ for (i=0; i<ARRAY_SIZE(data->keys); i++) {
+ u8 key = data->keys[i];
+ if (!key)
+ continue;
+ // New key pressed.
+ procscankey(key, 0, data->modifiers);
+ old.keys[addpos++] = key;
+ old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
+ }
+ if (addpos < ARRAY_SIZE(old.keys))
+ old.keys[addpos] = 0;
+
+ // Check for key repeat event.
+ if (addpos) {
+ if (!old.repeatcount)
+ procscankey(old.keys[addpos-1], 0, data->modifiers);
+ else if (old.repeatcount != 0xff)
+ old.repeatcount--;
+ }
+
+ // Update old keys
+ SET_LOW(LastUSBkey.data, old.data);
+}
+
+// Check if a USB keyboard event is pending and process it if so.
+static void
+usb_check_key(void)
+{
+ if (! CONFIG_USB_KEYBOARD)
+ return;
+ struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
+ if (!pipe)
+ return;
+
+ for (;;) {
+ u8 data[MAX_KBD_EVENT];
+ int ret = usb_poll_intr(pipe, data);
+ if (ret)
+ break;
+ handle_key((void*)data);
+ }
+}
+
+// Test if USB keyboard is active.
+inline int
+usb_kbd_active(void)
+{
+ if (! CONFIG_USB_KEYBOARD)
+ return 0;
+ return GET_GLOBAL(keyboard_pipe) != NULL;
+}
+
+// Handle a ps2 style keyboard command.
+inline int
+usb_kbd_command(int command, u8 *param)
+{
+ if (! CONFIG_USB_KEYBOARD)
+ return -1;
+ dprintf(9, "usb keyboard cmd=%x\n", command);
+ switch (command) {
+ case ATKBD_CMD_GETID:
+ // Return the id of a standard AT keyboard.
+ param[0] = 0xab;
+ param[1] = 0x83;
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+
+/****************************************************************
+ * Mouse events
+ ****************************************************************/
+
+// Process USB mouse data.
+static void
+handle_mouse(struct mouseevent *data)
+{
+ dprintf(9, "Got mouse b=%x x=%x y=%x\n", data->buttons, data->x, data->y);
+
+ s8 x = data->x, y = -data->y;
+ u8 flag = ((data->buttons & 0x7) | (1<<3)
+ | (x & 0x80 ? (1<<4) : 0) | (y & 0x80 ? (1<<5) : 0));
+ process_mouse(flag);
+ process_mouse(x);
+ process_mouse(y);
+}
+
+// Check if a USB mouse event is pending and process it if so.
+static void
+usb_check_mouse(void)
+{
+ if (! CONFIG_USB_MOUSE)
+ return;
+ struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe);
+ if (!pipe)
+ return;
+
+ for (;;) {
+ u8 data[MAX_MOUSE_EVENT];
+ int ret = usb_poll_intr(pipe, data);
+ if (ret)
+ break;
+ handle_mouse((void*)data);
+ }
+}
+
+// Test if USB mouse is active.
+inline int
+usb_mouse_active(void)
+{
+ if (! CONFIG_USB_MOUSE)
+ return 0;
+ return GET_GLOBAL(mouse_pipe) != NULL;
+}
+
+// Handle a ps2 style mouse command.
+inline int
+usb_mouse_command(int command, u8 *param)
+{
+ if (! CONFIG_USB_MOUSE)
+ return -1;
+ dprintf(9, "usb mouse cmd=%x\n", command);
+ switch (command) {
+ case PSMOUSE_CMD_ENABLE:
+ case PSMOUSE_CMD_DISABLE:
+ case PSMOUSE_CMD_SETSCALE11:
+ return 0;
+ case PSMOUSE_CMD_SETSCALE21:
+ case PSMOUSE_CMD_SETRATE:
+ case PSMOUSE_CMD_SETRES:
+ // XXX
+ return 0;
+ case PSMOUSE_CMD_RESET_BAT:
+ case PSMOUSE_CMD_GETID:
+ // Return the id of a standard AT mouse.
+ param[0] = 0xaa;
+ param[1] = 0x00;
+ return 0;
+
+ case PSMOUSE_CMD_GETINFO:
+ param[0] = 0x00;
+ param[1] = 4;
+ param[2] = 100;
+ return 0;
+
+ default:
+ return -1;
+ }
+}
+
+// Check for USB events pending - called periodically from timer interrupt.
+void
+usb_check_event(void)
+{
+ usb_check_key();
+ usb_check_mouse();
+}
diff --git a/roms/seabios-hppa/src/hw/usb-hid.h b/roms/seabios-hppa/src/hw/usb-hid.h
new file mode 100644
index 000000000..fd7b8f8be
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-hid.h
@@ -0,0 +1,29 @@
+#ifndef __USB_HID_H
+#define __USB_HID_H
+
+// usb-hid.c
+struct usbdevice_s;
+int usb_hid_setup(struct usbdevice_s *usbdev);
+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);
+
+
+/****************************************************************
+ * hid flags
+ ****************************************************************/
+
+#define USB_INTERFACE_SUBCLASS_BOOT 1
+#define USB_INTERFACE_PROTOCOL_KEYBOARD 1
+#define USB_INTERFACE_PROTOCOL_MOUSE 2
+
+#define HID_REQ_GET_REPORT 0x01
+#define HID_REQ_GET_IDLE 0x02
+#define HID_REQ_GET_PROTOCOL 0x03
+#define HID_REQ_SET_REPORT 0x09
+#define HID_REQ_SET_IDLE 0x0A
+#define HID_REQ_SET_PROTOCOL 0x0B
+
+#endif // ush-hid.h
diff --git a/roms/seabios-hppa/src/hw/usb-hub.c b/roms/seabios-hppa/src/hw/usb-hub.c
new file mode 100644
index 000000000..54e341b73
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-hub.c
@@ -0,0 +1,205 @@
+// Code for handling standard USB hubs.
+//
+// Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_USB_HUB
+#include "output.h" // dprintf
+#include "string.h" // memset
+#include "usb.h" // struct usb_s
+#include "usb-hub.h" // struct usb_hub_descriptor
+#include "util.h" // timer_calc
+
+static int
+get_hub_desc(struct usb_pipe *pipe, struct usb_hub_descriptor *desc)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE;
+ req.bRequest = USB_REQ_GET_DESCRIPTOR;
+ if (pipe->speed == USB_SUPERSPEED)
+ req.wValue = USB_DT_HUB3<<8;
+ else
+ req.wValue = USB_DT_HUB<<8;
+ req.wIndex = 0;
+ req.wLength = sizeof(*desc);
+ return usb_send_default_control(pipe, &req, desc);
+}
+
+static int
+set_hub_depth(struct usb_pipe *pipe, u16 depth)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE;
+ req.bRequest = HUB_REQ_SET_HUB_DEPTH;
+ req.wValue = depth;
+ req.wIndex = 0;
+ req.wLength = 0;
+ return usb_send_default_control(pipe, &req, NULL);
+}
+
+static int
+set_port_feature(struct usbhub_s *hub, int port, int feature)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
+ req.bRequest = USB_REQ_SET_FEATURE;
+ req.wValue = feature;
+ req.wIndex = port + 1;
+ req.wLength = 0;
+ mutex_lock(&hub->lock);
+ int ret = usb_send_default_control(hub->usbdev->defpipe, &req, NULL);
+ mutex_unlock(&hub->lock);
+ return ret;
+}
+
+static int
+clear_port_feature(struct usbhub_s *hub, int port, int feature)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
+ req.bRequest = USB_REQ_CLEAR_FEATURE;
+ req.wValue = feature;
+ req.wIndex = port + 1;
+ req.wLength = 0;
+ mutex_lock(&hub->lock);
+ int ret = usb_send_default_control(hub->usbdev->defpipe, &req, NULL);
+ mutex_unlock(&hub->lock);
+ return ret;
+}
+
+static int
+get_port_status(struct usbhub_s *hub, int port, struct usb_port_status *sts)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER;
+ req.bRequest = USB_REQ_GET_STATUS;
+ req.wValue = 0;
+ req.wIndex = port + 1;
+ req.wLength = sizeof(*sts);
+ mutex_lock(&hub->lock);
+ int ret = usb_send_default_control(hub->usbdev->defpipe, &req, sts);
+ mutex_unlock(&hub->lock);
+ return ret;
+}
+
+// Check if device attached to port
+static int
+usb_hub_detect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_port_status sts;
+ int ret = get_port_status(hub, port, &sts);
+ if (ret) {
+ dprintf(1, "Failure on hub port %d detect\n", port);
+ return -1;
+ }
+ return (sts.wPortStatus & USB_PORT_STAT_CONNECTION) ? 1 : 0;
+}
+
+// Disable port
+static void
+usb_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+ int ret = clear_port_feature(hub, port, USB_PORT_FEAT_ENABLE);
+ if (ret)
+ dprintf(1, "Failure on hub port %d disconnect\n", port);
+}
+
+// Reset device on port
+static int
+usb_hub_reset(struct usbhub_s *hub, u32 port)
+{
+ int ret = set_port_feature(hub, port, USB_PORT_FEAT_RESET);
+ if (ret)
+ goto fail;
+
+ // Wait for reset to complete.
+ struct usb_port_status sts;
+ u32 end = timer_calc(USB_TIME_DRST * 2);
+ for (;;) {
+ ret = get_port_status(hub, port, &sts);
+ if (ret)
+ goto fail;
+ if (!(sts.wPortStatus & USB_PORT_STAT_RESET)
+ && (hub->usbdev->speed != USB_SUPERSPEED
+ || !(sts.wPortStatus & USB_PORT_STAT_LINK_MASK)))
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ goto fail;
+ }
+ msleep(5);
+ }
+
+ // Reset complete.
+ if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION))
+ // Device no longer present
+ return -1;
+
+ if (hub->usbdev->speed == USB_SUPERSPEED)
+ return USB_SUPERSPEED;
+ return ((sts.wPortStatus & USB_PORT_STAT_SPEED_MASK)
+ >> USB_PORT_STAT_SPEED_SHIFT);
+
+fail:
+ dprintf(1, "Failure on hub port %d reset\n", port);
+ usb_hub_disconnect(hub, port);
+ return -1;
+}
+
+static struct usbhub_op_s HubOp = {
+ .detect = usb_hub_detect,
+ .reset = usb_hub_reset,
+ .disconnect = usb_hub_disconnect,
+};
+
+// Configure a usb hub and then find devices connected to it.
+int
+usb_hub_setup(struct usbdevice_s *usbdev)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_USB_HUB)
+ return -1;
+
+ struct usb_hub_descriptor desc;
+ int ret = get_hub_desc(usbdev->defpipe, &desc);
+ if (ret)
+ return ret;
+
+ struct usbhub_s hub;
+ memset(&hub, 0, sizeof(hub));
+ hub.usbdev = usbdev;
+ hub.cntl = usbdev->defpipe->cntl;
+ hub.portcount = desc.bNbrPorts;
+ hub.op = &HubOp;
+
+ if (usbdev->speed == USB_SUPERSPEED) {
+ int depth = 0;
+ struct usbdevice_s *parent = usbdev->hub->usbdev;
+ while (parent) {
+ depth++;
+ parent = parent->hub->usbdev;
+ }
+
+ ret = set_hub_depth(usbdev->defpipe, depth);
+ if (ret)
+ return ret;
+ }
+
+ // Turn on power to ports.
+ int port;
+ for (port=0; port<desc.bNbrPorts; port++) {
+ ret = set_port_feature(&hub, port, USB_PORT_FEAT_POWER);
+ if (ret)
+ return ret;
+ }
+ // Wait for port power to stabilize.
+ msleep(desc.bPwrOn2PwrGood * 2);
+
+ usb_enumerate(&hub);
+
+ dprintf(1, "Initialized USB HUB (%d ports used)\n", hub.devcount);
+ if (hub.devcount)
+ return 0;
+ return -1;
+}
diff --git a/roms/seabios-hppa/src/hw/usb-hub.h b/roms/seabios-hppa/src/hw/usb-hub.h
new file mode 100644
index 000000000..880378ca1
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-hub.h
@@ -0,0 +1,64 @@
+#ifndef __USB_HUB_H
+#define __USB_HUB_H
+
+// usb-hub.c
+struct usbdevice_s;
+int usb_hub_setup(struct usbdevice_s *usbdev);
+
+
+/****************************************************************
+ * hub flags
+ ****************************************************************/
+
+#define USB_DT_HUB (USB_TYPE_CLASS | 0x09)
+#define USB_DT_HUB3 (USB_TYPE_CLASS | 0x0a)
+
+#define HUB_REQ_SET_HUB_DEPTH 0x0C
+
+struct usb_hub_descriptor {
+ u8 bDescLength;
+ u8 bDescriptorType;
+ u8 bNbrPorts;
+ u16 wHubCharacteristics;
+ u8 bPwrOn2PwrGood;
+ u8 bHubContrCurrent;
+ // Variable length fields for DeviceRemovable[], PortPwrCtrlMask[] follow.
+} PACKED;
+
+#define USB_PORT_FEAT_CONNECTION 0
+#define USB_PORT_FEAT_ENABLE 1
+#define USB_PORT_FEAT_SUSPEND 2
+#define USB_PORT_FEAT_OVER_CURRENT 3
+#define USB_PORT_FEAT_RESET 4
+#define USB_PORT_FEAT_POWER 8
+#define USB_PORT_FEAT_LOWSPEED 9
+#define USB_PORT_FEAT_C_CONNECTION 16
+#define USB_PORT_FEAT_C_ENABLE 17
+#define USB_PORT_FEAT_C_SUSPEND 18
+#define USB_PORT_FEAT_C_OVER_CURRENT 19
+#define USB_PORT_FEAT_C_RESET 20
+#define USB_PORT_FEAT_TEST 21
+#define USB_PORT_FEAT_INDICATOR 22
+#define USB_PORT_FEAT_C_PORT_L1 23
+
+struct usb_port_status {
+ u16 wPortStatus;
+ u16 wPortChange;
+} PACKED;
+
+#define USB_PORT_STAT_CONNECTION 0x0001
+#define USB_PORT_STAT_ENABLE 0x0002
+#define USB_PORT_STAT_SUSPEND 0x0004
+#define USB_PORT_STAT_OVERCURRENT 0x0008
+#define USB_PORT_STAT_RESET 0x0010
+#define USB_PORT_STAT_LINK_SHIFT 5
+#define USB_PORT_STAT_LINK_MASK (0x7 << USB_PORT_STAT_LINK_SHIFT)
+#define USB_PORT_STAT_POWER 0x0100
+#define USB_PORT_STAT_SPEED_SHIFT 9
+#define USB_PORT_STAT_SPEED_MASK (0x3 << USB_PORT_STAT_SPEED_SHIFT)
+#define USB_PORT_STAT_LOW_SPEED 0x0200
+#define USB_PORT_STAT_HIGH_SPEED 0x0400
+#define USB_PORT_STAT_TEST 0x0800
+#define USB_PORT_STAT_INDICATOR 0x1000
+
+#endif // ush-hid.h
diff --git a/roms/seabios-hppa/src/hw/usb-msc.c b/roms/seabios-hppa/src/hw/usb-msc.c
new file mode 100644
index 000000000..444f4365c
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-msc.c
@@ -0,0 +1,222 @@
+// Code for handling USB Mass Storage Controller devices.
+//
+// Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBALFLAT
+#include "block.h" // DTYPE_USB
+#include "blockcmd.h" // cdb_read
+#include "config.h" // CONFIG_USB_MSC
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "usb.h" // struct usb_s
+#include "usb-msc.h" // usb_msc_setup
+#include "util.h" // bootprio_find_usb
+
+struct usbdrive_s {
+ struct drive_s drive;
+ struct usb_pipe *bulkin, *bulkout;
+ int lun;
+};
+
+
+/****************************************************************
+ * Bulk-only drive command processing
+ ****************************************************************/
+
+#define USB_CDB_SIZE 12
+
+#define CBW_SIGNATURE 0x43425355 // USBC
+
+struct cbw_s {
+ u32 dCBWSignature;
+ u32 dCBWTag;
+ u32 dCBWDataTransferLength;
+ u8 bmCBWFlags;
+ u8 bCBWLUN;
+ u8 bCBWCBLength;
+ u8 CBWCB[16];
+} PACKED;
+
+#define CSW_SIGNATURE 0x53425355 // USBS
+
+struct csw_s {
+ u32 dCSWSignature;
+ u32 dCSWTag;
+ u32 dCSWDataResidue;
+ u8 bCSWStatus;
+} PACKED;
+
+static int
+usb_msc_send(struct usbdrive_s *udrive_gf, int dir, void *buf, u32 bytes)
+{
+ struct usb_pipe *pipe;
+ if (dir == USB_DIR_OUT)
+ pipe = GET_GLOBALFLAT(udrive_gf->bulkout);
+ else
+ pipe = GET_GLOBALFLAT(udrive_gf->bulkin);
+ return usb_send_bulk(pipe, dir, buf, bytes);
+}
+
+// Low-level usb command transmit function.
+int
+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 buf=%p\n"
+ , op->drive_fl, 0, op->count, op->buf_fl);
+ struct usbdrive_s *udrive_gf = container_of(
+ op->drive_fl, struct usbdrive_s, drive);
+
+ // Setup command block wrapper.
+ struct cbw_s cbw;
+ memset(&cbw, 0, sizeof(cbw));
+ 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 = scsi_is_read(op) ? USB_DIR_IN : USB_DIR_OUT;
+ cbw.bCBWLUN = GET_GLOBALFLAT(udrive_gf->lun);
+ cbw.bCBWCBLength = USB_CDB_SIZE;
+
+ // Transfer cbw to device.
+ int ret = usb_msc_send(udrive_gf, USB_DIR_OUT
+ , MAKE_FLATPTR(GET_SEG(SS), &cbw), sizeof(cbw));
+ if (ret)
+ goto fail;
+
+ // Transfer data to/from device.
+ if (bytes) {
+ ret = usb_msc_send(udrive_gf, cbw.bmCBWFlags, op->buf_fl, bytes);
+ if (ret)
+ goto fail;
+ }
+
+ // Transfer csw info.
+ struct csw_s csw;
+ ret = usb_msc_send(udrive_gf, USB_DIR_IN
+ , MAKE_FLATPTR(GET_SEG(SS), &csw), sizeof(csw));
+ if (ret)
+ goto fail;
+
+ if (!csw.bCSWStatus)
+ return DISK_RET_SUCCESS;
+ if (csw.bCSWStatus == 2)
+ goto fail;
+
+ if (blocksize)
+ op->count -= csw.dCSWDataResidue / blocksize;
+ return DISK_RET_EBADTRACK;
+
+fail:
+ // XXX - reset connection
+ dprintf(1, "USB transmission failed\n");
+ return DISK_RET_EBADTRACK;
+}
+
+static int
+usb_msc_maxlun(struct usb_pipe *pipe)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ req.bRequest = 0xfe;
+ req.wValue = 0;
+ req.wIndex = 0;
+ req.wLength = 1;
+ unsigned char maxlun;
+ int ret = usb_send_default_control(pipe, &req, &maxlun);
+ if (ret)
+ return 0;
+ return maxlun;
+}
+
+static int
+usb_msc_lun_setup(struct usb_pipe *inpipe, struct usb_pipe *outpipe,
+ struct usbdevice_s *usbdev, int lun)
+{
+ // Allocate drive structure.
+ struct usbdrive_s *drive = malloc_fseg(sizeof(*drive));
+ if (!drive) {
+ warn_noalloc();
+ return -1;
+ }
+ memset(drive, 0, sizeof(*drive));
+ if (usb_32bit_pipe(inpipe))
+ drive->drive.type = DTYPE_USB_32;
+ else
+ drive->drive.type = DTYPE_USB;
+ drive->bulkin = inpipe;
+ drive->bulkout = outpipe;
+ drive->lun = lun;
+
+ int prio = bootprio_find_usb(usbdev, lun);
+ int ret = scsi_drive_setup(&drive->drive, "USB MSC", prio, 0, lun);
+ if (ret) {
+ dprintf(1, "Unable to configure USB MSC drive.\n");
+ free(drive);
+ return -1;
+ }
+ return 0;
+}
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+// Configure a usb msc device.
+int
+usb_msc_setup(struct usbdevice_s *usbdev)
+{
+ if (!CONFIG_USB_MSC)
+ return -1;
+
+ // Verify right kind of device
+ struct usb_interface_descriptor *iface = usbdev->iface;
+ if ((iface->bInterfaceSubClass != US_SC_SCSI &&
+ iface->bInterfaceSubClass != US_SC_ATAPI_8070 &&
+ iface->bInterfaceSubClass != US_SC_ATAPI_8020)
+ || iface->bInterfaceProtocol != US_PR_BULK) {
+ dprintf(1, "Unsupported MSC USB device (subclass=%02x proto=%02x)\n"
+ , iface->bInterfaceSubClass, iface->bInterfaceProtocol);
+ return -1;
+ }
+
+ // Find bulk in and bulk out endpoints.
+ struct usb_pipe *inpipe = NULL, *outpipe = NULL;
+ struct usb_endpoint_descriptor *indesc = usb_find_desc(
+ usbdev, USB_ENDPOINT_XFER_BULK, USB_DIR_IN);
+ struct usb_endpoint_descriptor *outdesc = usb_find_desc(
+ usbdev, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT);
+ if (!indesc || !outdesc)
+ goto fail;
+ inpipe = usb_alloc_pipe(usbdev, indesc);
+ outpipe = usb_alloc_pipe(usbdev, outdesc);
+ if (!inpipe || !outpipe)
+ goto fail;
+
+ int maxlun = usb_msc_maxlun(usbdev->defpipe);
+ int lun, pipesused = 0;
+ for (lun = 0; lun < maxlun + 1; lun++) {
+ int ret = usb_msc_lun_setup(inpipe, outpipe, usbdev, lun);
+ if (!ret)
+ pipesused = 1;
+ }
+
+ if (!pipesused)
+ goto fail;
+
+ return 0;
+fail:
+ dprintf(1, "Unable to configure USB MSC device.\n");
+ usb_free_pipe(usbdev, inpipe);
+ usb_free_pipe(usbdev, outpipe);
+ return -1;
+}
diff --git a/roms/seabios-hppa/src/hw/usb-msc.h b/roms/seabios-hppa/src/hw/usb-msc.h
new file mode 100644
index 000000000..ff3c38038
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-msc.h
@@ -0,0 +1,10 @@
+#ifndef __USB_MSC_H
+#define __USB_MSC_H
+
+// usb-msc.c
+struct disk_op_s;
+int usb_process_op(struct disk_op_s *op);
+struct usbdevice_s;
+int usb_msc_setup(struct usbdevice_s *usbdev);
+
+#endif // ush-msc.h
diff --git a/roms/seabios-hppa/src/hw/usb-ohci.c b/roms/seabios-hppa/src/hw/usb-ohci.c
new file mode 100644
index 000000000..90f60e645
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-ohci.c
@@ -0,0 +1,568 @@
+// Code for handling OHCI USB controllers.
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_LOWFLAT
+#include "config.h" // CONFIG_*
+#include "malloc.h" // free
+#include "memmap.h" // PAGE_SIZE
+#include "output.h" // dprintf
+#include "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_OHCI
+#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "string.h" // memset
+#include "usb.h" // struct usb_s
+#include "usb-ehci.h" // ehci_wait_controllers
+#include "usb-ohci.h" // struct ohci_hcca
+#include "util.h" // msleep
+#include "x86.h" // readl
+
+#define FIT (1 << 31)
+
+struct usb_ohci_s {
+ struct usb_s usb;
+ struct ohci_regs *regs;
+};
+
+struct ohci_pipe {
+ struct ohci_ed ed;
+ struct usb_pipe pipe;
+ struct ohci_regs *regs;
+ void *data;
+ int count;
+ struct ohci_td *tds;
+};
+
+
+/****************************************************************
+ * Root hub
+ ****************************************************************/
+
+// Check if device attached to port
+static int
+ohci_hub_detect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb);
+ u32 sts = readl(&cntl->regs->roothub_portstatus[port]);
+ return (sts & RH_PS_CCS) ? 1 : 0;
+}
+
+// Disable port
+static void
+ohci_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb);
+ writel(&cntl->regs->roothub_portstatus[port], RH_PS_CCS|RH_PS_LSDA);
+}
+
+// Reset device on port
+static int
+ohci_hub_reset(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb);
+ writel(&cntl->regs->roothub_portstatus[port], RH_PS_PRS);
+ u32 sts;
+ u32 end = timer_calc(USB_TIME_DRSTR * 2);
+ for (;;) {
+ sts = readl(&cntl->regs->roothub_portstatus[port]);
+ if (!(sts & RH_PS_PRS))
+ // XXX - need to ensure USB_TIME_DRSTR time in reset?
+ break;
+ if (timer_check(end)) {
+ // Timeout.
+ warn_timeout();
+ ohci_hub_disconnect(hub, port);
+ return -1;
+ }
+ yield();
+ }
+
+ if ((sts & (RH_PS_CCS|RH_PS_PES)) != (RH_PS_CCS|RH_PS_PES))
+ // Device no longer present
+ return -1;
+
+ return !!(sts & RH_PS_LSDA);
+}
+
+static struct usbhub_op_s ohci_HubOp = {
+ .detect = ohci_hub_detect,
+ .reset = ohci_hub_reset,
+ .disconnect = ohci_hub_disconnect,
+};
+
+// Find any devices connected to the root hub.
+static int
+check_ohci_ports(struct usb_ohci_s *cntl)
+{
+ ASSERT32FLAT();
+ // Wait for ehci init - in case this is a "companion controller"
+ ehci_wait_controllers();
+ // Turn on power for all devices on roothub.
+ u32 rha = readl(&cntl->regs->roothub_a);
+ rha &= ~(RH_A_PSM | RH_A_OCPM);
+ writel(&cntl->regs->roothub_status, RH_HS_LPSC);
+ writel(&cntl->regs->roothub_b, RH_B_PPCM);
+ msleep((rha >> 24) * 2);
+ // XXX - need to sleep for USB_TIME_SIGATT if just powered up?
+
+ struct usbhub_s hub;
+ memset(&hub, 0, sizeof(hub));
+ hub.cntl = &cntl->usb;
+ hub.portcount = rha & RH_A_NDP;
+ hub.op = &ohci_HubOp;
+ usb_enumerate(&hub);
+ return hub.devcount;
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+// Wait for next USB frame to start - for ensuring safe memory release.
+static void
+ohci_waittick(struct ohci_regs *regs)
+{
+ barrier();
+ struct ohci_hcca *hcca = (void*)regs->hcca;
+ u32 startframe = hcca->frame_no;
+ u32 end = timer_calc(1000 * 5);
+ for (;;) {
+ if (hcca->frame_no != startframe)
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ return;
+ }
+ yield();
+ }
+}
+
+static void
+ohci_free_pipes(struct usb_ohci_s *cntl)
+{
+ dprintf(7, "ohci_free_pipes %p\n", cntl);
+
+ u32 creg = readl(&cntl->regs->control);
+ if (creg & (OHCI_CTRL_CLE|OHCI_CTRL_BLE)) {
+ writel(&cntl->regs->control, creg & ~(OHCI_CTRL_CLE|OHCI_CTRL_BLE));
+ ohci_waittick(cntl->regs);
+ }
+
+ u32 *pos = &cntl->regs->ed_controlhead;
+ for (;;) {
+ struct ohci_ed *next = (void*)*pos;
+ if (!next)
+ break;
+ struct ohci_pipe *pipe = container_of(next, struct ohci_pipe, ed);
+ if (usb_is_freelist(&cntl->usb, &pipe->pipe)) {
+ *pos = next->hwNextED;
+ free(pipe);
+ } else {
+ pos = &next->hwNextED;
+ }
+ }
+
+ writel(&cntl->regs->ed_controlcurrent, 0);
+ writel(&cntl->regs->ed_bulkcurrent, 0);
+ writel(&cntl->regs->control, creg);
+ cntl->usb.freelist = NULL;
+}
+
+static int
+start_ohci(struct usb_ohci_s *cntl, struct ohci_hcca *hcca)
+{
+ u32 oldfminterval = readl(&cntl->regs->fminterval);
+ u32 oldrwc = readl(&cntl->regs->control) & OHCI_CTRL_RWC;
+
+ // XXX - check if already running?
+
+ // Do reset
+ writel(&cntl->regs->control, OHCI_USB_RESET | oldrwc);
+ readl(&cntl->regs->control); // flush writes
+ msleep(USB_TIME_DRSTR);
+
+ // Do software init (min 10us, max 2ms)
+ u32 end = timer_calc_usec(10);
+ writel(&cntl->regs->cmdstatus, OHCI_HCR);
+ for (;;) {
+ u32 status = readl(&cntl->regs->cmdstatus);
+ if (! status & OHCI_HCR)
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ }
+
+ // Init memory
+ writel(&cntl->regs->ed_controlhead, 0);
+ writel(&cntl->regs->ed_bulkhead, 0);
+ writel(&cntl->regs->hcca, (u32)hcca);
+
+ // Init fminterval
+ u32 fi = oldfminterval & 0x3fff;
+ writel(&cntl->regs->fminterval
+ , (((oldfminterval & FIT) ^ FIT)
+ | fi | (((6 * (fi - 210)) / 7) << 16)));
+ writel(&cntl->regs->periodicstart, ((9 * fi) / 10) & 0x3fff);
+ readl(&cntl->regs->control); // flush writes
+
+ // XXX - verify that fminterval was setup correctly.
+
+ // Go into operational state
+ writel(&cntl->regs->control
+ , (OHCI_CTRL_CBSR | OHCI_CTRL_CLE | OHCI_CTRL_BLE | OHCI_CTRL_PLE
+ | OHCI_USB_OPER | oldrwc));
+ readl(&cntl->regs->control); // flush writes
+
+ return 0;
+}
+
+static void
+stop_ohci(struct usb_ohci_s *cntl)
+{
+ u32 oldrwc = readl(&cntl->regs->control) & OHCI_CTRL_RWC;
+ writel(&cntl->regs->control, oldrwc);
+ readl(&cntl->regs->control); // flush writes
+}
+
+static void
+configure_ohci(void *data)
+{
+ struct usb_ohci_s *cntl = data;
+
+ // Allocate memory
+ struct ohci_hcca *hcca = memalign_high(256, sizeof(*hcca));
+ struct ohci_ed *intr_ed = malloc_high(sizeof(*intr_ed));
+ if (!hcca || !intr_ed) {
+ warn_noalloc();
+ goto free;
+ }
+ memset(hcca, 0, sizeof(*hcca));
+ memset(intr_ed, 0, sizeof(*intr_ed));
+ intr_ed->hwINFO = ED_SKIP;
+ int i;
+ for (i=0; i<ARRAY_SIZE(hcca->int_table); i++)
+ hcca->int_table[i] = (u32)intr_ed;
+
+ int ret = start_ohci(cntl, hcca);
+ if (ret)
+ goto err;
+
+ int count = check_ohci_ports(cntl);
+ ohci_free_pipes(cntl);
+ if (! count)
+ goto err;
+ return;
+
+err:
+ stop_ohci(cntl);
+free:
+ free(hcca);
+ free(intr_ed);
+}
+
+static void
+ohci_controller_setup(struct pci_device *pci)
+{
+ struct ohci_regs *regs = pci_enable_membar(pci, PCI_BASE_ADDRESS_0);
+ if (!regs)
+ return;
+
+ struct usb_ohci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+ if (!cntl) {
+ warn_noalloc();
+ return;
+ }
+ memset(cntl, 0, sizeof(*cntl));
+ cntl->usb.pci = pci;
+ cntl->usb.type = USB_TYPE_OHCI;
+ cntl->regs = regs;
+
+ dprintf(1, "OHCI init on dev %pP (regs=%p)\n", pci, cntl->regs);
+
+ pci_enable_busmaster(pci);
+
+ // XXX - check for and disable SMM control?
+
+ // Disable interrupts
+ writel(&cntl->regs->intrdisable, ~0);
+ writel(&cntl->regs->intrstatus, ~0);
+
+ run_thread(configure_ohci, cntl);
+}
+
+void
+ohci_setup(void)
+{
+ if (! CONFIG_USB_OHCI)
+ return;
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_OHCI)
+ ohci_controller_setup(pci);
+ }
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+// Setup fields in ed
+static void
+ohci_desc2pipe(struct ohci_pipe *pipe, struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
+ pipe->ed.hwINFO = (ED_SKIP | usbdev->devaddr | (pipe->pipe.ep << 7)
+ | (epdesc->wMaxPacketSize << 16)
+ | (usbdev->speed ? ED_LOWSPEED : 0));
+ struct usb_ohci_s *cntl = container_of(
+ usbdev->hub->cntl, struct usb_ohci_s, usb);
+ pipe->regs = cntl->regs;
+}
+
+static struct usb_pipe *
+ohci_alloc_intr_pipe(struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ struct usb_ohci_s *cntl = container_of(
+ usbdev->hub->cntl, struct usb_ohci_s, usb);
+ int frameexp = usb_get_period(usbdev, epdesc);
+ dprintf(7, "ohci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
+
+ if (frameexp > 5)
+ frameexp = 5;
+ int maxpacket = epdesc->wMaxPacketSize;
+ // Determine number of entries needed for 2 timer ticks.
+ int ms = 1<<frameexp;
+ int count = DIV_ROUND_UP(ticks_to_ms(2), ms) + 1;
+ struct ohci_pipe *pipe = malloc_low(sizeof(*pipe));
+ struct ohci_td *tds = malloc_low(sizeof(*tds) * count);
+ void *data = malloc_low(maxpacket * count);
+ if (!pipe || !tds || !data)
+ goto err;
+ memset(pipe, 0, sizeof(*pipe));
+ ohci_desc2pipe(pipe, usbdev, epdesc);
+ pipe->ed.hwINFO &= ~ED_SKIP;
+ pipe->data = data;
+ pipe->count = count;
+ pipe->tds = tds;
+
+ struct ohci_ed *ed = &pipe->ed;
+ ed->hwHeadP = (u32)&tds[0];
+ ed->hwTailP = (u32)&tds[count-1];
+
+ int i;
+ for (i=0; i<count-1; i++) {
+ tds[i].hwINFO = TD_DP_IN | TD_T_TOGGLE | TD_CC;
+ tds[i].hwCBP = (u32)data + maxpacket * i;
+ tds[i].hwNextTD = (u32)&tds[i+1];
+ tds[i].hwBE = tds[i].hwCBP + maxpacket - 1;
+ }
+
+ // Add to interrupt schedule.
+ struct ohci_hcca *hcca = (void*)cntl->regs->hcca;
+ if (frameexp == 0) {
+ // Add to existing interrupt entry.
+ struct ohci_ed *intr_ed = (void*)hcca->int_table[0];
+ ed->hwNextED = intr_ed->hwNextED;
+ barrier();
+ intr_ed->hwNextED = (u32)ed;
+ } else {
+ int startpos = 1<<(frameexp-1);
+ ed->hwNextED = hcca->int_table[startpos];
+ barrier();
+ for (i=startpos; i<ARRAY_SIZE(hcca->int_table); i+=ms)
+ hcca->int_table[i] = (u32)ed;
+ }
+
+ return &pipe->pipe;
+
+err:
+ free(pipe);
+ free(tds);
+ free(data);
+ return NULL;
+}
+
+struct usb_pipe *
+ohci_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *upipe
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ if (! CONFIG_USB_OHCI)
+ return NULL;
+ usb_add_freelist(upipe);
+ if (!epdesc)
+ return NULL;
+ u8 eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ if (eptype == USB_ENDPOINT_XFER_INT)
+ return ohci_alloc_intr_pipe(usbdev, epdesc);
+ struct usb_ohci_s *cntl = container_of(
+ usbdev->hub->cntl, struct usb_ohci_s, usb);
+ dprintf(7, "ohci_alloc_async_pipe %p\n", &cntl->usb);
+
+ struct usb_pipe *usbpipe = usb_get_freelist(&cntl->usb, eptype);
+ if (usbpipe) {
+ // Use previously allocated pipe.
+ struct ohci_pipe *pipe = container_of(usbpipe, struct ohci_pipe, pipe);
+ ohci_desc2pipe(pipe, usbdev, epdesc);
+ return usbpipe;
+ }
+
+ // Allocate a new queue head.
+ struct ohci_pipe *pipe;
+ if (eptype == USB_ENDPOINT_XFER_CONTROL)
+ pipe = malloc_tmphigh(sizeof(*pipe));
+ else
+ pipe = malloc_low(sizeof(*pipe));
+ if (!pipe) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ ohci_desc2pipe(pipe, usbdev, epdesc);
+
+ // Add queue head to controller list.
+ u32 *head = &cntl->regs->ed_controlhead;
+ if (eptype != USB_ENDPOINT_XFER_CONTROL)
+ head = &cntl->regs->ed_bulkhead;
+ pipe->ed.hwNextED = *head;
+ barrier();
+ *head = (u32)&pipe->ed;
+ return &pipe->pipe;
+}
+
+static int
+wait_ed(struct ohci_ed *ed, int timeout)
+{
+ u32 end = timer_calc(timeout);
+ for (;;) {
+ if ((ed->hwHeadP & ~(ED_C|ED_H)) == ed->hwTailP)
+ return 0;
+ if (timer_check(end)) {
+ warn_timeout();
+ dprintf(1, "ohci ed info=%x tail=%x head=%x next=%x\n"
+ , ed->hwINFO, ed->hwTailP, ed->hwHeadP, ed->hwNextED);
+ return -1;
+ }
+ yield();
+ }
+}
+
+#define STACKOTDS 18
+#define OHCI_TD_ALIGN 16
+
+int
+ohci_send_pipe(struct usb_pipe *p, int dir, const void *cmd
+ , void *data, int datasize)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_USB_OHCI)
+ return -1;
+ dprintf(7, "ohci_send_pipe %p\n", p);
+ struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+
+ // Allocate tds on stack (with required alignment)
+ u8 tdsbuf[sizeof(struct ohci_td) * STACKOTDS + OHCI_TD_ALIGN - 1];
+ struct ohci_td *tds = (void*)ALIGN((u32)tdsbuf, OHCI_TD_ALIGN), *td = tds;
+ memset(tds, 0, sizeof(*tds) * STACKOTDS);
+
+ // Setup transfer descriptors
+ u16 maxpacket = pipe->pipe.maxpacket;
+ u32 toggle = 0, statuscmd = OHCI_BLF;
+ if (cmd) {
+ // Send setup pid on control transfers
+ td->hwINFO = TD_DP_SETUP | TD_T_DATA0 | TD_CC;
+ td->hwCBP = (u32)cmd;
+ td->hwNextTD = (u32)&td[1];
+ td->hwBE = (u32)cmd + USB_CONTROL_SETUP_SIZE - 1;
+ td++;
+ toggle = TD_T_DATA1;
+ statuscmd = OHCI_CLF;
+ }
+ u32 dest = (u32)data, dataend = dest + datasize;
+ while (dest < dataend) {
+ // Send data pids
+ if (td >= &tds[STACKOTDS]) {
+ warn_noalloc();
+ return -1;
+ }
+ int maxtransfer = 2*PAGE_SIZE - (dest & (PAGE_SIZE-1));
+ int transfer = dataend - dest;
+ if (transfer > maxtransfer)
+ transfer = ALIGN_DOWN(maxtransfer, maxpacket);
+ td->hwINFO = (dir ? TD_DP_IN : TD_DP_OUT) | toggle | TD_CC;
+ td->hwCBP = dest;
+ td->hwNextTD = (u32)&td[1];
+ td->hwBE = dest + transfer - 1;
+ td++;
+ dest += transfer;
+ }
+ if (cmd) {
+ // Send status pid on control transfers
+ if (td >= &tds[STACKOTDS]) {
+ warn_noalloc();
+ return -1;
+ }
+ td->hwINFO = (dir ? TD_DP_OUT : TD_DP_IN) | TD_T_DATA1 | TD_CC;
+ td->hwCBP = 0;
+ td->hwNextTD = (u32)&td[1];
+ td->hwBE = 0;
+ td++;
+ }
+
+ // Transfer data
+ pipe->ed.hwHeadP = (u32)tds | (pipe->ed.hwHeadP & ED_C);
+ pipe->ed.hwTailP = (u32)td;
+ barrier();
+ pipe->ed.hwINFO &= ~ED_SKIP;
+ writel(&pipe->regs->cmdstatus, statuscmd);
+
+ int ret = wait_ed(&pipe->ed, usb_xfer_time(p, datasize));
+ pipe->ed.hwINFO |= ED_SKIP;
+ if (ret)
+ ohci_waittick(pipe->regs);
+ return ret;
+}
+
+int
+ohci_poll_intr(struct usb_pipe *p, void *data)
+{
+ ASSERT16();
+ if (! CONFIG_USB_OHCI)
+ return -1;
+
+ struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+ struct ohci_td *tds = GET_LOWFLAT(pipe->tds);
+ struct ohci_td *head = (void*)(GET_LOWFLAT(pipe->ed.hwHeadP) & ~(ED_C|ED_H));
+ struct ohci_td *tail = (void*)GET_LOWFLAT(pipe->ed.hwTailP);
+ int count = GET_LOWFLAT(pipe->count);
+ int pos = (tail - tds + 1) % count;
+ struct ohci_td *next = &tds[pos];
+ if (head == next)
+ // No intrs found.
+ return -1;
+ // XXX - check for errors.
+
+ // Copy data.
+ int maxpacket = GET_LOWFLAT(pipe->pipe.maxpacket);
+ void *pipedata = GET_LOWFLAT((pipe->data));
+ void *intrdata = pipedata + maxpacket * pos;
+ memcpy_far(GET_SEG(SS), data, SEG_LOW, LOWFLAT2LOW(intrdata), maxpacket);
+
+ // Reenable this td.
+ SET_LOWFLAT(tail->hwINFO, TD_DP_IN | TD_T_TOGGLE | TD_CC);
+ intrdata = pipedata + maxpacket * (tail-tds);
+ SET_LOWFLAT(tail->hwCBP, (u32)intrdata);
+ SET_LOWFLAT(tail->hwNextTD, (u32)next);
+ SET_LOWFLAT(tail->hwBE, (u32)intrdata + maxpacket - 1);
+ barrier();
+ SET_LOWFLAT(pipe->ed.hwTailP, (u32)next);
+
+ return 0;
+}
diff --git a/roms/seabios-hppa/src/hw/usb-ohci.h b/roms/seabios-hppa/src/hw/usb-ohci.h
new file mode 100644
index 000000000..5a275a334
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-ohci.h
@@ -0,0 +1,144 @@
+#ifndef __USB_OHCI_H
+#define __USB_OHCI_H
+
+// usb-ohci.c
+void ohci_setup(void);
+struct usbdevice_s;
+struct usb_endpoint_descriptor;
+struct usb_pipe;
+struct usb_pipe *ohci_realloc_pipe(struct usbdevice_s *usbdev
+ , struct usb_pipe *upipe
+ , struct usb_endpoint_descriptor *epdesc);
+int ohci_send_pipe(struct usb_pipe *p, int dir, const void *cmd
+ , void *data, int datasize);
+int ohci_poll_intr(struct usb_pipe *p, void *data);
+
+
+/****************************************************************
+ * ohci structs and flags
+ ****************************************************************/
+
+struct ohci_ed {
+ u32 hwINFO;
+ u32 hwTailP;
+ u32 hwHeadP;
+ u32 hwNextED;
+} PACKED;
+
+#define ED_ISO (1 << 15)
+#define ED_SKIP (1 << 14)
+#define ED_LOWSPEED (1 << 13)
+#define ED_OUT (0x01 << 11)
+#define ED_IN (0x02 << 11)
+
+#define ED_C (0x02)
+#define ED_H (0x01)
+
+struct ohci_td {
+ u32 hwINFO;
+ u32 hwCBP;
+ u32 hwNextTD;
+ u32 hwBE;
+} PACKED;
+
+#define TD_CC 0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_DI 0x00E00000
+
+#define TD_DONE 0x00020000
+#define TD_ISO 0x00010000
+
+#define TD_EC 0x0C000000
+#define TD_T 0x03000000
+#define TD_T_DATA0 0x02000000
+#define TD_T_DATA1 0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_DP 0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN 0x00100000
+#define TD_DP_OUT 0x00080000
+
+#define TD_R 0x00040000
+
+struct ohci_hcca {
+ u32 int_table[32];
+ u32 frame_no;
+ u32 done_head;
+ u8 reserved[120];
+} PACKED;
+
+struct ohci_regs {
+ u32 revision;
+ u32 control;
+ u32 cmdstatus;
+ u32 intrstatus;
+ u32 intrenable;
+ u32 intrdisable;
+
+ u32 hcca;
+ u32 ed_periodcurrent;
+ u32 ed_controlhead;
+ u32 ed_controlcurrent;
+ u32 ed_bulkhead;
+ u32 ed_bulkcurrent;
+ u32 donehead;
+
+ u32 fminterval;
+ u32 fmremaining;
+ u32 fmnumber;
+ u32 periodicstart;
+ u32 lsthresh;
+
+ u32 roothub_a;
+ u32 roothub_b;
+ u32 roothub_status;
+ u32 roothub_portstatus[15];
+} PACKED;
+
+#define OHCI_CTRL_CBSR (3 << 0)
+#define OHCI_CTRL_PLE (1 << 2)
+#define OHCI_CTRL_CLE (1 << 4)
+#define OHCI_CTRL_BLE (1 << 5)
+#define OHCI_CTRL_HCFS (3 << 6)
+# define OHCI_USB_RESET (0 << 6)
+# define OHCI_USB_OPER (2 << 6)
+#define OHCI_CTRL_RWC (1 << 9)
+
+#define OHCI_HCR (1 << 0)
+#define OHCI_CLF (1 << 1)
+#define OHCI_BLF (1 << 2)
+
+#define OHCI_INTR_MIE (1 << 31)
+
+#define RH_PS_CCS 0x00000001
+#define RH_PS_PES 0x00000002
+#define RH_PS_PSS 0x00000004
+#define RH_PS_POCI 0x00000008
+#define RH_PS_PRS 0x00000010
+#define RH_PS_PPS 0x00000100
+#define RH_PS_LSDA 0x00000200
+#define RH_PS_CSC 0x00010000
+#define RH_PS_PESC 0x00020000
+#define RH_PS_PSSC 0x00040000
+#define RH_PS_OCIC 0x00080000
+#define RH_PS_PRSC 0x00100000
+
+#define RH_HS_LPS 0x00000001
+#define RH_HS_OCI 0x00000002
+#define RH_HS_DRWE 0x00008000
+#define RH_HS_LPSC 0x00010000
+#define RH_HS_OCIC 0x00020000
+#define RH_HS_CRWE 0x80000000
+
+#define RH_B_DR 0x0000ffff
+#define RH_B_PPCM 0xffff0000
+
+#define RH_A_NDP (0xff << 0)
+#define RH_A_PSM (1 << 8)
+#define RH_A_NPS (1 << 9)
+#define RH_A_DT (1 << 10)
+#define RH_A_OCPM (1 << 11)
+#define RH_A_NOCP (1 << 12)
+#define RH_A_POTPGT (0xff << 24)
+
+#endif // usb-ohci.h
diff --git a/roms/seabios-hppa/src/hw/usb-uas.c b/roms/seabios-hppa/src/hw/usb-uas.c
new file mode 100644
index 000000000..4a789b321
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-uas.c
@@ -0,0 +1,289 @@
+// Code for handling usb attached scsi devices.
+//
+// only usb 2.0 for now.
+//
+// once we have xhci driver with usb 3.0 support this must
+// be updated to use usb3 streams so booting from usb3
+// devices actually works.
+//
+// Authors:
+// Gerd Hoffmann <kraxel@redhat.com>
+//
+// based on usb-msc.c which is written by:
+// Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBALFLAT
+#include "block.h" // DTYPE_USB
+#include "blockcmd.h" // cdb_read
+#include "config.h" // CONFIG_USB_UAS
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "usb.h" // struct usb_s
+#include "usb-uas.h" // usb_uas_init
+#include "util.h" // bootprio_find_usb
+
+#define UAS_UI_COMMAND 0x01
+#define UAS_UI_SENSE 0x03
+#define UAS_UI_RESPONSE 0x04
+#define UAS_UI_TASK_MGMT 0x05
+#define UAS_UI_READ_READY 0x06
+#define UAS_UI_WRITE_READY 0x07
+
+#define UAS_PIPE_ID_COMMAND 0x01
+#define UAS_PIPE_ID_STATUS 0x02
+#define UAS_PIPE_ID_DATA_IN 0x03
+#define UAS_PIPE_ID_DATA_OUT 0x04
+
+typedef struct {
+ u8 id;
+ u8 reserved;
+ u16 tag;
+} PACKED uas_ui_header;
+
+typedef struct {
+ u8 prio_taskattr; /* 6:3 priority, 2:0 task attribute */
+ u8 reserved_1;
+ u8 add_cdb_length; /* 7:2 additional adb length (dwords) */
+ u8 reserved_2;
+ u8 lun[8];
+ u8 cdb[16];
+ u8 add_cdb[];
+} PACKED uas_ui_command;
+
+typedef struct {
+ u16 status_qualifier;
+ u8 status;
+ u8 reserved[7];
+ u16 sense_length;
+ u8 sense_data[18];
+} PACKED uas_ui_sense;
+
+typedef struct {
+ u16 add_response_info;
+ u8 response_code;
+} PACKED uas_ui_response;
+
+typedef struct {
+ u8 function;
+ u8 reserved;
+ u16 task_tag;
+ u8 lun[8];
+} PACKED uas_ui_task_mgmt;
+
+typedef struct {
+ uas_ui_header hdr;
+ union {
+ uas_ui_command command;
+ uas_ui_sense sense;
+ uas_ui_task_mgmt task;
+ uas_ui_response response;
+ };
+} PACKED uas_ui;
+
+struct uasdrive_s {
+ struct drive_s drive;
+ struct usbdevice_s *usbdev;
+ struct usb_pipe *command, *status, *data_in, *data_out;
+ u32 lun;
+};
+
+int
+uas_process_op(struct disk_op_s *op)
+{
+ if (!CONFIG_USB_UAS)
+ return DISK_RET_EBADTRACK;
+
+ struct uasdrive_s *drive_gf = container_of(
+ op->drive_fl, struct uasdrive_s, drive);
+
+ uas_ui ui;
+ memset(&ui, 0, sizeof(ui));
+ ui.hdr.id = UAS_UI_COMMAND;
+ ui.hdr.tag = 0xdead;
+ ui.command.lun[1] = GET_GLOBALFLAT(drive_gf->lun);
+ 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));
+ if (ret) {
+ dprintf(1, "uas: command send fail");
+ goto fail;
+ }
+
+ memset(&ui, 0xff, sizeof(ui));
+ ret = usb_send_bulk(GET_GLOBALFLAT(drive_gf->status),
+ USB_DIR_IN, MAKE_FLATPTR(GET_SEG(SS), &ui), sizeof(ui));
+ if (ret) {
+ dprintf(1, "uas: status recv fail");
+ goto fail;
+ }
+
+ switch (ui.hdr.id) {
+ case UAS_UI_SENSE:
+ goto have_sense;
+ case UAS_UI_READ_READY:
+ ret = usb_send_bulk(GET_GLOBALFLAT(drive_gf->data_in),
+ USB_DIR_IN, op->buf_fl, op->count * blocksize);
+ if (ret) {
+ dprintf(1, "uas: data read fail");
+ goto fail;
+ }
+ break;
+ case UAS_UI_WRITE_READY:
+ ret = usb_send_bulk(GET_GLOBALFLAT(drive_gf->data_out),
+ USB_DIR_OUT, op->buf_fl, op->count * blocksize);
+ if (ret) {
+ dprintf(1, "uas: data write fail");
+ goto fail;
+ }
+ break;
+ default:
+ dprintf(1, "uas: unknown status ui id %d", ui.hdr.id);
+ goto fail;
+ }
+
+ memset(&ui, 0xff, sizeof(ui));
+ ret = usb_send_bulk(GET_GLOBALFLAT(drive_gf->status),
+ USB_DIR_IN, MAKE_FLATPTR(GET_SEG(SS), &ui), sizeof(ui));
+ if (ret) {
+ dprintf(1, "uas: status recv fail");
+ goto fail;
+ }
+ if (ui.hdr.id != UAS_UI_SENSE) {
+ dprintf(1, "uas: expected sense ui, got ui id %d", ui.hdr.id);
+ goto fail;
+ }
+
+have_sense:
+ if (ui.sense.status == 0) {
+ return DISK_RET_SUCCESS;
+ }
+
+fail:
+ return DISK_RET_EBADTRACK;
+}
+
+static void
+uas_init_lun(struct uasdrive_s *drive, struct usbdevice_s *usbdev,
+ struct usb_pipe *command, struct usb_pipe *status,
+ struct usb_pipe *data_in, struct usb_pipe *data_out,
+ u32 lun)
+{
+ memset(drive, 0, sizeof(*drive));
+ if (usb_32bit_pipe(data_in))
+ drive->drive.type = DTYPE_UAS_32;
+ else
+ drive->drive.type = DTYPE_UAS;
+ drive->usbdev = usbdev;
+ drive->command = command;
+ drive->status = status;
+ drive->data_in = data_in;
+ drive->data_out = data_out;
+ drive->lun = lun;
+}
+
+static int
+uas_add_lun(u32 lun, struct drive_s *tmpl_drv)
+{
+ struct uasdrive_s *tmpl_lun =
+ container_of(tmpl_drv, struct uasdrive_s, drive);
+ struct uasdrive_s *drive = malloc_fseg(sizeof(*drive));
+ if (!drive) {
+ warn_noalloc();
+ return -1;
+ }
+ uas_init_lun(drive, tmpl_lun->usbdev,
+ tmpl_lun->command, tmpl_lun->status,
+ tmpl_lun->data_in, tmpl_lun->data_out,
+ lun);
+
+ int prio = bootprio_find_usb(drive->usbdev, drive->lun);
+ int ret = scsi_drive_setup(&drive->drive, "USB UAS", prio, 0, lun);
+ if (ret) {
+ free(drive);
+ return -1;
+ }
+ return 0;
+}
+
+int
+usb_uas_setup(struct usbdevice_s *usbdev)
+{
+ if (!CONFIG_USB_UAS)
+ return -1;
+
+ // Verify right kind of device
+ struct usb_interface_descriptor *iface = usbdev->iface;
+ if (iface->bInterfaceSubClass != US_SC_SCSI ||
+ iface->bInterfaceProtocol != US_PR_UAS) {
+ dprintf(1, "Unsupported UAS device (subclass=%02x proto=%02x)\n"
+ , iface->bInterfaceSubClass, iface->bInterfaceProtocol);
+ return -1;
+ }
+
+ /* find & allocate pipes */
+ struct usb_endpoint_descriptor *ep = NULL;
+ struct usb_pipe *command = NULL;
+ struct usb_pipe *status = NULL;
+ struct usb_pipe *data_in = NULL;
+ struct usb_pipe *data_out = NULL;
+ u8 *desc = (u8*)iface;
+ while (desc) {
+ desc += desc[0];
+ switch (desc[1]) {
+ case USB_DT_ENDPOINT:
+ ep = (void*)desc;
+ break;
+ case USB_DT_ENDPOINT_COMPANION:
+ /* No support (yet) for usb3 streams */
+ dprintf(1, "Superspeed UAS devices not supported (yet)\n");
+ goto fail;
+ case 0x24:
+ switch (desc[2]) {
+ case UAS_PIPE_ID_COMMAND:
+ command = usb_alloc_pipe(usbdev, ep);
+ break;
+ case UAS_PIPE_ID_STATUS:
+ status = usb_alloc_pipe(usbdev, ep);
+ break;
+ case UAS_PIPE_ID_DATA_IN:
+ data_in = usb_alloc_pipe(usbdev, ep);
+ break;
+ case UAS_PIPE_ID_DATA_OUT:
+ data_out = usb_alloc_pipe(usbdev, ep);
+ break;
+ default:
+ goto fail;
+ }
+ break;
+ default:
+ desc = NULL;
+ break;
+ }
+ }
+ if (!command || !status || !data_in || !data_out)
+ goto fail;
+
+ struct uasdrive_s lun0;
+ uas_init_lun(&lun0, usbdev, command, status, data_in, data_out, 0);
+ int ret = scsi_rep_luns_scan(&lun0.drive, uas_add_lun);
+ if (ret <= 0) {
+ dprintf(1, "Unable to configure UAS drive.\n");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ usb_free_pipe(usbdev, command);
+ usb_free_pipe(usbdev, status);
+ usb_free_pipe(usbdev, data_in);
+ usb_free_pipe(usbdev, data_out);
+ return -1;
+}
diff --git a/roms/seabios-hppa/src/hw/usb-uas.h b/roms/seabios-hppa/src/hw/usb-uas.h
new file mode 100644
index 000000000..8b2f810e9
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-uas.h
@@ -0,0 +1,9 @@
+#ifndef __USB_UAS_H
+#define __USB_UAS_H
+
+struct disk_op_s;
+int uas_process_op(struct disk_op_s *op);
+struct usbdevice_s;
+int usb_uas_setup(struct usbdevice_s *usbdev);
+
+#endif /* __USB_UAS_H */
diff --git a/roms/seabios-hppa/src/hw/usb-uhci.c b/roms/seabios-hppa/src/hw/usb-uhci.c
new file mode 100644
index 000000000..075ed02cd
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-uhci.c
@@ -0,0 +1,571 @@
+// Code for handling UHCI USB controllers.
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_LOWFLAT
+#include "config.h" // CONFIG_*
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "pci.h" // pci_config_writew
+#include "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI
+#include "pci_regs.h" // PCI_BASE_ADDRESS_4
+#include "string.h" // memset
+#include "usb.h" // struct usb_s
+#include "usb-ehci.h" // ehci_wait_controllers
+#include "usb-uhci.h" // USBLEGSUP
+#include "util.h" // msleep
+#include "x86.h" // outw
+
+struct usb_uhci_s {
+ struct usb_s usb;
+ u16 iobase;
+ struct uhci_qh *control_qh;
+ struct uhci_framelist *framelist;
+};
+
+struct uhci_pipe {
+ struct uhci_qh qh;
+ struct uhci_td *next_td;
+ struct usb_pipe pipe;
+ u16 iobase;
+ u8 toggle;
+};
+
+
+/****************************************************************
+ * Root hub
+ ****************************************************************/
+
+// Check if device attached to a given port
+static int
+uhci_hub_detect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb);
+ u16 ioport = cntl->iobase + USBPORTSC1 + port * 2;
+ u16 status = inw(ioport);
+ if (!(status & USBPORTSC_CCS))
+ // No device found.
+ return 0;
+
+ // XXX - if just powered up, need to wait for USB_TIME_ATTDB?
+
+ // Begin reset on port
+ outw(USBPORTSC_PR, ioport);
+ msleep(USB_TIME_DRSTR);
+ return 1;
+}
+
+// Reset device on port
+static int
+uhci_hub_reset(struct usbhub_s *hub, u32 port)
+{
+ struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb);
+ u16 ioport = cntl->iobase + USBPORTSC1 + port * 2;
+
+ // Finish reset on port
+ outw(0, ioport);
+ udelay(6); // 64 high-speed bit times
+ u16 status = inw(ioport);
+ if (!(status & USBPORTSC_CCS))
+ // No longer connected
+ return -1;
+ outw(USBPORTSC_PE, ioport);
+ return !!(status & USBPORTSC_LSDA);
+}
+
+// Disable port
+static void
+uhci_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb);
+ u16 ioport = cntl->iobase + USBPORTSC1 + port * 2;
+ outw(0, ioport);
+}
+
+static struct usbhub_op_s uhci_HubOp = {
+ .detect = uhci_hub_detect,
+ .reset = uhci_hub_reset,
+ .disconnect = uhci_hub_disconnect,
+};
+
+// Find any devices connected to the root hub.
+static int
+check_uhci_ports(struct usb_uhci_s *cntl)
+{
+ ASSERT32FLAT();
+ // Wait for ehci init - in case this is a "companion controller"
+ ehci_wait_controllers();
+
+ struct usbhub_s hub;
+ memset(&hub, 0, sizeof(hub));
+ hub.cntl = &cntl->usb;
+ hub.portcount = 2;
+ hub.op = &uhci_HubOp;
+ usb_enumerate(&hub);
+ return hub.devcount;
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+// Wait for next USB frame to start - for ensuring safe memory release.
+static void
+uhci_waittick(u16 iobase)
+{
+ barrier();
+ u16 startframe = inw(iobase + USBFRNUM);
+ u32 end = timer_calc(1000 * 5);
+ for (;;) {
+ if (inw(iobase + USBFRNUM) != startframe)
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ return;
+ }
+ yield();
+ }
+}
+
+static void
+uhci_free_pipes(struct usb_uhci_s *cntl)
+{
+ dprintf(7, "uhci_free_pipes %p\n", cntl);
+
+ struct uhci_qh *pos = (void*)(cntl->framelist->links[0] & ~UHCI_PTR_BITS);
+ for (;;) {
+ u32 link = pos->link;
+ if (link == UHCI_PTR_TERM)
+ break;
+ struct uhci_qh *next = (void*)(link & ~UHCI_PTR_BITS);
+ struct uhci_pipe *pipe = container_of(next, struct uhci_pipe, qh);
+ if (usb_is_freelist(&cntl->usb, &pipe->pipe))
+ pos->link = next->link;
+ else
+ pos = next;
+ }
+ uhci_waittick(cntl->iobase);
+ for (;;) {
+ struct usb_pipe *usbpipe = cntl->usb.freelist;
+ if (!usbpipe)
+ break;
+ cntl->usb.freelist = usbpipe->freenext;
+ struct uhci_pipe *pipe = container_of(usbpipe, struct uhci_pipe, pipe);
+ free(pipe);
+ }
+}
+
+static void
+reset_uhci(struct usb_uhci_s *cntl, u16 bdf)
+{
+ // XXX - don't reset if not needed.
+
+ // Reset PIRQ and SMI
+ pci_config_writew(bdf, USBLEGSUP, USBLEGSUP_RWC);
+
+ // Reset the HC
+ outw(USBCMD_HCRESET, cntl->iobase + USBCMD);
+ udelay(5);
+
+ // Disable interrupts and commands (just to be safe).
+ outw(0, cntl->iobase + USBINTR);
+ outw(0, cntl->iobase + USBCMD);
+}
+
+static void
+configure_uhci(void *data)
+{
+ struct usb_uhci_s *cntl = data;
+
+ // Allocate ram for schedule storage
+ struct uhci_td *term_td = malloc_high(sizeof(*term_td));
+ struct uhci_framelist *fl = memalign_high(sizeof(*fl), sizeof(*fl));
+ struct uhci_pipe *intr_pipe = malloc_high(sizeof(*intr_pipe));
+ struct uhci_pipe *term_pipe = malloc_high(sizeof(*term_pipe));
+ if (!term_td || !fl || !intr_pipe || !term_pipe) {
+ warn_noalloc();
+ goto fail;
+ }
+
+ // Work around for PIIX errata
+ memset(term_td, 0, sizeof(*term_td));
+ term_td->link = UHCI_PTR_TERM;
+ term_td->token = (uhci_explen(0) | (0x7f << TD_TOKEN_DEVADDR_SHIFT)
+ | USB_PID_IN);
+ memset(term_pipe, 0, sizeof(*term_pipe));
+ term_pipe->qh.element = (u32)term_td;
+ term_pipe->qh.link = UHCI_PTR_TERM;
+ term_pipe->pipe.cntl = &cntl->usb;
+
+ // Set schedule to point to primary intr queue head
+ memset(intr_pipe, 0, sizeof(*intr_pipe));
+ intr_pipe->qh.element = UHCI_PTR_TERM;
+ intr_pipe->qh.link = (u32)&term_pipe->qh | UHCI_PTR_QH;
+ intr_pipe->pipe.cntl = &cntl->usb;
+ int i;
+ for (i=0; i<ARRAY_SIZE(fl->links); i++)
+ fl->links[i] = (u32)&intr_pipe->qh | UHCI_PTR_QH;
+ cntl->framelist = fl;
+ cntl->control_qh = &intr_pipe->qh;
+ barrier();
+
+ // Set the frame length to the default: 1 ms exactly
+ outb(USBSOF_DEFAULT, cntl->iobase + USBSOF);
+
+ // Store the frame list base address
+ outl((u32)fl->links, cntl->iobase + USBFLBASEADD);
+
+ // Set the current frame number
+ outw(0, cntl->iobase + USBFRNUM);
+
+ // Mark as configured and running with a 64-byte max packet.
+ outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, cntl->iobase + USBCMD);
+
+ // Find devices
+ int count = check_uhci_ports(cntl);
+ uhci_free_pipes(cntl);
+ if (count)
+ // Success
+ return;
+
+ // No devices found - shutdown and free controller.
+ outw(0, cntl->iobase + USBCMD);
+fail:
+ free(term_td);
+ free(fl);
+ free(intr_pipe);
+ free(term_pipe);
+ free(cntl);
+}
+
+static void
+uhci_controller_setup(struct pci_device *pci)
+{
+ u16 iobase = pci_enable_iobar(pci, PCI_BASE_ADDRESS_4);
+ if (!iobase)
+ return;
+
+ struct usb_uhci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+ if (!cntl) {
+ warn_noalloc();
+ return;
+ }
+ memset(cntl, 0, sizeof(*cntl));
+ cntl->usb.pci = pci;
+ cntl->usb.type = USB_TYPE_UHCI;
+ cntl->iobase = iobase;
+
+ dprintf(1, "UHCI init on dev %pP (io=%x)\n", pci, cntl->iobase);
+
+ pci_enable_busmaster(pci);
+
+ reset_uhci(cntl, pci->bdf);
+
+ run_thread(configure_uhci, cntl);
+}
+
+void
+uhci_setup(void)
+{
+ if (! CONFIG_USB_UHCI)
+ return;
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_UHCI)
+ uhci_controller_setup(pci);
+ }
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+static struct usb_pipe *
+uhci_alloc_intr_pipe(struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ struct usb_uhci_s *cntl = container_of(
+ usbdev->hub->cntl, struct usb_uhci_s, usb);
+ int frameexp = usb_get_period(usbdev, epdesc);
+ dprintf(7, "uhci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
+
+ if (frameexp > 10)
+ frameexp = 10;
+ int maxpacket = epdesc->wMaxPacketSize;
+ // Determine number of entries needed for 2 timer ticks.
+ int ms = 1<<frameexp;
+ int count = DIV_ROUND_UP(ticks_to_ms(2), ms);
+ count = ALIGN(count, 2);
+ struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
+ struct uhci_td *tds = malloc_low(sizeof(*tds) * count);
+ void *data = malloc_low(maxpacket * count);
+ if (!pipe || !tds || !data) {
+ warn_noalloc();
+ goto fail;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
+ int lowspeed = pipe->pipe.speed;
+ int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7);
+ pipe->qh.element = (u32)tds;
+ pipe->next_td = &tds[0];
+ pipe->iobase = cntl->iobase;
+
+ int toggle = 0;
+ int i;
+ for (i=0; i<count; i++) {
+ tds[i].link = (i==count-1 ? (u32)&tds[0] : (u32)&tds[i+1]);
+ tds[i].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+ | TD_CTRL_ACTIVE);
+ tds[i].token = (uhci_explen(maxpacket) | toggle
+ | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+ | USB_PID_IN);
+ tds[i].buffer = data + maxpacket * i;
+ toggle ^= TD_TOKEN_TOGGLE;
+ }
+
+ // Add to interrupt schedule.
+ struct uhci_framelist *fl = cntl->framelist;
+ if (frameexp == 0) {
+ // Add to existing interrupt entry.
+ struct uhci_qh *intr_qh = (void*)(fl->links[0] & ~UHCI_PTR_BITS);
+ pipe->qh.link = intr_qh->link;
+ barrier();
+ intr_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+ if (cntl->control_qh == intr_qh)
+ cntl->control_qh = &pipe->qh;
+ } else {
+ int startpos = 1<<(frameexp-1);
+ pipe->qh.link = fl->links[startpos];
+ barrier();
+ for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms)
+ fl->links[i] = (u32)&pipe->qh | UHCI_PTR_QH;
+ }
+
+ return &pipe->pipe;
+fail:
+ free(pipe);
+ free(tds);
+ free(data);
+ return NULL;
+}
+
+struct usb_pipe *
+uhci_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *upipe
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ if (! CONFIG_USB_UHCI)
+ return NULL;
+ usb_add_freelist(upipe);
+ if (!epdesc)
+ return NULL;
+ u8 eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ if (eptype == USB_ENDPOINT_XFER_INT)
+ return uhci_alloc_intr_pipe(usbdev, epdesc);
+ struct usb_uhci_s *cntl = container_of(
+ usbdev->hub->cntl, struct usb_uhci_s, usb);
+ dprintf(7, "uhci_alloc_async_pipe %p %d\n", &cntl->usb, eptype);
+
+ struct usb_pipe *usbpipe = usb_get_freelist(&cntl->usb, eptype);
+ if (usbpipe) {
+ // Use previously allocated pipe.
+ usb_desc2pipe(usbpipe, usbdev, epdesc);
+ return usbpipe;
+ }
+
+ // Allocate a new queue head.
+ struct uhci_pipe *pipe;
+ if (eptype == USB_ENDPOINT_XFER_CONTROL)
+ pipe = malloc_tmphigh(sizeof(*pipe));
+ else
+ pipe = malloc_low(sizeof(*pipe));
+ if (!pipe) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
+ pipe->qh.element = UHCI_PTR_TERM;
+ pipe->iobase = cntl->iobase;
+
+ // Add queue head to controller list.
+ struct uhci_qh *control_qh = cntl->control_qh;
+ pipe->qh.link = control_qh->link;
+ barrier();
+ control_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+ if (eptype == USB_ENDPOINT_XFER_CONTROL)
+ cntl->control_qh = &pipe->qh;
+ return &pipe->pipe;
+}
+
+static int
+wait_pipe(struct uhci_pipe *pipe, u32 end)
+{
+ for (;;) {
+ u32 el_link = GET_LOWFLAT(pipe->qh.element);
+ if (el_link & UHCI_PTR_TERM)
+ return 0;
+ if (timer_check(end)) {
+ warn_timeout();
+ u16 iobase = GET_LOWFLAT(pipe->iobase);
+ struct uhci_td *td = (void*)(el_link & ~UHCI_PTR_BITS);
+ dprintf(1, "Timeout on wait_pipe %p (td=%p s=%x c=%x/%x)\n"
+ , pipe, (void*)el_link, GET_LOWFLAT(td->status)
+ , inw(iobase + USBCMD)
+ , inw(iobase + USBSTS));
+ SET_LOWFLAT(pipe->qh.element, UHCI_PTR_TERM);
+ uhci_waittick(iobase);
+ return -1;
+ }
+ yield();
+ }
+}
+
+static int
+wait_td(struct uhci_td *td, u32 end)
+{
+ u32 status;
+ for (;;) {
+ status = td->status;
+ if (!(status & TD_CTRL_ACTIVE))
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+ if (status & TD_CTRL_ANY_ERROR) {
+ dprintf(1, "wait_td error - status=%x\n", status);
+ return -2;
+ }
+ return 0;
+}
+
+#define STACKTDS 16
+#define TDALIGN 16
+
+int
+uhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd
+ , void *data, int datasize)
+{
+ if (! CONFIG_USB_UHCI)
+ return -1;
+ struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+ dprintf(7, "uhci_send_pipe qh=%p dir=%d data=%p size=%d\n"
+ , &pipe->qh, dir, data, datasize);
+ int maxpacket = GET_LOWFLAT(pipe->pipe.maxpacket);
+ int lowspeed = GET_LOWFLAT(pipe->pipe.speed);
+ int devaddr = (GET_LOWFLAT(pipe->pipe.devaddr)
+ | (GET_LOWFLAT(pipe->pipe.ep) << 7));
+ int toggle = GET_LOWFLAT(pipe->toggle) ? TD_TOKEN_TOGGLE : 0;
+
+ // Allocate 16 tds on stack (16byte aligned)
+ u8 tdsbuf[sizeof(struct uhci_td) * STACKTDS + TDALIGN - 1];
+ struct uhci_td *tds = (void*)ALIGN((u32)tdsbuf, TDALIGN);
+ memset(tds, 0, sizeof(*tds) * STACKTDS);
+ int tdpos = 0;
+
+ // Enable tds
+ u32 end = timer_calc(usb_xfer_time(p, datasize));
+ barrier();
+ SET_LOWFLAT(pipe->qh.element, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
+
+ // Setup transfer descriptors
+ if (cmd) {
+ // Send setup pid on control transfers
+ struct uhci_td *td = &tds[tdpos++ % STACKTDS];
+ u32 nexttd = (u32)MAKE_FLATPTR(GET_SEG(SS), &tds[tdpos % STACKTDS]);
+ td->link = nexttd | UHCI_PTR_DEPTH;
+ td->token = (uhci_explen(USB_CONTROL_SETUP_SIZE)
+ | (devaddr << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_SETUP);
+ td->buffer = (void*)cmd;
+ barrier();
+ td->status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+ | TD_CTRL_ACTIVE);
+ toggle = TD_TOKEN_TOGGLE;
+ }
+ while (datasize) {
+ // Send data pids
+ struct uhci_td *td = &tds[tdpos++ % STACKTDS];
+ int ret = wait_td(td, end);
+ if (ret)
+ goto fail;
+
+ int transfer = datasize;
+ if (transfer > maxpacket)
+ transfer = maxpacket;
+ u32 nexttd = (u32)MAKE_FLATPTR(GET_SEG(SS), &tds[tdpos % STACKTDS]);
+ td->link = ((transfer==datasize && !cmd)
+ ? UHCI_PTR_TERM : (nexttd | UHCI_PTR_DEPTH));
+ td->token = (uhci_explen(transfer) | toggle
+ | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+ | (dir ? USB_PID_IN : USB_PID_OUT));
+ td->buffer = data;
+ barrier();
+ td->status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+ | TD_CTRL_ACTIVE);
+ toggle ^= TD_TOKEN_TOGGLE;
+
+ data += transfer;
+ datasize -= transfer;
+ }
+ if (cmd) {
+ // Send status pid on control transfers
+ struct uhci_td *td = &tds[tdpos++ % STACKTDS];
+ int ret = wait_td(td, end);
+ if (ret)
+ goto fail;
+ td->link = UHCI_PTR_TERM;
+ td->token = (uhci_explen(0) | TD_TOKEN_TOGGLE
+ | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+ | (dir ? USB_PID_OUT : USB_PID_IN));
+ td->buffer = 0;
+ barrier();
+ td->status = (uhci_maxerr(0) | (lowspeed ? TD_CTRL_LS : 0)
+ | TD_CTRL_ACTIVE);
+ }
+ SET_LOWFLAT(pipe->toggle, !!toggle);
+ return wait_pipe(pipe, end);
+fail:
+ dprintf(1, "uhci_send_bulk failed\n");
+ SET_LOWFLAT(pipe->qh.element, UHCI_PTR_TERM);
+ uhci_waittick(GET_LOWFLAT(pipe->iobase));
+ return -1;
+}
+
+int
+uhci_poll_intr(struct usb_pipe *p, void *data)
+{
+ ASSERT16();
+ if (! CONFIG_USB_UHCI)
+ return -1;
+
+ struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+ struct uhci_td *td = GET_LOWFLAT(pipe->next_td);
+ u32 status = GET_LOWFLAT(td->status);
+ u32 token = GET_LOWFLAT(td->token);
+ if (status & TD_CTRL_ACTIVE)
+ // No intrs found.
+ return -1;
+ // XXX - check for errors.
+
+ // Copy data.
+ void *tddata = GET_LOWFLAT(td->buffer);
+ memcpy_far(GET_SEG(SS), data, SEG_LOW, LOWFLAT2LOW(tddata)
+ , uhci_expected_length(token));
+
+ // Reenable this td.
+ struct uhci_td *next = (void*)(GET_LOWFLAT(td->link) & ~UHCI_PTR_BITS);
+ SET_LOWFLAT(pipe->next_td, next);
+ barrier();
+ SET_LOWFLAT(td->status, (uhci_maxerr(0) | (status & TD_CTRL_LS)
+ | TD_CTRL_ACTIVE));
+
+ return 0;
+}
diff --git a/roms/seabios-hppa/src/hw/usb-uhci.h b/roms/seabios-hppa/src/hw/usb-uhci.h
new file mode 100644
index 000000000..bff70c667
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-uhci.h
@@ -0,0 +1,128 @@
+#ifndef __USB_UHCI_H
+#define __USB_UHCI_H
+
+// usb-uhci.c
+void uhci_setup(void);
+struct usbdevice_s;
+struct usb_endpoint_descriptor;
+struct usb_pipe;
+struct usb_pipe *uhci_realloc_pipe(struct usbdevice_s *usbdev
+ , struct usb_pipe *upipe
+ , struct usb_endpoint_descriptor *epdesc);
+int uhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd
+ , void *data, int datasize);
+int uhci_poll_intr(struct usb_pipe *p, void *data);
+
+
+/****************************************************************
+ * uhci structs and flags
+ ****************************************************************/
+
+/* USB port status and control registers */
+#define USBPORTSC1 16
+#define USBPORTSC2 18
+#define USBPORTSC_CCS 0x0001 /* Current Connect Status
+ * ("device present") */
+#define USBPORTSC_CSC 0x0002 /* Connect Status Change */
+#define USBPORTSC_PE 0x0004 /* Port Enable */
+#define USBPORTSC_PEC 0x0008 /* Port Enable Change */
+#define USBPORTSC_DPLUS 0x0010 /* D+ high (line status) */
+#define USBPORTSC_DMINUS 0x0020 /* D- high (line status) */
+#define USBPORTSC_RD 0x0040 /* Resume Detect */
+#define USBPORTSC_RES1 0x0080 /* reserved, always 1 */
+#define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */
+#define USBPORTSC_PR 0x0200 /* Port Reset */
+
+/* Legacy support register */
+#define USBLEGSUP 0xc0
+#define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */
+
+/* Command register */
+#define USBCMD 0
+#define USBCMD_RS 0x0001 /* Run/Stop */
+#define USBCMD_HCRESET 0x0002 /* Host reset */
+#define USBCMD_GRESET 0x0004 /* Global reset */
+#define USBCMD_EGSM 0x0008 /* Global Suspend Mode */
+#define USBCMD_FGR 0x0010 /* Force Global Resume */
+#define USBCMD_SWDBG 0x0020 /* SW Debug mode */
+#define USBCMD_CF 0x0040 /* Config Flag (sw only) */
+#define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS 2
+#define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */
+#define USBSTS_ERROR 0x0002 /* Interrupt due to error */
+#define USBSTS_RD 0x0004 /* Resume Detect */
+#define USBSTS_HSE 0x0008 /* Host System Error: PCI problems */
+#define USBSTS_HCPE 0x0010 /* Host Controller Process Error:
+ * the schedule is buggy */
+#define USBSTS_HCH 0x0020 /* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR 4
+#define USBINTR_TIMEOUT 0x0001 /* Timeout/CRC error enable */
+#define USBINTR_RESUME 0x0002 /* Resume interrupt enable */
+#define USBINTR_IOC 0x0004 /* Interrupt On Complete enable */
+#define USBINTR_SP 0x0008 /* Short packet interrupt enable */
+
+#define USBFRNUM 6
+#define USBFLBASEADD 8
+#define USBSOF 12
+#define USBSOF_DEFAULT 64 /* Frame length is exactly 1 ms */
+
+struct uhci_framelist {
+ u32 links[1024];
+} PACKED;
+
+#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */
+#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */
+#define TD_CTRL_C_ERR_SHIFT 27
+#define TD_CTRL_LS (1 << 26) /* Low Speed Device */
+#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */
+#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */
+#define TD_CTRL_ACTIVE (1 << 23) /* TD Active */
+#define TD_CTRL_STALLED (1 << 22) /* TD Stalled */
+#define TD_CTRL_DBUFERR (1 << 21) /* Data Buffer Error */
+#define TD_CTRL_BABBLE (1 << 20) /* Babble Detected */
+#define TD_CTRL_NAK (1 << 19) /* NAK Received */
+#define TD_CTRL_CRCTIMEO (1 << 18) /* CRC/Time Out Error */
+#define TD_CTRL_BITSTUFF (1 << 17) /* Bit Stuff Error */
+#define TD_CTRL_ACTLEN_MASK 0x7FF /* actual length, encoded as n - 1 */
+
+#define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
+ TD_CTRL_BABBLE | TD_CTRL_CRCTIMEO | \
+ TD_CTRL_BITSTUFF)
+#define uhci_maxerr(err) ((err) << TD_CTRL_C_ERR_SHIFT)
+
+#define TD_TOKEN_DEVADDR_SHIFT 8
+#define TD_TOKEN_TOGGLE_SHIFT 19
+#define TD_TOKEN_TOGGLE (1 << 19)
+#define TD_TOKEN_EXPLEN_SHIFT 21
+#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n-1 */
+#define TD_TOKEN_PID_MASK 0xFF
+
+#define uhci_explen(len) ((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \
+ TD_TOKEN_EXPLEN_SHIFT)
+
+#define uhci_expected_length(token) ((((token) >> TD_TOKEN_EXPLEN_SHIFT) + \
+ 1) & TD_TOKEN_EXPLEN_MASK)
+
+struct uhci_td {
+ u32 link;
+ u32 status;
+ u32 token;
+ void *buffer;
+} PACKED;
+
+struct uhci_qh {
+ u32 link;
+ u32 element;
+} PACKED;
+
+#define UHCI_PTR_BITS 0x000F
+#define UHCI_PTR_TERM 0x0001
+#define UHCI_PTR_QH 0x0002
+#define UHCI_PTR_DEPTH 0x0004
+#define UHCI_PTR_BREADTH 0x0000
+
+#endif // usb-uhci.h
diff --git a/roms/seabios-hppa/src/hw/usb-xhci.c b/roms/seabios-hppa/src/hw/usb-xhci.c
new file mode 100644
index 000000000..c35f22119
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-xhci.c
@@ -0,0 +1,1206 @@
+// Code for handling XHCI "Super speed" USB controllers.
+//
+// Copyright (C) 2013 Gerd Hoffmann <kraxel@redhat.com>
+// Copyright (C) 2014 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "malloc.h" // memalign_low
+#include "memmap.h" // PAGE_SIZE
+#include "output.h" // dprintf
+#include "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_XHCI
+#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "string.h" // memcpy
+#include "usb.h" // struct usb_s
+#include "usb-xhci.h" // struct ehci_qh
+#include "util.h" // timer_calc
+#include "x86.h" // readl
+
+// --------------------------------------------------------------
+// configuration
+
+#define XHCI_RING_ITEMS 16
+#define XHCI_RING_SIZE (XHCI_RING_ITEMS*sizeof(struct xhci_trb))
+
+/*
+ * xhci_ring structs are allocated with XHCI_RING_SIZE alignment,
+ * then we can get it from a trb pointer (provided by evt ring).
+ */
+#define XHCI_RING(_trb) \
+ ((struct xhci_ring*)((u32)(_trb) & ~(XHCI_RING_SIZE-1)))
+
+// --------------------------------------------------------------
+// bit definitions
+
+#define XHCI_CMD_RS (1<<0)
+#define XHCI_CMD_HCRST (1<<1)
+#define XHCI_CMD_INTE (1<<2)
+#define XHCI_CMD_HSEE (1<<3)
+#define XHCI_CMD_LHCRST (1<<7)
+#define XHCI_CMD_CSS (1<<8)
+#define XHCI_CMD_CRS (1<<9)
+#define XHCI_CMD_EWE (1<<10)
+#define XHCI_CMD_EU3S (1<<11)
+
+#define XHCI_STS_HCH (1<<0)
+#define XHCI_STS_HSE (1<<2)
+#define XHCI_STS_EINT (1<<3)
+#define XHCI_STS_PCD (1<<4)
+#define XHCI_STS_SSS (1<<8)
+#define XHCI_STS_RSS (1<<9)
+#define XHCI_STS_SRE (1<<10)
+#define XHCI_STS_CNR (1<<11)
+#define XHCI_STS_HCE (1<<12)
+
+#define XHCI_PORTSC_CCS (1<<0)
+#define XHCI_PORTSC_PED (1<<1)
+#define XHCI_PORTSC_OCA (1<<3)
+#define XHCI_PORTSC_PR (1<<4)
+#define XHCI_PORTSC_PLS_SHIFT 5
+#define XHCI_PORTSC_PLS_MASK 0xf
+#define XHCI_PORTSC_PP (1<<9)
+#define XHCI_PORTSC_SPEED_SHIFT 10
+#define XHCI_PORTSC_SPEED_MASK 0xf
+#define XHCI_PORTSC_SPEED_FULL (1<<10)
+#define XHCI_PORTSC_SPEED_LOW (2<<10)
+#define XHCI_PORTSC_SPEED_HIGH (3<<10)
+#define XHCI_PORTSC_SPEED_SUPER (4<<10)
+#define XHCI_PORTSC_PIC_SHIFT 14
+#define XHCI_PORTSC_PIC_MASK 0x3
+#define XHCI_PORTSC_LWS (1<<16)
+#define XHCI_PORTSC_CSC (1<<17)
+#define XHCI_PORTSC_PEC (1<<18)
+#define XHCI_PORTSC_WRC (1<<19)
+#define XHCI_PORTSC_OCC (1<<20)
+#define XHCI_PORTSC_PRC (1<<21)
+#define XHCI_PORTSC_PLC (1<<22)
+#define XHCI_PORTSC_CEC (1<<23)
+#define XHCI_PORTSC_CAS (1<<24)
+#define XHCI_PORTSC_WCE (1<<25)
+#define XHCI_PORTSC_WDE (1<<26)
+#define XHCI_PORTSC_WOE (1<<27)
+#define XHCI_PORTSC_DR (1<<30)
+#define XHCI_PORTSC_WPR (1<<31)
+
+#define TRB_C (1<<0)
+#define TRB_TYPE_SHIFT 10
+#define TRB_TYPE_MASK 0x3f
+#define TRB_TYPE(t) (((t) >> TRB_TYPE_SHIFT) & TRB_TYPE_MASK)
+
+#define TRB_EV_ED (1<<2)
+
+#define TRB_TR_ENT (1<<1)
+#define TRB_TR_ISP (1<<2)
+#define TRB_TR_NS (1<<3)
+#define TRB_TR_CH (1<<4)
+#define TRB_TR_IOC (1<<5)
+#define TRB_TR_IDT (1<<6)
+#define TRB_TR_TBC_SHIFT 7
+#define TRB_TR_TBC_MASK 0x3
+#define TRB_TR_BEI (1<<9)
+#define TRB_TR_TLBPC_SHIFT 16
+#define TRB_TR_TLBPC_MASK 0xf
+#define TRB_TR_FRAMEID_SHIFT 20
+#define TRB_TR_FRAMEID_MASK 0x7ff
+#define TRB_TR_SIA (1<<31)
+
+#define TRB_TR_DIR (1<<16)
+
+#define TRB_CR_SLOTID_SHIFT 24
+#define TRB_CR_SLOTID_MASK 0xff
+#define TRB_CR_EPID_SHIFT 16
+#define TRB_CR_EPID_MASK 0x1f
+
+#define TRB_CR_BSR (1<<9)
+#define TRB_CR_DC (1<<9)
+
+#define TRB_LK_TC (1<<1)
+
+#define TRB_INTR_SHIFT 22
+#define TRB_INTR_MASK 0x3ff
+#define TRB_INTR(t) (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK)
+
+typedef enum TRBType {
+ TRB_RESERVED = 0,
+ TR_NORMAL,
+ TR_SETUP,
+ TR_DATA,
+ TR_STATUS,
+ TR_ISOCH,
+ TR_LINK,
+ TR_EVDATA,
+ TR_NOOP,
+ CR_ENABLE_SLOT,
+ CR_DISABLE_SLOT,
+ CR_ADDRESS_DEVICE,
+ CR_CONFIGURE_ENDPOINT,
+ CR_EVALUATE_CONTEXT,
+ CR_RESET_ENDPOINT,
+ CR_STOP_ENDPOINT,
+ CR_SET_TR_DEQUEUE,
+ CR_RESET_DEVICE,
+ CR_FORCE_EVENT,
+ CR_NEGOTIATE_BW,
+ CR_SET_LATENCY_TOLERANCE,
+ CR_GET_PORT_BANDWIDTH,
+ CR_FORCE_HEADER,
+ CR_NOOP,
+ ER_TRANSFER = 32,
+ ER_COMMAND_COMPLETE,
+ ER_PORT_STATUS_CHANGE,
+ ER_BANDWIDTH_REQUEST,
+ ER_DOORBELL,
+ ER_HOST_CONTROLLER,
+ ER_DEVICE_NOTIFICATION,
+ ER_MFINDEX_WRAP,
+} TRBType;
+
+typedef enum TRBCCode {
+ CC_INVALID = 0,
+ CC_SUCCESS,
+ CC_DATA_BUFFER_ERROR,
+ CC_BABBLE_DETECTED,
+ CC_USB_TRANSACTION_ERROR,
+ CC_TRB_ERROR,
+ CC_STALL_ERROR,
+ CC_RESOURCE_ERROR,
+ CC_BANDWIDTH_ERROR,
+ CC_NO_SLOTS_ERROR,
+ CC_INVALID_STREAM_TYPE_ERROR,
+ CC_SLOT_NOT_ENABLED_ERROR,
+ CC_EP_NOT_ENABLED_ERROR,
+ CC_SHORT_PACKET,
+ CC_RING_UNDERRUN,
+ CC_RING_OVERRUN,
+ CC_VF_ER_FULL,
+ CC_PARAMETER_ERROR,
+ CC_BANDWIDTH_OVERRUN,
+ CC_CONTEXT_STATE_ERROR,
+ CC_NO_PING_RESPONSE_ERROR,
+ CC_EVENT_RING_FULL_ERROR,
+ CC_INCOMPATIBLE_DEVICE_ERROR,
+ CC_MISSED_SERVICE_ERROR,
+ CC_COMMAND_RING_STOPPED,
+ CC_COMMAND_ABORTED,
+ CC_STOPPED,
+ CC_STOPPED_LENGTH_INVALID,
+ CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR = 29,
+ CC_ISOCH_BUFFER_OVERRUN = 31,
+ CC_EVENT_LOST_ERROR,
+ CC_UNDEFINED_ERROR,
+ CC_INVALID_STREAM_ID_ERROR,
+ CC_SECONDARY_BANDWIDTH_ERROR,
+ CC_SPLIT_TRANSACTION_ERROR
+} TRBCCode;
+
+enum {
+ PLS_U0 = 0,
+ PLS_U1 = 1,
+ PLS_U2 = 2,
+ PLS_U3 = 3,
+ PLS_DISABLED = 4,
+ PLS_RX_DETECT = 5,
+ PLS_INACTIVE = 6,
+ PLS_POLLING = 7,
+ PLS_RECOVERY = 8,
+ PLS_HOT_RESET = 9,
+ PLS_COMPILANCE_MODE = 10,
+ PLS_TEST_MODE = 11,
+ PLS_RESUME = 15,
+};
+
+#define xhci_get_field(data, field) \
+ (((data) >> field##_SHIFT) & field##_MASK)
+
+// --------------------------------------------------------------
+// state structs
+
+struct xhci_ring {
+ struct xhci_trb ring[XHCI_RING_ITEMS];
+ struct xhci_trb evt;
+ u32 eidx;
+ u32 nidx;
+ u32 cs;
+ struct mutex_s lock;
+};
+
+struct xhci_portmap {
+ u8 start;
+ u8 count;
+};
+
+struct usb_xhci_s {
+ struct usb_s usb;
+
+ /* devinfo */
+ u32 xcap;
+ u32 ports;
+ u32 slots;
+ u8 context64;
+ struct xhci_portmap usb2;
+ struct xhci_portmap usb3;
+
+ /* xhci registers */
+ struct xhci_caps *caps;
+ struct xhci_op *op;
+ struct xhci_pr *pr;
+ struct xhci_ir *ir;
+ struct xhci_db *db;
+
+ /* xhci data structures */
+ struct xhci_devlist *devs;
+ struct xhci_ring *cmds;
+ struct xhci_ring *evts;
+ struct xhci_er_seg *eseg;
+};
+
+struct xhci_pipe {
+ struct xhci_ring reqs;
+
+ struct usb_pipe pipe;
+ u32 slotid;
+ u32 epid;
+ void *buf;
+ int bufused;
+};
+
+// --------------------------------------------------------------
+// tables
+
+static const char *speed_name[16] = {
+ [ 0 ] = " - ",
+ [ 1 ] = "Full",
+ [ 2 ] = "Low",
+ [ 3 ] = "High",
+ [ 4 ] = "Super",
+};
+
+static const int speed_from_xhci[16] = {
+ [ 0 ] = -1,
+ [ 1 ] = USB_FULLSPEED,
+ [ 2 ] = USB_LOWSPEED,
+ [ 3 ] = USB_HIGHSPEED,
+ [ 4 ] = USB_SUPERSPEED,
+ [ 5 ... 15 ] = -1,
+};
+
+static const int speed_to_xhci[] = {
+ [ USB_FULLSPEED ] = 1,
+ [ USB_LOWSPEED ] = 2,
+ [ USB_HIGHSPEED ] = 3,
+ [ USB_SUPERSPEED ] = 4,
+};
+
+static int wait_bit(u32 *reg, u32 mask, int value, u32 timeout)
+{
+ u32 end = timer_calc(timeout);
+
+ while ((readl(reg) & mask) != value) {
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+ return 0;
+}
+
+
+/****************************************************************
+ * Root hub
+ ****************************************************************/
+
+#define XHCI_TIME_POSTPOWER 20
+
+// Check if device attached to port
+static void
+xhci_print_port_state(int loglevel, const char *prefix, u32 port, u32 portsc)
+{
+ u32 pls = xhci_get_field(portsc, XHCI_PORTSC_PLS);
+ u32 speed = xhci_get_field(portsc, XHCI_PORTSC_SPEED);
+
+ dprintf(loglevel, "%s port #%d: 0x%08x,%s%s pls %d, speed %d [%s]\n",
+ prefix, port + 1, portsc,
+ (portsc & XHCI_PORTSC_PP) ? " powered," : "",
+ (portsc & XHCI_PORTSC_PED) ? " enabled," : "",
+ pls, speed, speed_name[speed]);
+}
+
+static int
+xhci_hub_detect(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);
+ return (portsc & XHCI_PORTSC_CCS) ? 1 : 0;
+}
+
+// Reset device on port
+static int
+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);
+ if (!(portsc & XHCI_PORTSC_CCS))
+ // Device no longer connected?!
+ return -1;
+
+ switch (xhci_get_field(portsc, XHCI_PORTSC_PLS)) {
+ case PLS_U0:
+ // 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);
+ writel(&xhci->pr[port].portsc, portsc | XHCI_PORTSC_PR);
+ break;
+ default:
+ 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;
+}
+
+static int
+xhci_hub_portmap(struct usbhub_s *hub, u32 vport)
+{
+ struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb);
+ u32 pport = vport + 1;
+
+ if (vport + 1 >= xhci->usb3.start &&
+ vport + 1 < xhci->usb3.start + xhci->usb3.count)
+ pport = vport + 2 - xhci->usb3.start;
+
+ if (vport + 1 >= xhci->usb2.start &&
+ vport + 1 < xhci->usb2.start + xhci->usb2.count)
+ pport = vport + 2 - xhci->usb2.start;
+
+ return pport;
+}
+
+static void
+xhci_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+ // XXX - should turn the port power off.
+}
+
+static struct usbhub_op_s xhci_hub_ops = {
+ .detect = xhci_hub_detect,
+ .reset = xhci_hub_reset,
+ .portmap = xhci_hub_portmap,
+ .disconnect = xhci_hub_disconnect,
+};
+
+// Find any devices connected to the root hub.
+static int
+xhci_check_ports(struct usb_xhci_s *xhci)
+{
+ // Wait for port power to stabilize.
+ msleep(XHCI_TIME_POSTPOWER);
+
+ struct usbhub_s hub;
+ memset(&hub, 0, sizeof(hub));
+ hub.cntl = &xhci->usb;
+ hub.portcount = xhci->ports;
+ hub.op = &xhci_hub_ops;
+ usb_enumerate(&hub);
+ return hub.devcount;
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static void
+xhci_free_pipes(struct usb_xhci_s *xhci)
+{
+ // XXX - should walk list of pipes and free unused pipes.
+}
+
+static void
+configure_xhci(void *data)
+{
+ struct usb_xhci_s *xhci = data;
+ u32 reg;
+
+ xhci->devs = memalign_high(64, sizeof(*xhci->devs) * (xhci->slots + 1));
+ xhci->eseg = memalign_high(64, sizeof(*xhci->eseg));
+ xhci->cmds = memalign_high(XHCI_RING_SIZE, sizeof(*xhci->cmds));
+ xhci->evts = memalign_high(XHCI_RING_SIZE, sizeof(*xhci->evts));
+ if (!xhci->devs || !xhci->cmds || !xhci->evts || !xhci->eseg) {
+ warn_noalloc();
+ goto fail;
+ }
+ memset(xhci->devs, 0, sizeof(*xhci->devs) * (xhci->slots + 1));
+ memset(xhci->cmds, 0, sizeof(*xhci->cmds));
+ memset(xhci->evts, 0, sizeof(*xhci->evts));
+ memset(xhci->eseg, 0, sizeof(*xhci->eseg));
+
+ reg = readl(&xhci->op->usbcmd);
+ if (reg & XHCI_CMD_RS) {
+ reg &= ~XHCI_CMD_RS;
+ writel(&xhci->op->usbcmd, reg);
+ if (wait_bit(&xhci->op->usbsts, XHCI_STS_HCH, XHCI_STS_HCH, 32) != 0)
+ goto fail;
+ }
+
+ dprintf(3, "%s: resetting\n", __func__);
+ writel(&xhci->op->usbcmd, XHCI_CMD_HCRST);
+ if (wait_bit(&xhci->op->usbcmd, XHCI_CMD_HCRST, 0, 1000) != 0)
+ goto fail;
+ if (wait_bit(&xhci->op->usbsts, XHCI_STS_CNR, 0, 1000) != 0)
+ goto fail;
+
+ writel(&xhci->op->config, xhci->slots);
+ writel(&xhci->op->dcbaap_low, (u32)xhci->devs);
+ writel(&xhci->op->dcbaap_high, 0);
+ writel(&xhci->op->crcr_low, (u32)xhci->cmds | 1);
+ writel(&xhci->op->crcr_high, 0);
+ xhci->cmds->cs = 1;
+
+ xhci->eseg->ptr_low = (u32)xhci->evts;
+ xhci->eseg->ptr_high = 0;
+ xhci->eseg->size = XHCI_RING_ITEMS;
+ writel(&xhci->ir->erstsz, 1);
+ writel(&xhci->ir->erdp_low, (u32)xhci->evts);
+ writel(&xhci->ir->erdp_high, 0);
+ writel(&xhci->ir->erstba_low, (u32)xhci->eseg);
+ writel(&xhci->ir->erstba_high, 0);
+ xhci->evts->cs = 1;
+
+ reg = readl(&xhci->caps->hcsparams2);
+ 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);
+ void *pad = memalign_high(PAGE_SIZE, PAGE_SIZE * spb);
+ if (!spba || !pad) {
+ warn_noalloc();
+ free(spba);
+ free(pad);
+ goto fail;
+ }
+ int i;
+ for (i = 0; i < spb; i++)
+ spba[i] = (u32)pad + (i * PAGE_SIZE);
+ xhci->devs[0].ptr_low = (u32)spba;
+ xhci->devs[0].ptr_high = 0;
+ }
+
+ reg = readl(&xhci->op->usbcmd);
+ reg |= XHCI_CMD_RS;
+ writel(&xhci->op->usbcmd, reg);
+
+ // Find devices
+ int count = xhci_check_ports(xhci);
+ xhci_free_pipes(xhci);
+ if (count)
+ // Success
+ return;
+
+ // No devices found - shutdown and free controller.
+ dprintf(1, "XHCI no devices found\n");
+ reg = readl(&xhci->op->usbcmd);
+ reg &= ~XHCI_CMD_RS;
+ writel(&xhci->op->usbcmd, reg);
+ wait_bit(&xhci->op->usbsts, XHCI_STS_HCH, XHCI_STS_HCH, 32);
+
+fail:
+ free(xhci->eseg);
+ free(xhci->evts);
+ free(xhci->cmds);
+ free(xhci->devs);
+ free(xhci);
+}
+
+static struct usb_xhci_s*
+xhci_controller_setup(void *baseaddr)
+{
+ struct usb_xhci_s *xhci = malloc_high(sizeof(*xhci));
+ if (!xhci) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(xhci, 0, sizeof(*xhci));
+ xhci->caps = baseaddr;
+ xhci->op = baseaddr + readb(&xhci->caps->caplength);
+ xhci->pr = baseaddr + readb(&xhci->caps->caplength) + 0x400;
+ xhci->db = baseaddr + readl(&xhci->caps->dboff);
+ xhci->ir = baseaddr + readl(&xhci->caps->rtsoff) + 0x20;
+
+ u32 hcs1 = readl(&xhci->caps->hcsparams1);
+ u32 hcc = readl(&xhci->caps->hccparams);
+ xhci->ports = (hcs1 >> 24) & 0xff;
+ xhci->slots = hcs1 & 0xff;
+ xhci->xcap = ((hcc >> 16) & 0xffff) << 2;
+ xhci->context64 = (hcc & 0x04) ? 1 : 0;
+ xhci->usb.type = USB_TYPE_XHCI;
+
+ dprintf(1, "XHCI init: regs @ %p, %d ports, %d slots"
+ ", %d byte contexts\n"
+ , xhci->caps, xhci->ports, xhci->slots
+ , xhci->context64 ? 64 : 32);
+
+ if (xhci->xcap) {
+ u32 off;
+ void *addr = baseaddr + xhci->xcap;
+ do {
+ struct xhci_xcap *xcap = addr;
+ u32 ports, name, cap = readl(&xcap->cap);
+ switch (cap & 0xff) {
+ case 0x02:
+ name = readl(&xcap->data[0]);
+ ports = readl(&xcap->data[1]);
+ u8 major = (cap >> 24) & 0xff;
+ u8 minor = (cap >> 16) & 0xff;
+ u8 count = (ports >> 8) & 0xff;
+ u8 start = (ports >> 0) & 0xff;
+ dprintf(1, "XHCI protocol %c%c%c%c %x.%02x"
+ ", %d ports (offset %d), def %x\n"
+ , (name >> 0) & 0xff
+ , (name >> 8) & 0xff
+ , (name >> 16) & 0xff
+ , (name >> 24) & 0xff
+ , major, minor
+ , count, start
+ , ports >> 16);
+ if (name == 0x20425355 /* "USB " */) {
+ if (major == 2) {
+ xhci->usb2.start = start;
+ xhci->usb2.count = count;
+ }
+ if (major == 3) {
+ xhci->usb3.start = start;
+ xhci->usb3.count = count;
+ }
+ }
+ break;
+ default:
+ dprintf(1, "XHCI extcap 0x%x @ %p\n", cap & 0xff, addr);
+ break;
+ }
+ off = (cap >> 8) & 0xff;
+ addr += off << 2;
+ } while (off > 0);
+ }
+
+ u32 pagesize = readl(&xhci->op->pagesize);
+ if (PAGE_SIZE != (pagesize<<12)) {
+ dprintf(1, "XHCI driver does not support page size code %d\n"
+ , pagesize<<12);
+ free(xhci);
+ return NULL;
+ }
+
+ return xhci;
+}
+
+static void
+xhci_controller_setup_pci(struct pci_device *pci)
+{
+ struct usb_xhci_s *xhci;
+ void *baseaddr;
+
+ baseaddr = pci_enable_membar(pci, PCI_BASE_ADDRESS_0);
+ if (!baseaddr)
+ return;
+
+ dprintf(1, "PCI: XHCI at %pP (mmio %p)\n", pci, baseaddr);
+ pci_enable_busmaster(pci);
+
+ xhci = xhci_controller_setup(baseaddr);
+ if (!xhci)
+ return;
+
+ xhci->usb.pci = pci;
+ run_thread(configure_xhci, xhci);
+}
+
+static void
+xhci_controller_setup_acpi(struct acpi_device *dev)
+{
+ struct usb_xhci_s *xhci;
+ u64 mem, unused;
+ void *baseaddr;
+
+ if (acpi_dsdt_find_mem(dev, &mem, &unused) < 0)
+ return;
+ if (mem >= 0x100000000ll)
+ return;
+
+ baseaddr = (void*)(u32)mem;
+ dprintf(1, "ACPI: XHCI at mmio %p\n", baseaddr);
+
+ xhci = xhci_controller_setup(baseaddr);
+ if (!xhci)
+ return;
+
+ xhci->usb.mmio = baseaddr;
+ run_thread(configure_xhci, xhci);
+}
+
+void
+xhci_setup(void)
+{
+ if (! CONFIG_USB_XHCI)
+ return;
+
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_XHCI)
+ xhci_controller_setup_pci(pci);
+ }
+
+ u16 xhci_eisaid = 0x0d10;
+ struct acpi_device *dev;
+ for (dev = acpi_dsdt_find_eisaid(NULL, xhci_eisaid);
+ dev != NULL;
+ dev = acpi_dsdt_find_eisaid(dev, xhci_eisaid)) {
+ xhci_controller_setup_acpi(dev);
+ }
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+// Signal the hardware to process events on a TRB ring
+static void xhci_doorbell(struct usb_xhci_s *xhci, u32 slotid, u32 value)
+{
+ dprintf(5, "%s: slotid %d, epid %d\n", __func__, slotid, value);
+ struct xhci_db *db = xhci->db;
+ void *addr = &db[slotid].doorbell;
+ writel(addr, value);
+}
+
+// Dequeue events on the XHCI command ring generated by the hardware
+static void xhci_process_events(struct usb_xhci_s *xhci)
+{
+ struct xhci_ring *evts = xhci->evts;
+
+ for (;;) {
+ /* check for event */
+ u32 nidx = evts->nidx;
+ u32 cs = evts->cs;
+ struct xhci_trb *etrb = evts->ring + nidx;
+ u32 control = etrb->control;
+ if ((control & TRB_C) != (cs ? 1 : 0))
+ return;
+
+ /* process event */
+ u32 evt_type = TRB_TYPE(control);
+ u32 evt_cc = (etrb->status >> 24) & 0xff;
+ switch (evt_type) {
+ case ER_TRANSFER:
+ case ER_COMMAND_COMPLETE:
+ {
+ struct xhci_trb *rtrb = (void*)etrb->ptr_low;
+ struct xhci_ring *ring = XHCI_RING(rtrb);
+ struct xhci_trb *evt = &ring->evt;
+ u32 eidx = rtrb - ring->ring + 1;
+ dprintf(5, "%s: ring %p [trb %p, evt %p, type %d, eidx %d, cc %d]\n",
+ __func__, ring, rtrb, evt, evt_type, eidx, evt_cc);
+ memcpy(evt, etrb, sizeof(*etrb));
+ ring->eidx = eidx;
+ break;
+ }
+ case ER_PORT_STATUS_CHANGE:
+ {
+ u32 port = ((etrb->ptr_low >> 24) & 0xff) - 1;
+ // Read status, and clear port status change bits
+ u32 portsc = readl(&xhci->pr[port].portsc);
+ u32 pclear = (((portsc & ~(XHCI_PORTSC_PED|XHCI_PORTSC_PR))
+ & ~(XHCI_PORTSC_PLS_MASK<<XHCI_PORTSC_PLS_SHIFT))
+ | (1<<XHCI_PORTSC_PLS_SHIFT));
+ writel(&xhci->pr[port].portsc, pclear);
+
+ xhci_print_port_state(3, __func__, port, portsc);
+ break;
+ }
+ default:
+ dprintf(1, "%s: unknown event, type %d, cc %d\n",
+ __func__, evt_type, evt_cc);
+ break;
+ }
+
+ /* move ring index, notify xhci */
+ nidx++;
+ if (nidx == XHCI_RING_ITEMS) {
+ nidx = 0;
+ cs = cs ? 0 : 1;
+ evts->cs = cs;
+ }
+ evts->nidx = nidx;
+ struct xhci_ir *ir = xhci->ir;
+ u32 erdp = (u32)(evts->ring + nidx);
+ writel(&ir->erdp_low, erdp);
+ writel(&ir->erdp_high, 0);
+ }
+}
+
+// Check if a ring has any pending TRBs
+static int xhci_ring_busy(struct xhci_ring *ring)
+{
+ u32 eidx = ring->eidx;
+ u32 nidx = ring->nidx;
+ return (eidx != nidx);
+}
+
+// Wait for a ring to empty (all TRBs processed by hardware)
+static int xhci_event_wait(struct usb_xhci_s *xhci,
+ struct xhci_ring *ring,
+ u32 timeout)
+{
+ u32 end = timer_calc(timeout);
+
+ for (;;) {
+ xhci_process_events(xhci);
+ if (!xhci_ring_busy(ring)) {
+ u32 status = ring->evt.status;
+ return (status >> 24) & 0xff;
+ }
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+}
+
+// Add a TRB to the given ring
+static void xhci_trb_fill(struct xhci_ring *ring
+ , void *data, u32 xferlen, u32 flags)
+{
+ struct xhci_trb *dst = &ring->ring[ring->nidx];
+ if (flags & TRB_TR_IDT) {
+ memcpy(&dst->ptr_low, data, xferlen);
+ } else {
+ dst->ptr_low = (u32)data;
+ dst->ptr_high = 0;
+ }
+ dst->status = xferlen;
+ dst->control = flags | (ring->cs ? TRB_C : 0);
+}
+
+// Queue a TRB onto a ring, wrapping ring as needed
+static void xhci_trb_queue(struct xhci_ring *ring,
+ void *data, u32 xferlen, u32 flags)
+{
+ if (ring->nidx >= ARRAY_SIZE(ring->ring) - 1) {
+ xhci_trb_fill(ring, ring->ring, 0, (TR_LINK << 10) | TRB_LK_TC);
+ ring->nidx = 0;
+ ring->cs ^= 1;
+ dprintf(5, "%s: ring %p [linked]\n", __func__, ring);
+ }
+
+ xhci_trb_fill(ring, data, xferlen, flags);
+ ring->nidx++;
+ dprintf(5, "%s: ring %p [nidx %d, len %d]\n",
+ __func__, ring, ring->nidx, xferlen);
+}
+
+// Submit a command to the xhci controller ring
+static int xhci_cmd_submit(struct usb_xhci_s *xhci, struct xhci_inctx *inctx
+ , u32 flags)
+{
+ if (inctx) {
+ struct xhci_slotctx *slot = (void*)&inctx[1 << xhci->context64];
+ u32 port = ((slot->ctx[1] >> 16) & 0xff) - 1;
+ u32 portsc = readl(&xhci->pr[port].portsc);
+ if (!(portsc & XHCI_PORTSC_CCS)) {
+ // Device no longer connected?!
+ xhci_print_port_state(1, __func__, port, portsc);
+ return -1;
+ }
+ }
+
+ mutex_lock(&xhci->cmds->lock);
+ xhci_trb_queue(xhci->cmds, inctx, 0, flags);
+ xhci_doorbell(xhci, 0, 0);
+ int rc = xhci_event_wait(xhci, xhci->cmds, 1000);
+ mutex_unlock(&xhci->cmds->lock);
+ return rc;
+}
+
+static int xhci_cmd_enable_slot(struct usb_xhci_s *xhci)
+{
+ dprintf(3, "%s:\n", __func__);
+ int cc = xhci_cmd_submit(xhci, NULL, CR_ENABLE_SLOT << 10);
+ if (cc != CC_SUCCESS)
+ return -1;
+ return (xhci->cmds->evt.control >> 24) & 0xff;
+}
+
+static int xhci_cmd_disable_slot(struct usb_xhci_s *xhci, u32 slotid)
+{
+ dprintf(3, "%s: slotid %d\n", __func__, slotid);
+ return xhci_cmd_submit(xhci, NULL, (CR_DISABLE_SLOT << 10) | (slotid << 24));
+}
+
+static int xhci_cmd_address_device(struct usb_xhci_s *xhci, u32 slotid
+ , struct xhci_inctx *inctx)
+{
+ dprintf(3, "%s: slotid %d\n", __func__, slotid);
+ return xhci_cmd_submit(xhci, inctx
+ , (CR_ADDRESS_DEVICE << 10) | (slotid << 24));
+}
+
+static int xhci_cmd_configure_endpoint(struct usb_xhci_s *xhci, u32 slotid
+ , struct xhci_inctx *inctx)
+{
+ dprintf(3, "%s: slotid %d, add 0x%x, del 0x%x\n", __func__,
+ slotid, inctx->add, inctx->del);
+ return xhci_cmd_submit(xhci, inctx
+ , (CR_CONFIGURE_ENDPOINT << 10) | (slotid << 24));
+}
+
+static int xhci_cmd_evaluate_context(struct usb_xhci_s *xhci, u32 slotid
+ , struct xhci_inctx *inctx)
+{
+ dprintf(3, "%s: slotid %d, add 0x%x, del 0x%x\n", __func__,
+ slotid, inctx->add, inctx->del);
+ return xhci_cmd_submit(xhci, inctx
+ , (CR_EVALUATE_CONTEXT << 10) | (slotid << 24));
+}
+
+static struct xhci_inctx *
+xhci_alloc_inctx(struct usbdevice_s *usbdev, int maxepid)
+{
+ struct usb_xhci_s *xhci = container_of(
+ usbdev->hub->cntl, struct usb_xhci_s, usb);
+ int size = (sizeof(struct xhci_inctx) * 33) << xhci->context64;
+ struct xhci_inctx *in = memalign_tmphigh(2048 << xhci->context64, size);
+ if (!in) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(in, 0, size);
+
+ struct xhci_slotctx *slot = (void*)&in[1 << xhci->context64];
+ slot->ctx[0] |= maxepid << 27; // context entries
+ slot->ctx[0] |= speed_to_xhci[usbdev->speed] << 20;
+
+ // Set high-speed hub flags.
+ struct usbdevice_s *hubdev = usbdev->hub->usbdev;
+ if (hubdev) {
+ if (usbdev->speed == USB_LOWSPEED || usbdev->speed == USB_FULLSPEED) {
+ struct xhci_pipe *hpipe = container_of(
+ hubdev->defpipe, struct xhci_pipe, pipe);
+ if (hubdev->speed == USB_HIGHSPEED) {
+ slot->ctx[2] |= hpipe->slotid;
+ slot->ctx[2] |= (usbdev->port+1) << 8;
+ } else {
+ struct xhci_slotctx *hslot = (void*)xhci->devs[hpipe->slotid].ptr_low;
+ slot->ctx[2] = hslot->ctx[2];
+ }
+ }
+ u32 route = 0;
+ while (usbdev->hub->usbdev) {
+ route <<= 4;
+ route |= (usbdev->port+1) & 0xf;
+ usbdev = usbdev->hub->usbdev;
+ }
+ slot->ctx[0] |= route;
+ }
+
+ slot->ctx[1] |= (usbdev->port+1) << 16;
+
+ return in;
+}
+
+static int xhci_config_hub(struct usbhub_s *hub)
+{
+ struct usb_xhci_s *xhci = container_of(
+ hub->cntl, struct usb_xhci_s, usb);
+ struct xhci_pipe *pipe = container_of(
+ hub->usbdev->defpipe, struct xhci_pipe, pipe);
+ struct xhci_slotctx *hdslot = (void*)xhci->devs[pipe->slotid].ptr_low;
+ if ((hdslot->ctx[3] >> 27) == 3)
+ // Already configured
+ return 0;
+ struct xhci_inctx *in = xhci_alloc_inctx(hub->usbdev, 1);
+ if (!in)
+ return -1;
+ in->add = 0x01;
+ struct xhci_slotctx *slot = (void*)&in[1 << xhci->context64];
+ slot->ctx[0] |= 1 << 26;
+ slot->ctx[1] |= hub->portcount << 24;
+
+ int cc = xhci_cmd_configure_endpoint(xhci, pipe->slotid, in);
+ free(in);
+ if (cc != CC_SUCCESS) {
+ dprintf(1, "%s: configure hub: failed (cc %d)\n", __func__, cc);
+ return -1;
+ }
+ return 0;
+}
+
+static struct usb_pipe *
+xhci_alloc_pipe(struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ u8 eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ struct usb_xhci_s *xhci = container_of(
+ usbdev->hub->cntl, struct usb_xhci_s, usb);
+ struct xhci_pipe *pipe;
+ u32 epid;
+
+ if (epdesc->bEndpointAddress == 0) {
+ epid = 1;
+ } else {
+ epid = (epdesc->bEndpointAddress & 0x0f) * 2;
+ epid += (epdesc->bEndpointAddress & USB_DIR_IN) ? 1 : 0;
+ }
+
+ if (eptype == USB_ENDPOINT_XFER_CONTROL)
+ pipe = memalign_high(XHCI_RING_SIZE, sizeof(*pipe));
+ else
+ pipe = memalign_low(XHCI_RING_SIZE, sizeof(*pipe));
+ if (!pipe) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+
+ usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
+ pipe->epid = epid;
+ pipe->reqs.cs = 1;
+ 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);
+ if (!in)
+ goto fail;
+ in->add = 0x01 | (1 << epid);
+ struct xhci_epctx *ep = (void*)&in[(pipe->epid+1) << xhci->context64];
+ if (eptype == USB_ENDPOINT_XFER_INT)
+ ep->ctx[0] = (usb_get_period(usbdev, epdesc) + 3) << 16;
+ ep->ctx[1] |= eptype << 3;
+ if (epdesc->bEndpointAddress & USB_DIR_IN
+ || eptype == USB_ENDPOINT_XFER_CONTROL)
+ ep->ctx[1] |= 1 << 5;
+ ep->ctx[1] |= pipe->pipe.maxpacket << 16;
+ ep->deq_low = (u32)&pipe->reqs.ring[0];
+ ep->deq_low |= 1; // dcs
+ ep->length = pipe->pipe.maxpacket;
+
+ dprintf(3, "%s: usbdev %p, ring %p, slotid %d, epid %d\n", __func__,
+ usbdev, &pipe->reqs, pipe->slotid, pipe->epid);
+ if (pipe->epid == 1) {
+ if (usbdev->hub->usbdev) {
+ // Make sure parent hub is configured.
+ int ret = xhci_config_hub(usbdev->hub);
+ if (ret)
+ goto fail;
+ }
+ // Enable slot.
+ u32 size = (sizeof(struct xhci_slotctx) * 32) << xhci->context64;
+ struct xhci_slotctx *dev = memalign_high(1024 << xhci->context64, size);
+ if (!dev) {
+ warn_noalloc();
+ goto fail;
+ }
+ int slotid = xhci_cmd_enable_slot(xhci);
+ if (slotid < 0) {
+ dprintf(1, "%s: enable slot: failed\n", __func__);
+ free(dev);
+ goto fail;
+ }
+ dprintf(3, "%s: enable slot: got slotid %d\n", __func__, slotid);
+ memset(dev, 0, size);
+ xhci->devs[slotid].ptr_low = (u32)dev;
+ xhci->devs[slotid].ptr_high = 0;
+
+ // Send set_address command.
+ int cc = xhci_cmd_address_device(xhci, slotid, in);
+ if (cc != CC_SUCCESS) {
+ dprintf(1, "%s: address device: failed (cc %d)\n", __func__, cc);
+ cc = xhci_cmd_disable_slot(xhci, slotid);
+ if (cc != CC_SUCCESS) {
+ dprintf(1, "%s: disable failed (cc %d)\n", __func__, cc);
+ goto fail;
+ }
+ xhci->devs[slotid].ptr_low = 0;
+ free(dev);
+ goto fail;
+ }
+ pipe->slotid = slotid;
+ } else {
+ struct xhci_pipe *defpipe = container_of(
+ usbdev->defpipe, struct xhci_pipe, pipe);
+ pipe->slotid = defpipe->slotid;
+ // Send configure command.
+ int cc = xhci_cmd_configure_endpoint(xhci, pipe->slotid, in);
+ if (cc != CC_SUCCESS) {
+ dprintf(1, "%s: configure endpoint: failed (cc %d)\n", __func__, cc);
+ goto fail;
+ }
+ }
+ free(in);
+ return &pipe->pipe;
+
+fail:
+ free(pipe->buf);
+ free(pipe);
+ free(in);
+ return NULL;
+}
+
+struct usb_pipe *
+xhci_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *upipe
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ if (!CONFIG_USB_XHCI)
+ return NULL;
+ if (!epdesc) {
+ usb_add_freelist(upipe);
+ return NULL;
+ }
+ if (!upipe)
+ return xhci_alloc_pipe(usbdev, epdesc);
+ u8 eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ int oldmaxpacket = upipe->maxpacket;
+ usb_desc2pipe(upipe, usbdev, epdesc);
+ struct xhci_pipe *pipe = container_of(upipe, struct xhci_pipe, pipe);
+ struct usb_xhci_s *xhci = container_of(
+ pipe->pipe.cntl, struct usb_xhci_s, usb);
+ dprintf(3, "%s: usbdev %p, ring %p, slotid %d, epid %d\n", __func__,
+ usbdev, &pipe->reqs, pipe->slotid, pipe->epid);
+ if (eptype != USB_ENDPOINT_XFER_CONTROL || upipe->maxpacket == oldmaxpacket)
+ return upipe;
+
+ // maxpacket has changed on control endpoint - update controller.
+ dprintf(1, "%s: reconf ctl endpoint pkt size: %d -> %d\n",
+ __func__, oldmaxpacket, pipe->pipe.maxpacket);
+ struct xhci_inctx *in = xhci_alloc_inctx(usbdev, 1);
+ if (!in)
+ return upipe;
+ in->add = (1 << 1);
+ struct xhci_epctx *ep = (void*)&in[2 << xhci->context64];
+ ep->ctx[1] |= (pipe->pipe.maxpacket << 16);
+ int cc = xhci_cmd_evaluate_context(xhci, pipe->slotid, in);
+ if (cc != CC_SUCCESS) {
+ dprintf(1, "%s: reconf ctl endpoint: failed (cc %d)\n",
+ __func__, cc);
+ }
+ free(in);
+
+ return upipe;
+}
+
+// Submit a USB "setup" message request to the pipe's ring
+static void xhci_xfer_setup(struct xhci_pipe *pipe, int dir, void *cmd
+ , void *data, int datalen)
+{
+ struct usb_xhci_s *xhci = container_of(
+ pipe->pipe.cntl, struct usb_xhci_s, usb);
+ xhci_trb_queue(&pipe->reqs, cmd, USB_CONTROL_SETUP_SIZE
+ , (TR_SETUP << 10) | TRB_TR_IDT
+ | ((datalen ? (dir ? 3 : 2) : 0) << 16));
+ if (datalen)
+ xhci_trb_queue(&pipe->reqs, data, datalen, (TR_DATA << 10)
+ | ((dir ? 1 : 0) << 16));
+ xhci_trb_queue(&pipe->reqs, NULL, 0, (TR_STATUS << 10) | TRB_TR_IOC
+ | ((dir ? 0 : 1) << 16));
+ xhci_doorbell(xhci, pipe->slotid, pipe->epid);
+}
+
+// Submit a USB transfer request to the pipe's ring
+static void xhci_xfer_normal(struct xhci_pipe *pipe,
+ void *data, int datalen)
+{
+ struct usb_xhci_s *xhci = container_of(
+ pipe->pipe.cntl, struct usb_xhci_s, usb);
+ xhci_trb_queue(&pipe->reqs, data, datalen, (TR_NORMAL << 10) | TRB_TR_IOC);
+ xhci_doorbell(xhci, pipe->slotid, pipe->epid);
+}
+
+int
+xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd
+ , void *data, int datalen)
+{
+ if (!CONFIG_USB_XHCI)
+ return -1;
+ struct xhci_pipe *pipe = container_of(p, struct xhci_pipe, pipe);
+ struct usb_xhci_s *xhci = container_of(
+ pipe->pipe.cntl, struct usb_xhci_s, usb);
+
+ if (cmd) {
+ const struct usb_ctrlrequest *req = cmd;
+ if (req->bRequest == USB_REQ_SET_ADDRESS)
+ // Set address command sent during xhci_alloc_pipe.
+ return 0;
+ xhci_xfer_setup(pipe, dir, (void*)req, data, datalen);
+ } else {
+ xhci_xfer_normal(pipe, data, datalen);
+ }
+
+ int cc = xhci_event_wait(xhci, &pipe->reqs, usb_xfer_time(p, datalen));
+ if (cc != CC_SUCCESS) {
+ dprintf(1, "%s: xfer failed (cc %d)\n", __func__, cc);
+ return -1;
+ }
+
+ return 0;
+}
+
+int VISIBLE32FLAT
+xhci_poll_intr(struct usb_pipe *p, void *data)
+{
+ if (!CONFIG_USB_XHCI)
+ return -1;
+
+ struct xhci_pipe *pipe = container_of(p, struct xhci_pipe, pipe);
+ struct usb_xhci_s *xhci = container_of(
+ pipe->pipe.cntl, struct usb_xhci_s, usb);
+ u32 len = pipe->pipe.maxpacket;
+ void *buf = pipe->buf;
+ int bufused = pipe->bufused;
+
+ if (!bufused) {
+ xhci_xfer_normal(pipe, buf, len);
+ bufused = 1;
+ pipe->bufused = bufused;
+ return -1;
+ }
+
+ xhci_process_events(xhci);
+ if (xhci_ring_busy(&pipe->reqs))
+ return -1;
+ dprintf(5, "%s: st %x ct %x [ %p <= %p / %d ]\n", __func__,
+ pipe->reqs.evt.status,
+ pipe->reqs.evt.control,
+ data, buf, len);
+ memcpy(data, buf, len);
+ xhci_xfer_normal(pipe, buf, len);
+ return 0;
+}
diff --git a/roms/seabios-hppa/src/hw/usb-xhci.h b/roms/seabios-hppa/src/hw/usb-xhci.h
new file mode 100644
index 000000000..c768c5b58
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb-xhci.h
@@ -0,0 +1,133 @@
+#ifndef __USB_XHCI_H
+#define __USB_XHCI_H
+
+struct usbdevice_s;
+struct usb_endpoint_descriptor;
+struct usb_pipe;
+
+// --------------------------------------------------------------
+
+// usb-xhci.c
+void xhci_setup(void);
+struct usb_pipe *xhci_realloc_pipe(struct usbdevice_s *usbdev
+ , struct usb_pipe *upipe
+ , struct usb_endpoint_descriptor *epdesc);
+int xhci_send_pipe(struct usb_pipe *p, int dir, const void *cmd
+ , void *data, int datasize);
+int xhci_poll_intr(struct usb_pipe *p, void *data);
+
+// --------------------------------------------------------------
+// register interface
+
+// capabilities
+struct xhci_caps {
+ u8 caplength;
+ u8 reserved_01;
+ u16 hciversion;
+ u32 hcsparams1;
+ u32 hcsparams2;
+ u32 hcsparams3;
+ u32 hccparams;
+ u32 dboff;
+ u32 rtsoff;
+} PACKED;
+
+// extended capabilities
+struct xhci_xcap {
+ u32 cap;
+ u32 data[];
+} PACKED;
+
+// operational registers
+struct xhci_op {
+ u32 usbcmd;
+ u32 usbsts;
+ u32 pagesize;
+ u32 reserved_01[2];
+ u32 dnctl;
+ u32 crcr_low;
+ u32 crcr_high;
+ u32 reserved_02[4];
+ u32 dcbaap_low;
+ u32 dcbaap_high;
+ u32 config;
+} PACKED;
+
+// port registers
+struct xhci_pr {
+ u32 portsc;
+ u32 portpmsc;
+ u32 portli;
+ u32 reserved_01;
+} PACKED;
+
+// doorbell registers
+struct xhci_db {
+ u32 doorbell;
+} PACKED;
+
+// runtime registers
+struct xhci_rts {
+ u32 mfindex;
+} PACKED;
+
+// interrupter registers
+struct xhci_ir {
+ u32 iman;
+ u32 imod;
+ u32 erstsz;
+ u32 reserved_01;
+ u32 erstba_low;
+ u32 erstba_high;
+ u32 erdp_low;
+ u32 erdp_high;
+} PACKED;
+
+// --------------------------------------------------------------
+// memory data structs
+
+// slot context
+struct xhci_slotctx {
+ u32 ctx[4];
+ u32 reserved_01[4];
+} PACKED;
+
+// endpoint context
+struct xhci_epctx {
+ u32 ctx[2];
+ u32 deq_low;
+ u32 deq_high;
+ u32 length;
+ u32 reserved_01[3];
+} PACKED;
+
+// device context array element
+struct xhci_devlist {
+ u32 ptr_low;
+ u32 ptr_high;
+} PACKED;
+
+// input context
+struct xhci_inctx {
+ u32 del;
+ u32 add;
+ u32 reserved_01[6];
+} PACKED;
+
+// transfer block (ring element)
+struct xhci_trb {
+ u32 ptr_low;
+ u32 ptr_high;
+ u32 status;
+ u32 control;
+} PACKED;
+
+// event ring segment
+struct xhci_er_seg {
+ u32 ptr_low;
+ u32 ptr_high;
+ u32 size;
+ u32 reserved_01;
+} PACKED;
+
+#endif // usb-xhci.h
diff --git a/roms/seabios-hppa/src/hw/usb.c b/roms/seabios-hppa/src/hw/usb.c
new file mode 100644
index 000000000..38a866adb
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb.c
@@ -0,0 +1,510 @@
+// Main code for handling USB controllers and devices.
+//
+// Copyright (C) 2009-2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "config.h" // CONFIG_*
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "romfile.h" // romfile_loadint
+#include "string.h" // memset
+#include "usb.h" // struct usb_s
+#include "usb-ehci.h" // ehci_setup
+#include "usb-xhci.h" // xhci_setup
+#include "usb-hid.h" // usb_keyboard_setup
+#include "usb-hub.h" // usb_hub_setup
+#include "usb-msc.h" // usb_msc_setup
+#include "usb-ohci.h" // ohci_setup
+#include "usb-uas.h" // usb_uas_setup
+#include "usb-uhci.h" // uhci_setup
+#include "util.h" // msleep
+#include "x86.h" // __fls
+
+
+/****************************************************************
+ * Controller function wrappers
+ ****************************************************************/
+
+// Allocate, update, or free a usb pipe.
+static struct usb_pipe *
+usb_realloc_pipe(struct usbdevice_s *usbdev, struct usb_pipe *pipe
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ switch (usbdev->hub->cntl->type) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_realloc_pipe(usbdev, pipe, epdesc);
+ case USB_TYPE_OHCI:
+ return ohci_realloc_pipe(usbdev, pipe, epdesc);
+ case USB_TYPE_EHCI:
+ return ehci_realloc_pipe(usbdev, pipe, epdesc);
+ case USB_TYPE_XHCI:
+ return xhci_realloc_pipe(usbdev, pipe, epdesc);
+ }
+}
+
+// Send a message on a control pipe using the default control descriptor.
+static int
+usb_send_pipe(struct usb_pipe *pipe_fl, int dir, const void *cmd
+ , void *data, int datasize)
+{
+ switch (GET_LOWFLAT(pipe_fl->type)) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_send_pipe(pipe_fl, dir, cmd, data, datasize);
+ case USB_TYPE_OHCI:
+ if (MODESEGMENT)
+ return -1;
+ return ohci_send_pipe(pipe_fl, dir, cmd, data, datasize);
+ case USB_TYPE_EHCI:
+ return ehci_send_pipe(pipe_fl, dir, cmd, data, datasize);
+ case USB_TYPE_XHCI:
+ if (MODESEGMENT)
+ return -1;
+ return xhci_send_pipe(pipe_fl, dir, cmd, data, datasize);
+ }
+}
+
+int
+usb_poll_intr(struct usb_pipe *pipe_fl, void *data)
+{
+ ASSERT16();
+ switch (GET_LOWFLAT(pipe_fl->type)) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_poll_intr(pipe_fl, data);
+ case USB_TYPE_OHCI:
+ return ohci_poll_intr(pipe_fl, data);
+ case USB_TYPE_EHCI:
+ return ehci_poll_intr(pipe_fl, data);
+ case USB_TYPE_XHCI: ;
+ return call32_params(xhci_poll_intr, pipe_fl
+ , MAKE_FLATPTR(GET_SEG(SS), data), 0, -1);
+ }
+}
+
+int usb_32bit_pipe(struct usb_pipe *pipe_fl)
+{
+ return (CONFIG_USB_XHCI && GET_LOWFLAT(pipe_fl->type) == USB_TYPE_XHCI)
+ || (CONFIG_USB_OHCI && GET_LOWFLAT(pipe_fl->type) == USB_TYPE_OHCI);
+}
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Allocate a usb pipe.
+struct usb_pipe *
+usb_alloc_pipe(struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ return usb_realloc_pipe(usbdev, NULL, epdesc);
+}
+
+// Free an allocated control or bulk pipe.
+void
+usb_free_pipe(struct usbdevice_s *usbdev, struct usb_pipe *pipe)
+{
+ if (!pipe)
+ return;
+ usb_realloc_pipe(usbdev, pipe, NULL);
+}
+
+// Send a message to the default control pipe of a device.
+int
+usb_send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
+ , void *data)
+{
+ return usb_send_pipe(pipe, req->bRequestType & USB_DIR_IN, req
+ , data, req->wLength);
+}
+
+// Send a message to a bulk endpoint
+int
+usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize)
+{
+ return usb_send_pipe(pipe_fl, dir, NULL, data, datasize);
+}
+
+// Check if a pipe for a given controller is on the freelist
+int
+usb_is_freelist(struct usb_s *cntl, struct usb_pipe *pipe)
+{
+ return pipe->cntl != cntl;
+}
+
+// Add a pipe to the controller's freelist
+void
+usb_add_freelist(struct usb_pipe *pipe)
+{
+ if (!pipe)
+ return;
+ struct usb_s *cntl = pipe->cntl;
+ pipe->freenext = cntl->freelist;
+ cntl->freelist = pipe;
+}
+
+// Check for an available pipe on the freelist.
+struct usb_pipe *
+usb_get_freelist(struct usb_s *cntl, u8 eptype)
+{
+ struct usb_pipe **pfree = &cntl->freelist;
+ for (;;) {
+ struct usb_pipe *pipe = *pfree;
+ if (!pipe)
+ return NULL;
+ if (pipe->eptype == eptype) {
+ *pfree = pipe->freenext;
+ return pipe;
+ }
+ pfree = &pipe->freenext;
+ }
+}
+
+// Fill "pipe" endpoint info from an endpoint descriptor.
+void
+usb_desc2pipe(struct usb_pipe *pipe, struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ pipe->cntl = usbdev->hub->cntl;
+ pipe->type = usbdev->hub->cntl->type;
+ pipe->ep = epdesc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ pipe->devaddr = usbdev->devaddr;
+ pipe->speed = usbdev->speed;
+ pipe->maxpacket = epdesc->wMaxPacketSize;
+ pipe->eptype = epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+}
+
+// Find the exponential period of the requested interrupt end point.
+int
+usb_get_period(struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ int period = epdesc->bInterval;
+ if (usbdev->speed != USB_HIGHSPEED)
+ return (period <= 0) ? 0 : __fls(period);
+ return (period <= 4) ? 0 : period - 4;
+}
+
+// Maximum time (in ms) a data transfer should take
+int
+usb_xfer_time(struct usb_pipe *pipe, int datalen)
+{
+ // Use the maximum command time (5 seconds), except for
+ // set_address commands where we don't want to stall the boot if
+ // the device doesn't actually exist. Add 100ms to account for
+ // any controller delays.
+ if (!GET_LOWFLAT(pipe->devaddr))
+ return USB_TIME_STATUS + 100;
+ return USB_TIME_COMMAND + 100;
+}
+
+// Find the first endpoint of a given type in an interface description.
+struct usb_endpoint_descriptor *
+usb_find_desc(struct usbdevice_s *usbdev, int type, int dir)
+{
+ struct usb_endpoint_descriptor *epdesc = (void*)&usbdev->iface[1];
+ for (;;) {
+ if ((void*)epdesc >= (void*)usbdev->iface + usbdev->imax
+ || epdesc->bDescriptorType == USB_DT_INTERFACE) {
+ return NULL;
+ }
+ if (epdesc->bDescriptorType == USB_DT_ENDPOINT
+ && (epdesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir
+ && (epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == type)
+ return epdesc;
+ epdesc = (void*)epdesc + epdesc->bLength;
+ }
+}
+
+// Get the first 8 bytes of the device descriptor.
+static int
+get_device_info8(struct usb_pipe *pipe, struct usb_device_descriptor *dinfo)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
+ req.bRequest = USB_REQ_GET_DESCRIPTOR;
+ req.wValue = USB_DT_DEVICE<<8;
+ req.wIndex = 0;
+ req.wLength = 8;
+ return usb_send_default_control(pipe, &req, dinfo);
+}
+
+static struct usb_config_descriptor *
+get_device_config(struct usb_pipe *pipe)
+{
+ struct usb_config_descriptor cfg;
+
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
+ req.bRequest = USB_REQ_GET_DESCRIPTOR;
+ req.wValue = USB_DT_CONFIG<<8;
+ req.wIndex = 0;
+ req.wLength = sizeof(cfg);
+ int ret = usb_send_default_control(pipe, &req, &cfg);
+ if (ret)
+ return NULL;
+
+ struct usb_config_descriptor *config = malloc_tmphigh(cfg.wTotalLength);
+ if (!config) {
+ warn_noalloc();
+ return NULL;
+ }
+ req.wLength = cfg.wTotalLength;
+ ret = usb_send_default_control(pipe, &req, config);
+ if (ret || config->wTotalLength != cfg.wTotalLength) {
+ free(config);
+ return NULL;
+ }
+ //hexdump(config, cfg.wTotalLength);
+ return config;
+}
+
+static int
+set_configuration(struct usb_pipe *pipe, u16 val)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
+ req.bRequest = USB_REQ_SET_CONFIGURATION;
+ req.wValue = val;
+ req.wIndex = 0;
+ req.wLength = 0;
+ return usb_send_default_control(pipe, &req, NULL);
+}
+
+
+/****************************************************************
+ * Initialization and enumeration
+ ****************************************************************/
+
+static const int speed_to_ctlsize[] = {
+ [ USB_FULLSPEED ] = 8,
+ [ USB_LOWSPEED ] = 8,
+ [ USB_HIGHSPEED ] = 64,
+ [ USB_SUPERSPEED ] = 512,
+};
+
+// Assign an address to a device in the default state on the given
+// controller.
+static int
+usb_set_address(struct usbdevice_s *usbdev)
+{
+ ASSERT32FLAT();
+ struct usb_s *cntl = usbdev->hub->cntl;
+ dprintf(3, "set_address %p\n", cntl);
+ if (cntl->maxaddr >= USB_MAXADDR)
+ return -1;
+
+ msleep(USB_TIME_RSTRCY);
+
+ // Create a pipe for the default address.
+ struct usb_endpoint_descriptor epdesc = {
+ .wMaxPacketSize = speed_to_ctlsize[usbdev->speed],
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ };
+ usbdev->defpipe = usb_alloc_pipe(usbdev, &epdesc);
+ if (!usbdev->defpipe)
+ return -1;
+
+ // Send set_address command.
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
+ req.bRequest = USB_REQ_SET_ADDRESS;
+ req.wValue = cntl->maxaddr + 1;
+ req.wIndex = 0;
+ req.wLength = 0;
+ int ret = usb_send_default_control(usbdev->defpipe, &req, NULL);
+ if (ret) {
+ usb_free_pipe(usbdev, usbdev->defpipe);
+ return -1;
+ }
+
+ msleep(USB_TIME_SETADDR_RECOVERY);
+
+ cntl->maxaddr++;
+ usbdev->devaddr = cntl->maxaddr;
+ usbdev->defpipe = usb_realloc_pipe(usbdev, usbdev->defpipe, &epdesc);
+ if (!usbdev->defpipe)
+ return -1;
+ return 0;
+}
+
+// Called for every found device - see if a driver is available for
+// this device and do setup if so.
+static int
+configure_usb_device(struct usbdevice_s *usbdev)
+{
+ ASSERT32FLAT();
+ dprintf(3, "config_usb: %p\n", usbdev->defpipe);
+
+ // Set the max packet size for endpoint 0 of this device.
+ struct usb_device_descriptor dinfo;
+ int ret = get_device_info8(usbdev->defpipe, &dinfo);
+ if (ret)
+ return 0;
+ u16 maxpacket = dinfo.bMaxPacketSize0;
+ if (dinfo.bcdUSB >= 0x0300)
+ maxpacket = 1 << dinfo.bMaxPacketSize0;
+ dprintf(3, "device rev=%04x cls=%02x sub=%02x proto=%02x size=%d\n"
+ , dinfo.bcdUSB, dinfo.bDeviceClass, dinfo.bDeviceSubClass
+ , dinfo.bDeviceProtocol, maxpacket);
+ if (maxpacket < 8)
+ return 0;
+ struct usb_endpoint_descriptor epdesc = {
+ .wMaxPacketSize = maxpacket,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ };
+ usbdev->defpipe = usb_realloc_pipe(usbdev, usbdev->defpipe, &epdesc);
+ if (!usbdev->defpipe)
+ return -1;
+
+ // Get configuration
+ struct usb_config_descriptor *config = get_device_config(usbdev->defpipe);
+ if (!config)
+ return 0;
+
+ // Determine if a driver exists for this device - only look at the
+ // interfaces of the first configuration.
+ int num_iface = config->bNumInterfaces;
+ void *config_end = (void*)config + config->wTotalLength;
+ struct usb_interface_descriptor *iface = (void*)(&config[1]);
+ for (;;) {
+ if (!num_iface-- || (void*)iface + iface->bLength > config_end)
+ // Not a supported device.
+ goto fail;
+ if (iface->bDescriptorType == USB_DT_INTERFACE
+ && (iface->bInterfaceClass == USB_CLASS_HUB
+ || (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE
+ && (iface->bInterfaceProtocol == US_PR_BULK
+ || iface->bInterfaceProtocol == US_PR_UAS))
+ || (iface->bInterfaceClass == USB_CLASS_HID
+ && iface->bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT)))
+ break;
+ iface = (void*)iface + iface->bLength;
+ }
+
+ // Set the configuration.
+ ret = set_configuration(usbdev->defpipe, config->bConfigurationValue);
+ if (ret)
+ goto fail;
+
+ // Configure driver.
+ usbdev->config = config;
+ usbdev->iface = iface;
+ usbdev->imax = (void*)config + config->wTotalLength - (void*)iface;
+ if (iface->bInterfaceClass == USB_CLASS_HUB)
+ ret = usb_hub_setup(usbdev);
+ else if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE) {
+ if (iface->bInterfaceProtocol == US_PR_BULK)
+ ret = usb_msc_setup(usbdev);
+ if (iface->bInterfaceProtocol == US_PR_UAS)
+ ret = usb_uas_setup(usbdev);
+ } else
+ ret = usb_hid_setup(usbdev);
+ if (ret)
+ goto fail;
+
+ free(config);
+ return 1;
+fail:
+ free(config);
+ return 0;
+}
+
+static void
+usb_hub_port_setup(void *data)
+{
+ struct usbdevice_s *usbdev = data;
+ struct usbhub_s *hub = usbdev->hub;
+ u32 port = usbdev->port;
+
+ for (;;) {
+ // Detect if device present (and possibly start reset)
+ int ret = hub->op->detect(hub, port);
+ if (ret > 0)
+ // Device connected.
+ break;
+ if (ret < 0 || timer_check(hub->detectend))
+ // No device found.
+ goto done;
+ msleep(5);
+ }
+
+ // XXX - wait USB_TIME_ATTDB time?
+
+ // Reset port and determine device speed
+ mutex_lock(&hub->cntl->resetlock);
+ int ret = hub->op->reset(hub, port);
+ if (ret < 0)
+ // Reset failed
+ goto resetfail;
+ usbdev->speed = ret;
+
+ // Set address of port
+ ret = usb_set_address(usbdev);
+ if (ret) {
+ hub->op->disconnect(hub, port);
+ goto resetfail;
+ }
+ mutex_unlock(&hub->cntl->resetlock);
+
+ // Configure the device
+ int count = configure_usb_device(usbdev);
+ usb_free_pipe(usbdev, usbdev->defpipe);
+ if (!count)
+ hub->op->disconnect(hub, port);
+ hub->devcount += count;
+done:
+ hub->threads--;
+ free(usbdev);
+ return;
+
+resetfail:
+ mutex_unlock(&hub->cntl->resetlock);
+ goto done;
+}
+
+static u32 usb_time_sigatt;
+
+void
+usb_enumerate(struct usbhub_s *hub)
+{
+ u32 portcount = hub->portcount;
+ hub->threads = portcount;
+ hub->detectend = timer_calc(usb_time_sigatt);
+
+ // Launch a thread for every port.
+ int i;
+ for (i=0; i<portcount; i++) {
+ struct usbdevice_s *usbdev = malloc_tmphigh(sizeof(*usbdev));
+ if (!usbdev) {
+ warn_noalloc();
+ continue;
+ }
+ memset(usbdev, 0, sizeof(*usbdev));
+ usbdev->hub = hub;
+ usbdev->port = i;
+ run_thread(usb_hub_port_setup, usbdev);
+ }
+
+ // Wait for threads to complete.
+ while (hub->threads)
+ yield();
+}
+
+void
+usb_setup(void)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_USB)
+ return;
+ dprintf(3, "init usb\n");
+ usb_time_sigatt = romfile_loadint("etc/usb-time-sigatt", USB_TIME_SIGATT);
+ xhci_setup();
+ ehci_setup();
+ uhci_setup();
+ ohci_setup();
+}
diff --git a/roms/seabios-hppa/src/hw/usb.h b/roms/seabios-hppa/src/hw/usb.h
new file mode 100644
index 000000000..887f2064c
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/usb.h
@@ -0,0 +1,255 @@
+// USB functions and data.
+#ifndef __USB_H
+#define __USB_H
+
+#include "stacks.h" // struct mutex_s
+
+// Information on a USB end point.
+struct usb_pipe {
+ union {
+ struct usb_s *cntl;
+ struct usb_pipe *freenext;
+ };
+ u8 type;
+ u8 ep;
+ u8 devaddr;
+ u8 speed;
+ u16 maxpacket;
+ u8 eptype;
+};
+
+// Common information for usb devices.
+struct usbdevice_s {
+ struct usbhub_s *hub;
+ struct usb_pipe *defpipe;
+ u32 port;
+ struct usb_config_descriptor *config;
+ struct usb_interface_descriptor *iface;
+ int imax;
+ u8 speed;
+ u8 devaddr;
+};
+
+// Common information for usb controllers.
+struct usb_s {
+ struct usb_pipe *freelist;
+ struct mutex_s resetlock;
+ struct pci_device *pci;
+ void *mmio;
+ u8 type;
+ u8 maxaddr;
+};
+
+// Information for enumerating USB hubs
+struct usbhub_s {
+ struct usbhub_op_s *op;
+ struct usbdevice_s *usbdev;
+ struct usb_s *cntl;
+ struct mutex_s lock;
+ u32 detectend;
+ u32 port;
+ u32 threads;
+ u32 portcount;
+ u32 devcount;
+};
+
+// Hub callback (32bit) info
+struct usbhub_op_s {
+ int (*detect)(struct usbhub_s *hub, u32 port);
+ int (*reset)(struct usbhub_s *hub, u32 port);
+ int (*portmap)(struct usbhub_s *hub, u32 port);
+ void (*disconnect)(struct usbhub_s *hub, u32 port);
+};
+
+#define USB_TYPE_UHCI 1
+#define USB_TYPE_OHCI 2
+#define USB_TYPE_EHCI 3
+#define USB_TYPE_XHCI 4
+
+#define USB_FULLSPEED 0
+#define USB_LOWSPEED 1
+#define USB_HIGHSPEED 2
+#define USB_SUPERSPEED 3
+
+#define USB_MAXADDR 127
+
+
+/****************************************************************
+ * usb structs and flags
+ ****************************************************************/
+
+// USB mandated timings (in ms)
+#define USB_TIME_SIGATT 100
+#define USB_TIME_ATTDB 100
+#define USB_TIME_DRST 10
+#define USB_TIME_DRSTR 50
+#define USB_TIME_RSTRCY 10
+
+#define USB_TIME_STATUS 50
+#define USB_TIME_DATAIN 500
+#define USB_TIME_COMMAND 5000
+
+#define USB_TIME_SETADDR_RECOVERY 2
+
+#define USB_PID_OUT 0xe1
+#define USB_PID_IN 0x69
+#define USB_PID_SETUP 0x2d
+
+#define USB_DIR_OUT 0 /* to device */
+#define USB_DIR_IN 0x80 /* to host */
+
+#define USB_TYPE_MASK (0x03 << 5)
+#define USB_TYPE_STANDARD (0x00 << 5)
+#define USB_TYPE_CLASS (0x01 << 5)
+#define USB_TYPE_VENDOR (0x02 << 5)
+#define USB_TYPE_RESERVED (0x03 << 5)
+
+#define USB_RECIP_MASK 0x1f
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+#define USB_REQ_GET_STATUS 0x00
+#define USB_REQ_CLEAR_FEATURE 0x01
+#define USB_REQ_SET_FEATURE 0x03
+#define USB_REQ_SET_ADDRESS 0x05
+#define USB_REQ_GET_DESCRIPTOR 0x06
+#define USB_REQ_SET_DESCRIPTOR 0x07
+#define USB_REQ_GET_CONFIGURATION 0x08
+#define USB_REQ_SET_CONFIGURATION 0x09
+#define USB_REQ_GET_INTERFACE 0x0A
+#define USB_REQ_SET_INTERFACE 0x0B
+#define USB_REQ_SYNCH_FRAME 0x0C
+
+struct usb_ctrlrequest {
+ u8 bRequestType;
+ u8 bRequest;
+ u16 wValue;
+ u16 wIndex;
+ u16 wLength;
+} PACKED;
+
+#define USB_DT_DEVICE 0x01
+#define USB_DT_CONFIG 0x02
+#define USB_DT_STRING 0x03
+#define USB_DT_INTERFACE 0x04
+#define USB_DT_ENDPOINT 0x05
+#define USB_DT_DEVICE_QUALIFIER 0x06
+#define USB_DT_OTHER_SPEED_CONFIG 0x07
+#define USB_DT_ENDPOINT_COMPANION 0x30
+
+struct usb_device_descriptor {
+ u8 bLength;
+ u8 bDescriptorType;
+
+ u16 bcdUSB;
+ u8 bDeviceClass;
+ u8 bDeviceSubClass;
+ u8 bDeviceProtocol;
+ u8 bMaxPacketSize0;
+ u16 idVendor;
+ u16 idProduct;
+ u16 bcdDevice;
+ u8 iManufacturer;
+ u8 iProduct;
+ u8 iSerialNumber;
+ u8 bNumConfigurations;
+} PACKED;
+
+#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
+#define USB_CLASS_AUDIO 1
+#define USB_CLASS_COMM 2
+#define USB_CLASS_HID 3
+#define USB_CLASS_PHYSICAL 5
+#define USB_CLASS_STILL_IMAGE 6
+#define USB_CLASS_PRINTER 7
+#define USB_CLASS_MASS_STORAGE 8
+#define USB_CLASS_HUB 9
+
+struct usb_config_descriptor {
+ u8 bLength;
+ u8 bDescriptorType;
+
+ u16 wTotalLength;
+ u8 bNumInterfaces;
+ u8 bConfigurationValue;
+ u8 iConfiguration;
+ u8 bmAttributes;
+ u8 bMaxPower;
+} PACKED;
+
+struct usb_interface_descriptor {
+ u8 bLength;
+ u8 bDescriptorType;
+
+ u8 bInterfaceNumber;
+ u8 bAlternateSetting;
+ u8 bNumEndpoints;
+ u8 bInterfaceClass;
+ u8 bInterfaceSubClass;
+ u8 bInterfaceProtocol;
+ u8 iInterface;
+} PACKED;
+
+struct usb_endpoint_descriptor {
+ u8 bLength;
+ u8 bDescriptorType;
+
+ u8 bEndpointAddress;
+ u8 bmAttributes;
+ u16 wMaxPacketSize;
+ u8 bInterval;
+} PACKED;
+
+#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK 0x80
+
+#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL 0
+#define USB_ENDPOINT_XFER_ISOC 1
+#define USB_ENDPOINT_XFER_BULK 2
+#define USB_ENDPOINT_XFER_INT 3
+#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
+
+#define USB_CONTROL_SETUP_SIZE 8
+
+
+/****************************************************************
+ * usb mass storage flags
+ ****************************************************************/
+
+#define US_SC_ATAPI_8020 0x02
+#define US_SC_ATAPI_8070 0x05
+#define US_SC_SCSI 0x06
+
+#define US_PR_BULK 0x50 /* bulk-only transport */
+#define US_PR_UAS 0x62 /* usb attached scsi */
+
+/****************************************************************
+ * function defs
+ ****************************************************************/
+
+// usb.c
+int usb_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize);
+int usb_poll_intr(struct usb_pipe *pipe, void *data);
+int usb_32bit_pipe(struct usb_pipe *pipe_fl);
+struct usb_pipe *usb_alloc_pipe(struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc);
+void usb_free_pipe(struct usbdevice_s *usbdev, struct usb_pipe *pipe);
+int usb_send_default_control(struct usb_pipe *pipe
+ , const struct usb_ctrlrequest *req, void *data);
+int usb_is_freelist(struct usb_s *cntl, struct usb_pipe *pipe);
+void usb_add_freelist(struct usb_pipe *pipe);
+struct usb_pipe *usb_get_freelist(struct usb_s *cntl, u8 eptype);
+void usb_desc2pipe(struct usb_pipe *pipe, struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc);
+int usb_get_period(struct usbdevice_s *usbdev
+ , struct usb_endpoint_descriptor *epdesc);
+int usb_xfer_time(struct usb_pipe *pipe, int datalen);
+struct usb_endpoint_descriptor *usb_find_desc(struct usbdevice_s *usbdev
+ , int type, int dir);
+void usb_enumerate(struct usbhub_s *hub);
+void usb_setup(void);
+
+#endif // usb.h
diff --git a/roms/seabios-hppa/src/hw/virtio-blk.c b/roms/seabios-hppa/src/hw/virtio-blk.c
new file mode 100644
index 000000000..3b198965c
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/virtio-blk.c
@@ -0,0 +1,293 @@
+// Virtio block boot support.
+//
+// Copyright (C) 2010 Red Hat Inc.
+//
+// Authors:
+// Gleb Natapov <gnatapov@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBALFLAT
+#include "config.h" // CONFIG_*
+#include "block.h" // struct drive_s
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "stacks.h" // run_thread
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // usleep, bootprio_find_pci_device, is_bootprio_strict
+#include "virtio-pci.h"
+#include "virtio-mmio.h"
+#include "virtio-ring.h"
+#include "virtio-blk.h"
+
+struct virtiodrive_s {
+ struct drive_s drive;
+ struct vring_virtqueue *vq;
+ struct vp_device vp;
+};
+
+static int
+virtio_blk_op(struct disk_op_s *op, int write)
+{
+ struct virtiodrive_s *vdrive =
+ container_of(op->drive_fl, struct virtiodrive_s, drive);
+ struct vring_virtqueue *vq = vdrive->vq;
+ struct virtio_blk_outhdr hdr = {
+ .type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN,
+ .ioprio = 0,
+ .sector = op->lba,
+ };
+ u8 status = VIRTIO_BLK_S_UNSUPP;
+ struct vring_list sg[] = {
+ {
+ .addr = (void*)(&hdr),
+ .length = sizeof(hdr),
+ },
+ {
+ .addr = op->buf_fl,
+ .length = vdrive->drive.blksize * op->count,
+ },
+ {
+ .addr = (void*)(&status),
+ .length = sizeof(status),
+ },
+ };
+
+ /* Add to virtqueue and kick host */
+ if (write)
+ vring_add_buf(vq, sg, 2, 1, 0, 0);
+ else
+ vring_add_buf(vq, sg, 1, 2, 0, 0);
+ vring_kick(&vdrive->vp, vq, 1);
+
+ /* Wait for reply */
+ while (!vring_more_used(vq))
+ usleep(5);
+
+ /* Reclaim virtqueue element */
+ vring_get_buf(vq, NULL);
+
+ /* Clear interrupt status register. Avoid leaving interrupts stuck if
+ * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
+ */
+ vp_get_isr(&vdrive->vp);
+
+ return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
+}
+
+int
+virtio_blk_process_op(struct disk_op_s *op)
+{
+ if (! CONFIG_VIRTIO_BLK)
+ return 0;
+ switch (op->command) {
+ case CMD_READ:
+ return virtio_blk_op(op, 0);
+ case CMD_WRITE:
+ return virtio_blk_op(op, 1);
+ default:
+ return default_process_op(op);
+ }
+}
+
+static void
+init_virtio_blk(void *data)
+{
+ struct pci_device *pci = data;
+ u8 status = VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER;
+ dprintf(1, "found virtio-blk at %pP\n", pci);
+ struct virtiodrive_s *vdrive = malloc_low(sizeof(*vdrive));
+ if (!vdrive) {
+ warn_noalloc();
+ return;
+ }
+ memset(vdrive, 0, sizeof(*vdrive));
+ vdrive->drive.type = DTYPE_VIRTIO_BLK;
+ vdrive->drive.cntl_id = pci->bdf;
+
+ 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 %pP\n", pci);
+ goto fail;
+ }
+
+ 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 iommu_platform = 1ull << VIRTIO_F_IOMMU_PLATFORM;
+ u64 blk_size = 1ull << VIRTIO_BLK_F_BLK_SIZE;
+ if (!(features & version1)) {
+ dprintf(1, "modern device without virtio_1 feature bit: %pP\n", pci);
+ goto fail;
+ }
+
+ features = features & (version1 | iommu_platform | 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: %pP\n", pci);
+ 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 %pP block size %d is unsupported\n",
+ pci, vdrive->drive.blksize);
+ goto fail;
+ }
+ dprintf(3, "virtio-blk %pP blksize=%d sectors=%u\n",
+ pci, 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 %pP blksize=%d sectors=%u\n",
+ pci, vdrive->drive.blksize, (u32)vdrive->drive.sectors);
+
+ if (vdrive->drive.blksize != DISK_SECTOR_SIZE) {
+ dprintf(1, "virtio-blk %pP block size %d is unsupported\n",
+ pci, vdrive->drive.blksize);
+ goto fail;
+ }
+ 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:%pP", pci);
+ boot_add_hd(&vdrive->drive, desc, bootprio_find_pci_device(pci));
+
+ status |= VIRTIO_CONFIG_S_DRIVER_OK;
+ vp_set_status(&vdrive->vp, status);
+
+ boot_lchs_find_pci_device(pci, &vdrive->drive.lchs);
+ return;
+
+fail:
+ vp_reset(&vdrive->vp);
+ free(vdrive->vq);
+ free(vdrive);
+}
+
+void
+init_virtio_blk_mmio(void *mmio)
+{
+ u8 status = VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER;
+ dprintf(1, "found virtio-blk-mmio at %p\n", mmio);
+ struct virtiodrive_s *vdrive = malloc_low(sizeof(*vdrive));
+ if (!vdrive) {
+ warn_noalloc();
+ return;
+ }
+ memset(vdrive, 0, sizeof(*vdrive));
+ vdrive->drive.type = DTYPE_VIRTIO_BLK;
+ vdrive->drive.cntl_id = (u32)mmio;
+
+ vp_init_mmio(&vdrive->vp, mmio);
+ if (vp_find_vq(&vdrive->vp, 0, &vdrive->vq) < 0 ) {
+ dprintf(1, "fail to find vq for virtio-blk-mmio %p\n", mmio);
+ goto fail;
+ }
+
+ 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;
+
+ 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: %p\n", mmio);
+ 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-mmio %p block size %d is unsupported\n",
+ mmio, vdrive->drive.blksize);
+ goto fail;
+ }
+ dprintf(1, "virtio-blk-mmio %p blksize=%d sectors=%u\n",
+ mmio, 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);
+
+ char *desc = znprintf(MAXDESCSIZE, "Virtio disk mmio:%p", mmio);
+ boot_add_hd(&vdrive->drive, desc, bootprio_find_mmio_device(mmio));
+
+ status |= VIRTIO_CONFIG_S_DRIVER_OK;
+ vp_set_status(&vdrive->vp, status);
+ return;
+
+fail:
+ vp_reset(&vdrive->vp);
+ free(vdrive->vq);
+ free(vdrive);
+}
+
+void
+virtio_blk_setup(void)
+{
+ u8 skip_nonbootable = is_bootprio_strict();
+
+ ASSERT32FLAT();
+ if (! CONFIG_VIRTIO_BLK)
+ return;
+
+ dprintf(3, "init virtio-blk\n");
+
+ struct pci_device *pci;
+ foreachpci(pci) {
+ 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;
+
+ if (skip_nonbootable && bootprio_find_pci_device(pci) < 0) {
+ dprintf(1, "skipping init of a non-bootable virtio-blk at %pP\n",
+ pci);
+ continue;
+ }
+
+ run_thread(init_virtio_blk, pci);
+ }
+}
diff --git a/roms/seabios-hppa/src/hw/virtio-blk.h b/roms/seabios-hppa/src/hw/virtio-blk.h
new file mode 100644
index 000000000..d20461a2a
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/virtio-blk.h
@@ -0,0 +1,44 @@
+#ifndef _VIRTIO_BLK_H
+#define _VIRTIO_BLK_H
+
+struct virtio_blk_config
+{
+ u64 capacity;
+ u32 size_max;
+ u32 seg_max;
+ u16 cylinders;
+ u8 heads;
+ u8 sectors;
+ u32 blk_size;
+ u8 physical_block_exp;
+ u8 alignment_offset;
+ u16 min_io_size;
+ u32 opt_io_size;
+} __attribute__((packed));
+
+#define VIRTIO_BLK_F_BLK_SIZE 6
+
+/* These two define direction. */
+#define VIRTIO_BLK_T_IN 0
+#define VIRTIO_BLK_T_OUT 1
+
+/* This is the first element of the read scatter-gather list. */
+struct virtio_blk_outhdr {
+ /* VIRTIO_BLK_T* */
+ u32 type;
+ /* io priority. */
+ u32 ioprio;
+ /* Sector (ie. 512 byte offset) */
+ u64 sector;
+};
+
+#define VIRTIO_BLK_S_OK 0
+#define VIRTIO_BLK_S_IOERR 1
+#define VIRTIO_BLK_S_UNSUPP 2
+
+struct disk_op_s;
+int virtio_blk_process_op(struct disk_op_s *op);
+void virtio_blk_setup(void);
+void init_virtio_blk_mmio(void *mmio);
+
+#endif /* _VIRTIO_BLK_H */
diff --git a/roms/seabios-hppa/src/hw/virtio-mmio.c b/roms/seabios-hppa/src/hw/virtio-mmio.c
new file mode 100644
index 000000000..44344a499
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/virtio-mmio.c
@@ -0,0 +1,97 @@
+#include "config.h" // CONFIG_DEBUG_LEVEL
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "stacks.h" // run_thread
+#include "string.h" // memset
+#include "util.h" // acpi_dsdt_*
+#include "virtio-pci.h"
+#include "virtio-blk.h"
+#include "virtio-scsi.h"
+#include "virtio-ring.h"
+#include "virtio-mmio.h"
+
+void virtio_mmio_setup_acpi(void)
+{
+ static const char *virtio_hid = "LNRO0005";
+ struct acpi_device *dev;
+ u64 mem, irq, unused;
+
+ for (dev = acpi_dsdt_find_string(NULL, virtio_hid);
+ dev != NULL;
+ dev = acpi_dsdt_find_string(dev, virtio_hid)) {
+ if (acpi_dsdt_find_mem(dev, &mem, &unused) < 0)
+ continue;
+ if (acpi_dsdt_find_irq(dev, &irq) < 0)
+ continue;
+ dprintf(1, "ACPI: virtio-mmio device %s at 0x%llx, irq %lld\n",
+ acpi_dsdt_name(dev), mem, irq);
+ virtio_mmio_setup_one(mem);
+ }
+}
+
+void virtio_mmio_setup_one(u64 addr)
+{
+ static const char *names[] = {
+ [ 1 ] = "net",
+ [ 2 ] = "blk",
+ [ 3 ] = "console",
+ [ 4 ] = "rng",
+ [ 8 ] = "scsi",
+ [ 9 ] = "9p",
+ [ 16 ] = "gpu",
+ [ 19 ] = "vsock",
+ [ 18 ] = "input",
+ [ 26 ] = "fs",
+ };
+ const char *name;
+ u32 magic, version, devid;
+ void *mmio;
+
+ if (addr >= 0x100000000) {
+ dprintf(1, "virtio-mmio: %llx: above 4G\n", addr);
+ return;
+ }
+
+ mmio = (void*)(u32)(addr);
+ magic = readl(mmio);
+ if (magic != 0x74726976) {
+ dprintf(1, "virtio-mmio: %llx: magic mismatch\n", addr);
+ return;
+ }
+ version = readl(mmio+4);
+ if (version != 1 /* legacy */ &&
+ version != 2 /* 1.0 */) {
+ dprintf(1, "virtio-mmio: %llx: unknown version %d\n", addr, version);
+ return;
+ }
+ devid = readl(mmio+8);
+
+ name = (devid < ARRAY_SIZE(names) && names[devid] != NULL)
+ ? names[devid] : "unknown";
+ dprintf(1, "virtio-mmio: %llx: device id %x (%s%s)\n",
+ addr, devid, name, version == 1 ? ", legacy" : "");
+
+ switch (devid) {
+ case 2: /* blk */
+ run_thread(init_virtio_blk_mmio, mmio);
+ break;
+ case 8: /* scsi */
+ run_thread(init_virtio_scsi_mmio, mmio);
+ break;
+ default:
+ break;
+ }
+}
+
+void vp_init_mmio(struct vp_device *vp, void *mmio)
+{
+ memset(vp, 0, sizeof(*vp));
+ vp->use_mmio = 1;
+ vp->common.mode = VP_ACCESS_MMIO;
+ vp->common.memaddr = mmio;
+ vp->device.mode = VP_ACCESS_MMIO;
+ vp->device.memaddr = mmio + 0x100;
+ vp_reset(vp);
+ vp_set_status(vp, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+ VIRTIO_CONFIG_S_DRIVER);
+}
diff --git a/roms/seabios-hppa/src/hw/virtio-mmio.h b/roms/seabios-hppa/src/hw/virtio-mmio.h
new file mode 100644
index 000000000..69fbd23c3
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/virtio-mmio.h
@@ -0,0 +1,77 @@
+#ifndef _VIRTIO_MMIO_H
+#define _VIRTIO_MMIO_H
+
+struct vp_device;
+
+typedef struct virtio_mmio_cfg {
+ u32 magic;
+ u32 version;
+ u32 device_id;
+ u32 vendor_id;
+
+ u32 device_feature;
+ u32 device_feature_select;
+ u32 res_18;
+ u32 res_1c;
+
+ u32 guest_feature;
+ u32 guest_feature_select;
+ u32 legacy_guest_page_size;
+ u32 res_2c;
+
+ u32 queue_select;
+ u32 queue_num_max;
+ u32 queue_num;
+ u32 legacy_queue_align;
+
+ u32 legacy_queue_pfn;
+ u32 queue_ready;
+ u32 res_48;
+ u32 res_4c;
+
+ u32 queue_notify;
+ u32 res_54;
+ u32 res_58;
+ u32 res_5c;
+
+ u32 irq_status;
+ u32 irq_ack;
+ u32 res_68;
+ u32 res_6c;
+
+ u32 device_status;
+ u32 res_74;
+ u32 res_78;
+ u32 res_7c;
+
+ u32 queue_desc_lo;
+ u32 queue_desc_hi;
+ u32 res_88;
+ u32 res_8c;
+
+ u32 queue_driver_lo;
+ u32 queue_driver_hi;
+ u32 res_98;
+ u32 res_9c;
+
+ u32 queue_device_lo;
+ u32 queue_device_hi;
+ u32 res_a8;
+ u32 shm_sel;
+
+ u32 shmem_len_lo;
+ u32 shmem_len_hi;
+ u32 shmem_base_lo;
+ u32 shmem_base_hi;
+
+ u32 res_c0_f7[14];
+
+ u32 res_f8;
+ u32 config_generation;
+} virtio_mmio_cfg;
+
+void virtio_mmio_setup_acpi(void);
+void virtio_mmio_setup_one(u64 mmio);
+void vp_init_mmio(struct vp_device *vp, void *mmio);
+
+#endif /* _VIRTIO_MMIO_H */
diff --git a/roms/seabios-hppa/src/hw/virtio-pci.c b/roms/seabios-hppa/src/hw/virtio-pci.c
new file mode 100644
index 000000000..213c49777
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/virtio-pci.c
@@ -0,0 +1,545 @@
+/* virtio-pci.c - pci interface for virtio interface
+ *
+ * (c) Copyright 2008 Bull S.A.S.
+ *
+ * Author: Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ * some parts from Linux Virtio PCI driver
+ *
+ * Copyright IBM Corp. 2007
+ * Authors: Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * Adopted for Seabios: Gleb Natapov <gleb@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPLv3
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "config.h" // CONFIG_DEBUG_LEVEL
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "pci.h" // pci_config_readl
+#include "pcidevice.h" // struct pci_device
+#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "string.h" // memset
+#include "virtio-pci.h"
+#include "virtio-mmio.h"
+#include "virtio-ring.h"
+
+u64 _vp_read(struct vp_cap *cap, u32 offset, u8 size)
+{
+ u64 var = 0;
+
+ switch (cap->mode) {
+ case VP_ACCESS_IO:
+ {
+ u32 addr = cap->ioaddr + offset;
+ 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;
+ }
+ break;
+ }
+
+ case VP_ACCESS_MMIO:
+ {
+ void *addr = cap->memaddr + offset;
+ switch (size) {
+ case 8:
+ var = readl(addr);
+ var |= (u64)readl(addr+4) << 32;
+ break;
+ case 4:
+ var = readl(addr);
+ break;
+ case 2:
+ var = readw(addr);
+ break;
+ case 1:
+ var = readb(addr);
+ break;
+ }
+ break;
+ }
+
+ case VP_ACCESS_PCICFG:
+ {
+ u32 addr = cap->baroff + offset;
+ pci_config_writeb(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.bar),
+ cap->bar);
+ pci_config_writel(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.offset),
+ addr);
+ pci_config_writel(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.length),
+ (size > 4) ? 4 : size);
+ switch (size) {
+ case 8:
+ var = pci_config_readl(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data));
+ pci_config_writel(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.offset),
+ addr + 4);
+ var |= (u64)pci_config_readl(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data)) << 32;
+ break;
+ case 4:
+ var = pci_config_readl(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data));
+ break;
+ case 2:
+ var = pci_config_readw(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data));
+ break;
+ case 1:
+ var = pci_config_readb(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data));
+ break;
+ }
+ }
+ }
+ dprintf(9, "vp read %x (%d) -> 0x%llx\n", cap->ioaddr + offset, size, var);
+ return var;
+}
+
+void _vp_write(struct vp_cap *cap, u32 offset, u8 size, u64 var)
+{
+ dprintf(9, "vp write %x (%d) <- 0x%llx\n", cap->ioaddr + offset, size, var);
+
+ switch (cap->mode) {
+ case VP_ACCESS_IO:
+ {
+ u32 addr = cap->ioaddr + offset;
+ switch (size) {
+ case 4:
+ outl(var, addr);
+ break;
+ case 2:
+ outw(var, addr);
+ break;
+ case 1:
+ outb(var, addr);
+ break;
+ }
+ break;
+ }
+
+ case VP_ACCESS_MMIO:
+ {
+ void *addr = cap->memaddr + offset;
+ switch (size) {
+ case 4:
+ writel(addr, var);
+ break;
+ case 2:
+ writew(addr, var);
+ break;
+ case 1:
+ writeb(addr, var);
+ break;
+ }
+ break;
+ }
+
+ case VP_ACCESS_PCICFG:
+ {
+ u32 addr = cap->baroff + offset;
+ pci_config_writeb(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.bar),
+ cap->bar);
+ pci_config_writel(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.offset),
+ addr);
+ pci_config_writel(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.length),
+ size);
+ switch (size) {
+ case 4:
+ pci_config_writel(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data),
+ var);
+ break;
+ case 2:
+ pci_config_writew(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data),
+ var);
+ break;
+ case 1:
+ pci_config_writeb(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data),
+ var);
+ break;
+ }
+ }
+ }
+}
+
+u64 vp_get_features(struct vp_device *vp)
+{
+ u32 f0, f1;
+
+ if (vp->use_mmio) {
+ vp_write(&vp->common, virtio_mmio_cfg, device_feature_select, 0);
+ f0 = vp_read(&vp->common, virtio_mmio_cfg, device_feature);
+ f1 = 0;
+ } else 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_mmio) {
+ vp_write(&vp->common, virtio_mmio_cfg, guest_feature_select, f0);
+ vp_write(&vp->common, virtio_mmio_cfg, guest_feature, f0);
+ } else 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_mmio) {
+ return vp_read(&vp->common, virtio_mmio_cfg, device_status);
+ } else 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_mmio) {
+ vp_write(&vp->common, virtio_mmio_cfg, device_status, status);
+ } else 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_mmio) {
+ return vp_read(&vp->common, virtio_mmio_cfg, irq_status);
+ } else 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_mmio) {
+ vp_write(&vp->common, virtio_mmio_cfg, device_status, 0);
+ vp_read(&vp->common, virtio_mmio_cfg, irq_status);
+ } else 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_mmio) {
+ vp_write(&vp->common, virtio_mmio_cfg, queue_notify, vq->queue_index);
+ } else if (vp->use_modern) {
+ u32 offset = vq->queue_notify_off * vp->notify_off_multiplier;
+ switch (vp->notify.mode) {
+ case VP_ACCESS_IO:
+ outw(vq->queue_index, vp->notify.ioaddr + offset);
+ break;
+ case VP_ACCESS_MMIO:
+ writew(vp->notify.memaddr + offset, vq->queue_index);
+ break;
+ case VP_ACCESS_PCICFG:
+ pci_config_writeb(vp->notify.bdf, vp->notify.cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.bar),
+ vp->notify.bar);
+ pci_config_writel(vp->notify.bdf, vp->notify.cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.offset),
+ vp->notify.baroff + offset);
+ pci_config_writel(vp->notify.bdf, vp->notify.cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.length),
+ 2);
+ pci_config_writew(vp->notify.bdf, vp->notify.cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data),
+ vq->queue_index);
+ }
+ dprintf(9, "vp notify %x (%d) -- 0x%x\n",
+ vp->notify.ioaddr, 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_high(PAGE_SIZE, sizeof(*vq));
+ if (!vq) {
+ warn_noalloc();
+ goto fail;
+ }
+ memset(vq, 0, sizeof(*vq));
+
+
+ /* select the queue */
+ if (vp->use_mmio) {
+ vp_write(&vp->common, virtio_mmio_cfg, queue_select, queue_index);
+ } else 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 */
+ if (vp->use_mmio) {
+ num = vp_read(&vp->common, virtio_mmio_cfg, queue_num_max);
+ if (num > MAX_QUEUE_NUM)
+ num = MAX_QUEUE_NUM;
+ vp_write(&vp->common, virtio_mmio_cfg, queue_num, num);
+ } else 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 (vp->use_mmio) {
+ /* TODO */;
+ } else 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);
+
+ /* activate the queue
+ *
+ * NOTE: vr->desc is initialized by vring_init()
+ */
+
+ if (vp->use_mmio) {
+ if (vp_read(&vp->common, virtio_mmio_cfg, version) == 2) {
+ vp_write(&vp->common, virtio_mmio_cfg, queue_desc_lo,
+ (unsigned long)virt_to_phys(vr->desc));
+ vp_write(&vp->common, virtio_mmio_cfg, queue_desc_hi, 0);
+ vp_write(&vp->common, virtio_mmio_cfg, queue_driver_lo,
+ (unsigned long)virt_to_phys(vr->avail));
+ vp_write(&vp->common, virtio_mmio_cfg, queue_driver_hi, 0);
+ vp_write(&vp->common, virtio_mmio_cfg, queue_device_lo,
+ (unsigned long)virt_to_phys(vr->used));
+ vp_write(&vp->common, virtio_mmio_cfg, queue_device_hi, 0);
+ vp_write(&vp->common, virtio_mmio_cfg, queue_ready, 1);
+ } else {
+ vp_write(&vp->common, virtio_mmio_cfg, legacy_guest_page_size,
+ (unsigned long)1 << PAGE_SHIFT);
+ vp_write(&vp->common, virtio_mmio_cfg, legacy_queue_pfn,
+ (unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT);
+ }
+ } else 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:
+ free(vq);
+ *p_vq = NULL;
+ return -1;
+}
+
+void vp_init_simple(struct vp_device *vp, struct pci_device *pci)
+{
+ u8 cap = pci_find_capability(pci->bdf, PCI_CAP_ID_VNDR, 0);
+ struct vp_cap *vp_cap;
+ const char *mode;
+ u32 offset, base, mul;
+ u64 addr;
+ 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;
+ case VIRTIO_PCI_CAP_PCI_CFG:
+ vp->common.cfg = cap;
+ vp->common.bdf = pci->bdf;
+ vp->notify.cfg = cap;
+ vp->notify.bdf = pci->bdf;
+ vp->isr.cfg = cap;
+ vp->isr.bdf = pci->bdf;
+ vp->device.cfg = cap;
+ vp->device.bdf = pci->bdf;
+ vp_cap = NULL;
+ dprintf(1, "pci dev %pP virtio cap at 0x%x type %d"
+ " [pci cfg access]\n", pci, cap, type);
+ 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));
+ base = PCI_BASE_ADDRESS_0 + 4 * vp_cap->bar;
+ addr = pci_config_readl(pci->bdf, base);
+ if (addr & PCI_BASE_ADDRESS_SPACE_IO) {
+ addr &= PCI_BASE_ADDRESS_IO_MASK;
+ vp_cap->mode = VP_ACCESS_IO;
+ } else if ((addr & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+ PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ addr &= PCI_BASE_ADDRESS_MEM_MASK;
+ addr |= (u64)pci_config_readl(pci->bdf, base + 4) << 32;
+ vp_cap->mode = (addr > 0xffffffffll) ?
+ VP_ACCESS_PCICFG : VP_ACCESS_MMIO;
+ } else {
+ addr &= PCI_BASE_ADDRESS_MEM_MASK;
+ vp_cap->mode = VP_ACCESS_MMIO;
+ }
+ switch (vp_cap->mode) {
+ case VP_ACCESS_IO:
+ {
+ u32 addr = pci_enable_iobar(pci, base);
+ if (!addr)
+ return;
+ vp_cap->ioaddr = addr + offset;
+ mode = "io";
+ break;
+ }
+ case VP_ACCESS_MMIO:
+ {
+ void *addr = pci_enable_membar(pci, base);
+ if (!addr)
+ return;
+ vp_cap->memaddr = addr + offset;
+ mode = "mmio";
+ break;
+ }
+ case VP_ACCESS_PCICFG:
+ mode = "pcicfg";
+ vp_cap->baroff = offset;
+ break;
+ default:
+ mode = "Huh?";
+ break;
+ }
+ dprintf(1, "pci dev %pP virtio cap at 0x%x type %d "
+ "bar %d at 0x%08llx off +0x%04x [%s]\n",
+ pci, vp_cap->cap, type, vp_cap->bar, addr, offset, mode);
+ }
+
+ cap = pci_find_capability(pci->bdf, PCI_CAP_ID_VNDR, cap);
+ }
+
+ if (vp->common.cap && vp->notify.cap && vp->isr.cap && vp->device.cap) {
+ dprintf(1, "pci dev %pP using modern (1.0) virtio mode\n", pci);
+ vp->use_modern = 1;
+ } else {
+ dprintf(1, "pci dev %pP using legacy (0.9.5) virtio mode\n", pci);
+ vp->legacy.bar = 0;
+ vp->legacy.ioaddr = pci_enable_iobar(pci, PCI_BASE_ADDRESS_0);
+ if (!vp->legacy.ioaddr)
+ return;
+ vp->legacy.mode = VP_ACCESS_IO;
+ }
+
+ vp_reset(vp);
+ pci_enable_busmaster(pci);
+ vp_set_status(vp, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+ VIRTIO_CONFIG_S_DRIVER );
+}
diff --git a/roms/seabios-hppa/src/hw/virtio-pci.h b/roms/seabios-hppa/src/hw/virtio-pci.h
new file mode 100644
index 000000000..269626448
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/virtio-pci.h
@@ -0,0 +1,152 @@
+#ifndef _VIRTIO_PCI_H
+#define _VIRTIO_PCI_H
+
+#include "x86.h" // inl
+#include "biosvar.h" // GET_LOWFLAT
+
+/* The bit of the ISR which indicates a device configuration change. */
+#define VIRTIO_PCI_ISR_CONFIG 0x2
+
+/* Virtio ABI version, this must match exactly */
+#define VIRTIO_PCI_ABI_VERSION 0
+
+/* --- 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. */
+};
+
+struct virtio_pci_cfg_cap {
+ struct virtio_pci_cap cap;
+ u8 pci_cfg_data[4]; /* Data for BAR access. */
+};
+
+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 ----------------------------------------------- */
+
+#define VP_ACCESS_IO 1
+#define VP_ACCESS_MMIO 2
+#define VP_ACCESS_PCICFG 3
+
+struct vp_cap {
+ union {
+ void *memaddr;
+ u32 ioaddr;
+ u32 baroff;
+ };
+ u16 bdf;
+ u8 cap;
+ u8 cfg;
+ u8 bar;
+ u8 mode;
+};
+
+struct vp_device {
+ struct vp_cap common, notify, isr, device, legacy;
+ u32 notify_off_multiplier;
+ u8 use_modern;
+ u8 use_mmio;
+};
+
+u64 _vp_read(struct vp_cap *cap, u32 offset, u8 size);
+void _vp_write(struct vp_cap *cap, u32 offset, u8 size, u64 var);
+
+#define vp_read(_cap, _struct, _field) \
+ _vp_read(_cap, offsetof(_struct, _field), \
+ sizeof(((_struct *)0)->_field))
+
+#define vp_write(_cap, _struct, _field, _var) \
+ _vp_write(_cap, offsetof(_struct, _field), \
+ sizeof(((_struct *)0)->_field), _var)
+
+u64 vp_get_features(struct vp_device *vp);
+void vp_set_features(struct vp_device *vp, u64 features);
+
+static inline void vp_get_legacy(struct vp_device *vp, unsigned offset,
+ void *buf, unsigned len)
+{
+ u8 *ptr = buf;
+ unsigned i;
+
+ for (i = 0; i < len; i++)
+ ptr[i] = vp_read(&vp->legacy, virtio_pci_legacy, device[i]);
+}
+
+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;
+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/roms/seabios-hppa/src/hw/virtio-ring.c b/roms/seabios-hppa/src/hw/virtio-ring.c
new file mode 100644
index 000000000..0ed3189ee
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/virtio-ring.c
@@ -0,0 +1,147 @@
+/* virtio-pci.c - virtio ring management
+ *
+ * (c) Copyright 2008 Bull S.A.S.
+ *
+ * Author: Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ * some parts from Linux Virtio Ring
+ *
+ * Copyright Rusty Russell IBM Corporation 2007
+ *
+ * Adopted for Seabios: Gleb Natapov <gleb@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPLv3
+ * See the COPYING file in the top-level directory.
+ *
+ *
+ */
+
+#include "output.h" // panic
+#include "virtio-ring.h"
+#include "virtio-pci.h"
+
+#define BUG() do { \
+ panic("BUG: failure at %d/%s()!\n", __LINE__, __func__); \
+ } while (0)
+#define BUG_ON(condition) do { if (condition) BUG(); } while (0)
+
+/*
+ * vring_more_used
+ *
+ * is there some used buffers ?
+ *
+ */
+
+int vring_more_used(struct vring_virtqueue *vq)
+{
+ 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;
+}
+
+/*
+ * vring_free
+ *
+ * put at the begin of the free list the current desc[head]
+ */
+
+void vring_detach(struct vring_virtqueue *vq, unsigned int head)
+{
+ struct vring *vr = &vq->vring;
+ struct vring_desc *desc = GET_LOWFLAT(vr->desc);
+ unsigned int i;
+
+ /* find end of given descriptor */
+
+ i = head;
+ while (desc[i].flags & VRING_DESC_F_NEXT)
+ i = desc[i].next;
+
+ /* link it with free list and point to it */
+
+ desc[i].next = vq->free_head;
+ vq->free_head = head;
+}
+
+/*
+ * vring_get_buf
+ *
+ * get a buffer from the used list
+ *
+ */
+
+int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
+{
+ struct vring *vr = &vq->vring;
+ struct vring_used_elem *elem;
+ struct vring_used *used = vq->vring.used;
+ u32 id;
+ int ret;
+
+// BUG_ON(!vring_more_used(vq));
+
+ elem = &used->ring[vq->last_used_idx % vr->num];
+ id = elem->id;
+ if (len != NULL)
+ *len = elem->len;
+
+ ret = vq->vdata[id];
+
+ vring_detach(vq, id);
+
+ vq->last_used_idx = vq->last_used_idx + 1;
+
+ return ret;
+}
+
+void vring_add_buf(struct vring_virtqueue *vq,
+ struct vring_list list[],
+ unsigned int out, unsigned int in,
+ int index, int num_added)
+{
+ struct vring *vr = &vq->vring;
+ int i, av, head, prev;
+ struct vring_desc *desc = vr->desc;
+ struct vring_avail *avail = vr->avail;
+
+ BUG_ON(out + in == 0);
+
+ prev = 0;
+ 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 = 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++;
+ }
+ desc[prev].flags = desc[prev].flags & ~VRING_DESC_F_NEXT;
+
+ vq->free_head = i;
+
+ vq->vdata[head] = index;
+
+ av = (avail->idx + num_added) % vr->num;
+ avail->ring[av] = head;
+}
+
+void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added)
+{
+ struct vring *vr = &vq->vring;
+ struct vring_avail *avail = vr->avail;
+
+ /* Make sure idx update is done after ring write. */
+ smp_wmb();
+ avail->idx = avail->idx + num_added;
+
+ vp_notify(vp, vq);
+}
diff --git a/roms/seabios-hppa/src/hw/virtio-ring.h b/roms/seabios-hppa/src/hw/virtio-ring.h
new file mode 100644
index 000000000..dccc50d73
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/virtio-ring.h
@@ -0,0 +1,121 @@
+#ifndef _VIRTIO_RING_H
+#define _VIRTIO_RING_H
+
+#include "types.h" // u64
+#include "memmap.h" // PAGE_SIZE
+
+/* 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
+/* We have found a driver for the device. */
+#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 VIRTIO_F_IOMMU_PLATFORM 33
+
+#define MAX_QUEUE_NUM (256)
+
+#define VRING_DESC_F_NEXT 1
+#define VRING_DESC_F_WRITE 2
+
+#define VRING_AVAIL_F_NO_INTERRUPT 1
+
+#define VRING_USED_F_NO_NOTIFY 1
+
+struct vring_desc
+{
+ u64 addr;
+ u32 len;
+ u16 flags;
+ u16 next;
+};
+
+struct vring_avail
+{
+ u16 flags;
+ u16 idx;
+ u16 ring[0];
+};
+
+struct vring_used_elem
+{
+ u32 id;
+ u32 len;
+};
+
+struct vring_used
+{
+ u16 flags;
+ u16 idx;
+ struct vring_used_elem ring[];
+};
+
+struct vring {
+ unsigned int num;
+ struct vring_desc *desc;
+ struct vring_avail *avail;
+ struct vring_used *used;
+};
+
+#define vring_size(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)];
+
+struct vring_virtqueue {
+ virtio_queue_t queue;
+ struct vring vring;
+ u16 free_head;
+ u16 last_used_idx;
+ u16 vdata[MAX_QUEUE_NUM];
+ /* PCI */
+ int queue_index;
+ int queue_notify_off;
+};
+
+struct vring_list {
+ char *addr;
+ unsigned int length;
+};
+
+static inline void
+vring_init(struct vring *vr, unsigned int num, unsigned char *queue)
+{
+ ASSERT32FLAT();
+ vr->num = num;
+
+ /* physical address of desc must be page aligned */
+ 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);
+
+ int i;
+ for (i = 0; i < num - 1; i++)
+ 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(struct vp_device *vp, struct vring_virtqueue *vq, int num_added);
+
+#endif /* _VIRTIO_RING_H_ */
diff --git a/roms/seabios-hppa/src/hw/virtio-scsi.c b/roms/seabios-hppa/src/hw/virtio-scsi.c
new file mode 100644
index 000000000..81bce226e
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/virtio-scsi.c
@@ -0,0 +1,291 @@
+// Virtio SCSI boot support.
+//
+// Copyright (C) 2012 Red Hat Inc.
+//
+// Authors:
+// Paolo Bonzini <pbonzini@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "block.h" // struct drive_s
+#include "blockcmd.h" // scsi_drive_setup
+#include "config.h" // CONFIG_*
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "pcidevice.h" // foreachpci
+#include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "stacks.h" // run_thread
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // usleep, bootprio_find_pci_device, is_bootprio_strict
+#include "virtio-pci.h"
+#include "virtio-ring.h"
+#include "virtio-scsi.h"
+#include "virtio-mmio.h"
+
+struct virtio_lun_s {
+ struct drive_s drive;
+ struct pci_device *pci;
+ void *mmio;
+ char name[16];
+ struct vring_virtqueue *vq;
+ struct vp_device *vp;
+ u16 target;
+ u16 lun;
+};
+
+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_fl, 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] = vlun->target;
+ req.lun[2] = (vlun->lun >> 8) | 0x40;
+ req.lun[3] = (vlun->lun & 0xff);
+
+ u32 len = op->count * blocksize;
+ int datain = scsi_is_read(op);
+ int in_num = (datain ? 2 : 1);
+ int out_num = (len ? 3 : 2) - in_num;
+
+ sg[0].addr = (void*)(&req);
+ sg[0].length = sizeof(req);
+
+ sg[out_num].addr = (void*)(&resp);
+ sg[out_num].length = sizeof(resp);
+
+ if (len) {
+ int data_idx = (datain ? 2 : 1);
+ sg[data_idx].addr = op->buf_fl;
+ sg[data_idx].length = len;
+ }
+
+ /* Add to virtqueue and kick host */
+ vring_add_buf(vq, sg, out_num, in_num, 0, 0);
+ vring_kick(vp, vq, 1);
+
+ /* Wait for reply */
+ while (!vring_more_used(vq))
+ usleep(5);
+
+ /* Reclaim virtqueue element */
+ vring_get_buf(vq, NULL);
+
+ /* Clear interrupt status register. Avoid leaving interrupts stuck if
+ * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
+ */
+ vp_get_isr(vp);
+
+ if (resp.response == VIRTIO_SCSI_S_OK && resp.status == 0) {
+ return DISK_RET_SUCCESS;
+ }
+ return DISK_RET_EBADTRACK;
+}
+
+static void
+virtio_scsi_init_lun(struct virtio_lun_s *vlun,
+ struct pci_device *pci, void *mmio,
+ struct vp_device *vp, struct vring_virtqueue *vq,
+ u16 target, u16 lun)
+{
+ memset(vlun, 0, sizeof(*vlun));
+ vlun->drive.type = DTYPE_VIRTIO_SCSI;
+ vlun->drive.cntl_id = pci->bdf;
+ vlun->pci = pci;
+ vlun->mmio = mmio;
+ vlun->vp = vp;
+ vlun->vq = vq;
+ vlun->target = target;
+ vlun->lun = lun;
+ if (vlun->pci)
+ snprintf(vlun->name, sizeof(vlun->name), "pci:%pP", vlun->pci);
+ if (vlun->mmio)
+ snprintf(vlun->name, sizeof(vlun->name), "mmio:%08x", (u32)vlun->mmio);
+}
+
+static int
+virtio_scsi_add_lun(u32 lun, struct drive_s *tmpl_drv)
+{
+ u8 skip_nonbootable = is_bootprio_strict();
+ struct virtio_lun_s *tmpl_vlun =
+ container_of(tmpl_drv, struct virtio_lun_s, drive);
+ int prio = -1;
+
+ if (tmpl_vlun->pci)
+ prio = bootprio_find_scsi_device(tmpl_vlun->pci, tmpl_vlun->target, lun);
+ if (tmpl_vlun->mmio)
+ prio = bootprio_find_scsi_mmio_device(tmpl_vlun->mmio, tmpl_vlun->target, lun);
+
+ if (skip_nonbootable && prio < 0) {
+ dprintf(1, "skipping init of a non-bootable virtio-scsi dev at %s,"
+ " target %d, lun %d\n",
+ tmpl_vlun->name, tmpl_vlun->target, lun);
+ return -1;
+ }
+
+ struct virtio_lun_s *vlun = malloc_low(sizeof(*vlun));
+ if (!vlun) {
+ warn_noalloc();
+ return -1;
+ }
+ virtio_scsi_init_lun(vlun, tmpl_vlun->pci, tmpl_vlun->mmio,tmpl_vlun->vp,
+ tmpl_vlun->vq, tmpl_vlun->target, lun);
+
+ if (vlun->pci)
+ boot_lchs_find_scsi_device(vlun->pci, vlun->target, vlun->lun,
+ &(vlun->drive.lchs));
+ int ret = scsi_drive_setup(&vlun->drive, "virtio-scsi", prio, vlun->target, vlun->lun);
+ if (ret)
+ goto fail;
+ return 0;
+
+fail:
+ free(vlun);
+ return -1;
+}
+
+static int
+virtio_scsi_scan_target(struct pci_device *pci, void *mmio, struct vp_device *vp,
+ struct vring_virtqueue *vq, u16 target)
+{
+
+ struct virtio_lun_s vlun0;
+
+ virtio_scsi_init_lun(&vlun0, pci, mmio, vp, vq, target, 0);
+
+ int ret = scsi_rep_luns_scan(&vlun0.drive, virtio_scsi_add_lun);
+ return ret < 0 ? 0 : ret;
+}
+
+static void
+init_virtio_scsi(void *data)
+{
+ struct pci_device *pci = data;
+ dprintf(1, "found virtio-scsi at %pP\n", pci);
+ struct vring_virtqueue *vq = NULL;
+ 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;
+ u64 iommu_platform = 1ull << VIRTIO_F_IOMMU_PLATFORM;
+ if (!(features & version1)) {
+ dprintf(1, "modern device without virtio_1 feature bit: %pP\n", pci);
+ goto fail;
+ }
+
+ vp_set_features(vp, features & (version1 | iommu_platform));
+ 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: %pP\n", pci);
+ goto fail;
+ }
+ }
+
+ if (vp_find_vq(vp, 2, &vq) < 0 ) {
+ dprintf(1, "fail to find vq for virtio-scsi %pP\n", pci);
+ goto fail;
+ }
+
+ 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, NULL, vp, vq, i);
+
+ if (!tot)
+ goto fail;
+
+ return;
+
+fail:
+ vp_reset(vp);
+ free(vp);
+ free(vq);
+}
+
+void
+init_virtio_scsi_mmio(void *mmio)
+{
+ dprintf(1, "found virtio-scsi-mmio at %p\n", mmio);
+ struct vring_virtqueue *vq = NULL;
+ struct vp_device *vp = malloc_high(sizeof(*vp));
+ if (!vp) {
+ warn_noalloc();
+ return;
+ }
+ vp_init_mmio(vp, mmio);
+ u8 status = VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER;
+
+ if (vp_find_vq(vp, 2, &vq) < 0 ) {
+ dprintf(1, "fail to find vq for virtio-scsi-mmio %p\n", mmio);
+ goto fail;
+ }
+
+ 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(NULL, mmio, vp, vq, i);
+
+ if (!tot)
+ goto fail;
+
+ return;
+
+fail:
+ vp_reset(vp);
+ free(vp);
+ free(vq);
+}
+
+void
+virtio_scsi_setup(void)
+{
+ u8 skip_nonbootable = is_bootprio_strict();
+
+ ASSERT32FLAT();
+ if (! CONFIG_VIRTIO_SCSI)
+ return;
+
+ dprintf(3, "init virtio-scsi\n");
+
+ struct pci_device *pci;
+ foreachpci(pci) {
+ 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;
+
+ if (skip_nonbootable && bootprio_find_pci_device(pci) < 0) {
+ dprintf(1, "skipping init of a non-bootable virtio-scsi at %pP\n",
+ pci);
+ continue;
+ }
+
+ run_thread(init_virtio_scsi, pci);
+ }
+}
diff --git a/roms/seabios-hppa/src/hw/virtio-scsi.h b/roms/seabios-hppa/src/hw/virtio-scsi.h
new file mode 100644
index 000000000..8f01de4cb
--- /dev/null
+++ b/roms/seabios-hppa/src/hw/virtio-scsi.h
@@ -0,0 +1,48 @@
+#ifndef _VIRTIO_SCSI_H
+#define _VIRTIO_SCSI_H
+
+#define VIRTIO_SCSI_CDB_SIZE 32
+#define VIRTIO_SCSI_SENSE_SIZE 96
+
+struct virtio_scsi_config
+{
+ u32 num_queues;
+ u32 seg_max;
+ u32 max_sectors;
+ u32 cmd_per_lun;
+ u32 event_info_size;
+ u32 sense_size;
+ u32 cdb_size;
+ u16 max_channel;
+ u16 max_target;
+ u32 max_lun;
+} __attribute__((packed));
+
+/* This is the first element of the "out" scatter-gather list. */
+struct virtio_scsi_req_cmd {
+ u8 lun[8];
+ u64 id;
+ u8 task_attr;
+ u8 prio;
+ u8 crn;
+ char cdb[VIRTIO_SCSI_CDB_SIZE];
+} __attribute__((packed));
+
+/* This is the first element of the "in" scatter-gather list. */
+struct virtio_scsi_resp_cmd {
+ u32 sense_len;
+ u32 residual;
+ u16 status_qualifier;
+ u8 status;
+ u8 response;
+ u8 sense[VIRTIO_SCSI_SENSE_SIZE];
+} __attribute__((packed));
+
+#define VIRTIO_SCSI_S_OK 0
+
+struct disk_op_s;
+int virtio_scsi_process_op(struct disk_op_s *op);
+void virtio_scsi_setup(void);
+void init_virtio_scsi_mmio(void *data);
+
+#endif /* _VIRTIO_SCSI_H */
diff --git a/roms/seabios-hppa/src/jpeg.c b/roms/seabios-hppa/src/jpeg.c
new file mode 100644
index 000000000..c2138edab
--- /dev/null
+++ b/roms/seabios-hppa/src/jpeg.c
@@ -0,0 +1,1055 @@
+/*
+ * Copyright (C) 2001, Novell Inc.
+ * Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of Novell nor the names of the contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * a tiny jpeg decoder.
+ *
+ * written in August 2001 by Michael Schroeder <mls@suse.de>
+ *
+ */
+
+#define __LITTLE_ENDIAN
+#include "malloc.h"
+#include "string.h"
+#include "util.h"
+#define ISHIFT 11
+
+#define IFIX(a) ((int)((a) * (1 << ISHIFT) + .5))
+#define IMULT(a, b) (((a) * (b)) >> ISHIFT)
+#define ITOINT(a) ((a) >> ISHIFT)
+
+#ifndef __P
+# define __P(x) x
+#endif
+
+/* special markers */
+#define M_BADHUFF -1
+#define M_EOF 0x80
+
+struct in {
+ unsigned char *p;
+ unsigned int bits;
+ int left;
+ int marker;
+
+ int (*func) __P((void *));
+ void *data;
+};
+
+/*********************************/
+struct dec_hufftbl;
+struct enc_hufftbl;
+
+union hufftblp {
+ struct dec_hufftbl *dhuff;
+ struct enc_hufftbl *ehuff;
+};
+
+struct scan {
+ int dc; /* old dc value */
+
+ union hufftblp hudc;
+ union hufftblp huac;
+ int next; /* when to switch to next scan */
+
+ int cid; /* component id */
+ int hv; /* horiz/vert, copied from comp */
+ int tq; /* quant tbl, copied from comp */
+};
+
+/*********************************/
+
+#define DECBITS 10 /* seems to be the optimum */
+
+struct dec_hufftbl {
+ int maxcode[17];
+ int valptr[16];
+ unsigned char vals[256];
+ unsigned int llvals[1 << DECBITS];
+};
+
+static void decode_mcus __P((struct in *, int *, int, struct scan *, int *));
+static int dec_readmarker __P((struct in *));
+static void dec_makehuff __P((struct dec_hufftbl *, int *, unsigned char *));
+
+static void setinput __P((struct in *, unsigned char *));
+/*********************************/
+
+#undef PREC
+#define PREC int
+
+static void idctqtab __P((unsigned char *, PREC *));
+static void idct __P((int *, int *, PREC *, PREC, int));
+static void scaleidctqtab __P((PREC *, PREC));
+
+/*********************************/
+
+static void initcol __P((PREC[][64]));
+
+static void col221111 __P((int *, unsigned char *, int));
+static void col221111_16 __P((int *, unsigned char *, int));
+static void col221111_32 __P((int *, unsigned char *, int));
+
+/*********************************/
+
+#define ERR_NO_SOI 1
+#define ERR_NOT_8BIT 2
+#define ERR_HEIGHT_MISMATCH 3
+#define ERR_WIDTH_MISMATCH 4
+#define ERR_BAD_WIDTH_OR_HEIGHT 5
+#define ERR_TOO_MANY_COMPPS 6
+#define ERR_ILLEGAL_HV 7
+#define ERR_QUANT_TABLE_SELECTOR 8
+#define ERR_NOT_YCBCR_221111 9
+#define ERR_UNKNOWN_CID_IN_SCAN 10
+#define ERR_NOT_SEQUENTIAL_DCT 11
+#define ERR_WRONG_MARKER 12
+#define ERR_NO_EOI 13
+#define ERR_BAD_TABLES 14
+#define ERR_DEPTH_MISMATCH 15
+
+/*********************************/
+
+#define M_SOI 0xd8
+#define M_APP0 0xe0
+#define M_DQT 0xdb
+#define M_SOF0 0xc0
+#define M_DHT 0xc4
+#define M_DRI 0xdd
+#define M_SOS 0xda
+#define M_RST0 0xd0
+#define M_EOI 0xd9
+#define M_COM 0xfe
+
+struct comp {
+ int cid;
+ int hv;
+ int tq;
+};
+
+#define MAXCOMP 4
+struct jpginfo {
+ int nc; /* number of components */
+ int ns; /* number of scans */
+ int dri; /* restart interval */
+ int nm; /* mcus til next marker */
+ int rm; /* next restart marker */
+};
+
+struct jpeg_decdata {
+ int dcts[6 * 64 + 16];
+ int out[64 * 6];
+ int dquant[3][64];
+
+ unsigned char *datap;
+ struct jpginfo info;
+ struct comp comps[MAXCOMP];
+ struct scan dscans[MAXCOMP];
+ unsigned char quant[4][64];
+ struct dec_hufftbl dhuff[4];
+ struct in in;
+
+ int height, width;
+};
+
+static int getbyte(struct jpeg_decdata *jpeg)
+{
+ return *jpeg->datap++;
+}
+
+static int getword(struct jpeg_decdata *jpeg)
+{
+ int c1, c2;
+ c1 = *jpeg->datap++;
+ c2 = *jpeg->datap++;
+ return c1 << 8 | c2;
+}
+
+static int readtables(struct jpeg_decdata *jpeg, int till)
+{
+ int m, l, i, j, lq, pq, tq;
+ int tc, th, tt;
+
+ for (;;) {
+ if (getbyte(jpeg) != 0xff)
+ return -1;
+ if ((m = getbyte(jpeg)) == till)
+ break;
+
+ switch (m) {
+ case 0xc2:
+ return 0;
+
+ case M_DQT:
+ lq = getword(jpeg);
+ while (lq > 2) {
+ pq = getbyte(jpeg);
+ tq = pq & 15;
+ if (tq > 3)
+ return -1;
+ pq >>= 4;
+ if (pq != 0)
+ return -1;
+ for (i = 0; i < 64; i++)
+ jpeg->quant[tq][i] = getbyte(jpeg);
+ lq -= 64 + 1;
+ }
+ break;
+
+ case M_DHT:
+ l = getword(jpeg);
+ while (l > 2) {
+ int hufflen[16], k;
+ unsigned char huffvals[256];
+
+ tc = getbyte(jpeg);
+ th = tc & 15;
+ tc >>= 4;
+ tt = tc * 2 + th;
+ if (tc > 1 || th > 1)
+ return -1;
+ for (i = 0; i < 16; i++)
+ hufflen[i] = getbyte(jpeg);
+ l -= 1 + 16;
+ k = 0;
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < hufflen[i]; j++)
+ huffvals[k++] = getbyte(jpeg);
+ l -= hufflen[i];
+ }
+ dec_makehuff(jpeg->dhuff + tt, hufflen, huffvals);
+ }
+ break;
+
+ case M_DRI:
+ l = getword(jpeg);
+ jpeg->info.dri = getword(jpeg);
+ break;
+
+ default:
+ l = getword(jpeg);
+ while (l-- > 2)
+ getbyte(jpeg);
+ break;
+ }
+ }
+ return 0;
+}
+
+static void dec_initscans(struct jpeg_decdata *jpeg)
+{
+ int i;
+
+ jpeg->info.nm = jpeg->info.dri + 1;
+ jpeg->info.rm = M_RST0;
+ for (i = 0; i < jpeg->info.ns; i++)
+ jpeg->dscans[i].dc = 0;
+}
+
+static int dec_checkmarker(struct jpeg_decdata *jpeg)
+{
+ int i;
+
+ if (dec_readmarker(&jpeg->in) != jpeg->info.rm)
+ return -1;
+ jpeg->info.nm = jpeg->info.dri;
+ jpeg->info.rm = (jpeg->info.rm + 1) & ~0x08;
+ for (i = 0; i < jpeg->info.ns; i++)
+ jpeg->dscans[i].dc = 0;
+ return 0;
+}
+
+struct jpeg_decdata *jpeg_alloc(void)
+{
+ struct jpeg_decdata *jpeg = malloc_tmphigh(sizeof(*jpeg));
+ return jpeg;
+}
+
+int jpeg_decode(struct jpeg_decdata *jpeg, unsigned char *buf)
+{
+ int i, j, m, tac, tdc;
+
+ if (!jpeg || !buf)
+ return -1;
+ jpeg->datap = buf;
+ if (getbyte(jpeg) != 0xff)
+ return ERR_NO_SOI;
+ if (getbyte(jpeg) != M_SOI)
+ return ERR_NO_SOI;
+ if (readtables(jpeg, M_SOF0))
+ return ERR_BAD_TABLES;
+ getword(jpeg);
+ i = getbyte(jpeg);
+ if (i != 8)
+ return ERR_NOT_8BIT;
+ jpeg->height = getword(jpeg);
+ jpeg->width = getword(jpeg);
+ if ((jpeg->height & 15) || (jpeg->width & 15))
+ return ERR_BAD_WIDTH_OR_HEIGHT;
+ jpeg->info.nc = getbyte(jpeg);
+ if (jpeg->info.nc > MAXCOMP)
+ return ERR_TOO_MANY_COMPPS;
+ for (i = 0; i < jpeg->info.nc; i++) {
+ int h, v;
+ jpeg->comps[i].cid = getbyte(jpeg);
+ jpeg->comps[i].hv = getbyte(jpeg);
+ v = jpeg->comps[i].hv & 15;
+ h = jpeg->comps[i].hv >> 4;
+ jpeg->comps[i].tq = getbyte(jpeg);
+ if (h > 3 || v > 3)
+ return ERR_ILLEGAL_HV;
+ if (jpeg->comps[i].tq > 3)
+ return ERR_QUANT_TABLE_SELECTOR;
+ }
+ if (readtables(jpeg, M_SOS))
+ return ERR_BAD_TABLES;
+ getword(jpeg);
+ jpeg->info.ns = getbyte(jpeg);
+ if (jpeg->info.ns != 3)
+ return ERR_NOT_YCBCR_221111;
+ for (i = 0; i < 3; i++) {
+ jpeg->dscans[i].cid = getbyte(jpeg);
+ tdc = getbyte(jpeg);
+ tac = tdc & 15;
+ tdc >>= 4;
+ if (tdc > 1 || tac > 1)
+ return ERR_QUANT_TABLE_SELECTOR;
+ for (j = 0; j < jpeg->info.nc; j++)
+ if (jpeg->comps[j].cid == jpeg->dscans[i].cid)
+ break;
+ if (j == jpeg->info.nc)
+ return ERR_UNKNOWN_CID_IN_SCAN;
+ jpeg->dscans[i].hv = jpeg->comps[j].hv;
+ jpeg->dscans[i].tq = jpeg->comps[j].tq;
+ jpeg->dscans[i].hudc.dhuff = &jpeg->dhuff[tdc];
+ jpeg->dscans[i].huac.dhuff = &jpeg->dhuff[2 + tac];
+ }
+
+ i = getbyte(jpeg);
+ j = getbyte(jpeg);
+ m = getbyte(jpeg);
+
+ if (i != 0 || j != 63 || m != 0)
+ return ERR_NOT_SEQUENTIAL_DCT;
+
+ if (jpeg->dscans[0].cid != 1 || jpeg->dscans[1].cid != 2
+ || jpeg->dscans[2].cid != 3)
+ return ERR_NOT_YCBCR_221111;
+
+ if (jpeg->dscans[0].hv != 0x22 || jpeg->dscans[1].hv != 0x11
+ || jpeg->dscans[2].hv != 0x11)
+ return ERR_NOT_YCBCR_221111;
+
+ idctqtab(jpeg->quant[jpeg->dscans[0].tq], jpeg->dquant[0]);
+ idctqtab(jpeg->quant[jpeg->dscans[1].tq], jpeg->dquant[1]);
+ idctqtab(jpeg->quant[jpeg->dscans[2].tq], jpeg->dquant[2]);
+ initcol(jpeg->dquant);
+ setinput(&jpeg->in, jpeg->datap);
+
+#if 0
+ /* landing zone */
+ img[len] = 0;
+ img[len + 1] = 0xff;
+ img[len + 2] = M_EOF;
+#endif
+
+ dec_initscans(jpeg);
+
+ return 0;
+}
+
+void jpeg_get_size(struct jpeg_decdata *jpeg, int *width, int *height)
+{
+ *width = jpeg->width;
+ *height = jpeg->height;
+}
+
+int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic, int width
+ , int height, int depth, int bytes_per_line_dest)
+{
+ int m, mcusx, mcusy, mx, my, mloffset, jpgbpl;
+ int max[6];
+
+ if (jpeg->height != height)
+ return ERR_HEIGHT_MISMATCH;
+ if (jpeg->width != width)
+ return ERR_WIDTH_MISMATCH;
+
+ jpgbpl = width * depth / 8;
+ mloffset = bytes_per_line_dest > jpgbpl ? bytes_per_line_dest : jpgbpl;
+
+ mcusx = jpeg->width >> 4;
+ mcusy = jpeg->height >> 4;
+
+ jpeg->dscans[0].next = 6 - 4;
+ jpeg->dscans[1].next = 6 - 4 - 1;
+ jpeg->dscans[2].next = 6 - 4 - 1 - 1; /* 411 encoding */
+ for (my = 0; my < mcusy; my++) {
+ for (mx = 0; mx < mcusx; mx++) {
+ if (jpeg->info.dri && !--jpeg->info.nm)
+ if (dec_checkmarker(jpeg))
+ return ERR_WRONG_MARKER;
+
+ decode_mcus(&jpeg->in, jpeg->dcts, 6, jpeg->dscans, max);
+ idct(jpeg->dcts, jpeg->out, jpeg->dquant[0],
+ IFIX(128.5), max[0]);
+ idct(jpeg->dcts + 64, jpeg->out + 64, jpeg->dquant[0],
+ IFIX(128.5), max[1]);
+ idct(jpeg->dcts + 128, jpeg->out + 128, jpeg->dquant[0],
+ IFIX(128.5), max[2]);
+ idct(jpeg->dcts + 192, jpeg->out + 192, jpeg->dquant[0],
+ IFIX(128.5), max[3]);
+ idct(jpeg->dcts + 256, jpeg->out + 256, jpeg->dquant[1],
+ IFIX(0.5), max[4]);
+ idct(jpeg->dcts + 320, jpeg->out + 320, jpeg->dquant[2],
+ IFIX(0.5), max[5]);
+
+ switch (depth) {
+ case 32:
+ col221111_32(jpeg->out,
+ pic + (my * 16 * mloffset + mx * 16 * 4),
+ mloffset);
+ break;
+ case 24:
+ col221111(jpeg->out,
+ pic + (my * 16 * mloffset + mx * 16 * 3),
+ mloffset);
+ break;
+ case 16:
+ col221111_16(jpeg->out,
+ pic + (my * 16 * mloffset + mx * 16 * 2),
+ mloffset);
+ break;
+ default:
+ return ERR_DEPTH_MISMATCH;
+ break;
+ }
+ }
+ }
+
+ m = dec_readmarker(&jpeg->in);
+ if (m != M_EOI)
+ return ERR_NO_EOI;
+
+ return 0;
+}
+
+/****************************************************************/
+/************** huffman decoder ***************/
+/****************************************************************/
+
+static int fillbits __P((struct in *, int, unsigned int));
+static int dec_rec2 __P((struct in *, struct dec_hufftbl *, int *, int, int));
+
+static void setinput(struct in *in, unsigned char *p)
+{
+ in->p = p;
+ in->left = 0;
+ in->bits = 0;
+ in->marker = 0;
+}
+
+static int fillbits(struct in *in, int le, unsigned int bi)
+{
+ int b, m;
+
+ if (in->marker) {
+ if (le <= 16)
+ in->bits = bi << 16, le += 16;
+ return le;
+ }
+ while (le <= 24) {
+ b = *in->p++;
+ if (b == 0xff && (m = *in->p++) != 0) {
+ if (m == M_EOF) {
+ if (in->func && (m = in->func(in->data)) == 0)
+ continue;
+ }
+ in->marker = m;
+ if (le <= 16)
+ bi = bi << 16, le += 16;
+ break;
+ }
+ bi = bi << 8 | b;
+ le += 8;
+ }
+ in->bits = bi; /* tmp... 2 return values needed */
+ return le;
+}
+
+static int dec_readmarker(struct in *in)
+{
+ int m;
+
+ in->left = fillbits(in, in->left, in->bits);
+ if ((m = in->marker) == 0)
+ return 0;
+ in->left = 0;
+ in->marker = 0;
+ return m;
+}
+
+#define LEBI_DCL int le, bi
+#define LEBI_GET(in) (le = in->left, bi = in->bits)
+#define LEBI_PUT(in) (in->left = le, in->bits = bi)
+
+#define GETBITS(in, n) ( \
+ (le < (n) ? le = fillbits(in, le, bi), bi = in->bits : 0), \
+ (le -= (n)), \
+ bi >> le & ((1 << (n)) - 1) \
+)
+
+#define UNGETBITS(in, n) ( \
+ le += (n) \
+)
+
+
+static int dec_rec2(struct in *in, struct dec_hufftbl *hu, int *runp,
+ int c, int i)
+{
+ LEBI_DCL;
+
+ LEBI_GET(in);
+ if (i) {
+ UNGETBITS(in, i & 127);
+ *runp = i >> 8 & 15;
+ i >>= 16;
+ } else {
+ for (i = DECBITS;
+ (c = ((c << 1) | GETBITS(in, 1))) >= (hu->maxcode[i]); i++);
+ if (i >= 16) {
+ in->marker = M_BADHUFF;
+ return 0;
+ }
+ i = hu->vals[hu->valptr[i] + c - hu->maxcode[i - 1] * 2];
+ *runp = i >> 4;
+ i &= 15;
+ }
+ if (i == 0) { /* sigh, 0xf0 is 11 bit */
+ LEBI_PUT(in);
+ return 0;
+ }
+ /* receive part */
+ c = GETBITS(in, i);
+ if (c < (1 << (i - 1)))
+ c += (-1 << i) + 1;
+ LEBI_PUT(in);
+ return c;
+}
+
+#define DEC_REC(in, hu, r, i) ( \
+ r = GETBITS(in, DECBITS), \
+ i = hu->llvals[r], \
+ i & 128 ? \
+ ( \
+ UNGETBITS(in, i & 127), \
+ r = i >> 8 & 15, \
+ i >> 16 \
+ ) \
+ : \
+ ( \
+ LEBI_PUT(in), \
+ i = dec_rec2(in, hu, &r, r, i), \
+ LEBI_GET(in), \
+ i \
+ ) \
+)
+
+static void decode_mcus(struct in *in, int *dct, int n, struct scan *sc,
+ int *maxp)
+{
+ struct dec_hufftbl *hu;
+ int i, r, t;
+ LEBI_DCL;
+
+ memset(dct, 0, n * 64 * sizeof(*dct));
+ LEBI_GET(in);
+ while (n-- > 0) {
+ hu = sc->hudc.dhuff;
+ *dct++ = (sc->dc += DEC_REC(in, hu, r, t));
+
+ hu = sc->huac.dhuff;
+ i = 63;
+ while (i > 0) {
+ t = DEC_REC(in, hu, r, t);
+ if (t == 0 && r == 0) {
+ dct += i;
+ break;
+ }
+ dct += r;
+ *dct++ = t;
+ i -= r + 1;
+ }
+ *maxp++ = 64 - i;
+ if (n == sc->next)
+ sc++;
+ }
+ LEBI_PUT(in);
+}
+
+static void dec_makehuff(struct dec_hufftbl *hu, int *hufflen,
+ unsigned char *huffvals)
+{
+ int code, k, i, j, d, x, c, v;
+ for (i = 0; i < (1 << DECBITS); i++)
+ hu->llvals[i] = 0;
+
+ /*
+ * llvals layout:
+ *
+ * value v already known, run r, backup u bits:
+ * vvvvvvvvvvvvvvvv 0000 rrrr 1 uuuuuuu
+ * value unknown, size b bits, run r, backup u bits:
+ * 000000000000bbbb 0000 rrrr 0 uuuuuuu
+ * value and size unknown:
+ * 0000000000000000 0000 0000 0 0000000
+ */
+
+ code = 0;
+ k = 0;
+ for (i = 0; i < 16; i++, code <<= 1) { /* sizes */
+ hu->valptr[i] = k;
+ for (j = 0; j < hufflen[i]; j++) {
+ hu->vals[k] = *huffvals++;
+ if (i < DECBITS) {
+ c = code << (DECBITS - 1 - i);
+ v = hu->vals[k] & 0x0f; /* size */
+ for (d = 1 << (DECBITS - 1 - i); --d >= 0;) {
+ if (v + i < DECBITS) { /* both fit in table */
+ x = d >> (DECBITS - 1 - v - i);
+ if (v && x < (1 << (v - 1)))
+ x += (-1 << v) + 1;
+ x = x << 16 | (hu->vals[k] & 0xf0) << 4 |
+ (DECBITS - (i + 1 + v)) | 128;
+ } else
+ x = v << 16 | (hu->vals[k] & 0xf0) << 4 |
+ (DECBITS - (i + 1));
+ hu->llvals[c | d] = x;
+ }
+ }
+ code++;
+ k++;
+ }
+ hu->maxcode[i] = code;
+ }
+ hu->maxcode[16] = 0x20000; /* always terminate decode */
+}
+
+/****************************************************************/
+/************** idct ***************/
+/****************************************************************/
+
+#define ONE ((PREC)IFIX(1.))
+#define S2 ((PREC)IFIX(0.382683432))
+#define C2 ((PREC)IFIX(0.923879532))
+#define C4 ((PREC)IFIX(0.707106781))
+
+#define S22 ((PREC)IFIX(2 * 0.382683432))
+#define C22 ((PREC)IFIX(2 * 0.923879532))
+#define IC4 ((PREC)IFIX(1 / 0.707106781))
+
+#define C3IC1 ((PREC)IFIX(0.847759065)) /* c3/c1 */
+#define C5IC1 ((PREC)IFIX(0.566454497)) /* c5/c1 */
+#define C7IC1 ((PREC)IFIX(0.198912367)) /* c7/c1 */
+
+#define XPP(a,b) (t = a + b, b = a - b, a = t)
+#define XMP(a,b) (t = a - b, b = a + b, a = t)
+#define XPM(a,b) (t = a + b, b = b - a, a = t)
+
+#define ROT(a,b,s,c) ( t = IMULT(a + b, s), \
+ a = IMULT(a, c - s) + t, \
+ b = IMULT(b, c + s) - t)
+
+#define IDCT \
+( \
+ XPP(t0, t1), \
+ XMP(t2, t3), \
+ t2 = IMULT(t2, IC4) - t3, \
+ XPP(t0, t3), \
+ XPP(t1, t2), \
+ XMP(t4, t7), \
+ XPP(t5, t6), \
+ XMP(t5, t7), \
+ t5 = IMULT(t5, IC4), \
+ ROT(t4, t6, S22, C22), \
+ t6 -= t7, \
+ t5 -= t6, \
+ t4 -= t5, \
+ XPP(t0, t7), \
+ XPP(t1, t6), \
+ XPP(t2, t5), \
+ XPP(t3, t4) \
+)
+
+static unsigned char zig2[64] = {
+ 0, 2, 3, 9, 10, 20, 21, 35,
+ 14, 16, 25, 31, 39, 46, 50, 57,
+ 5, 7, 12, 18, 23, 33, 37, 48,
+ 27, 29, 41, 44, 52, 55, 59, 62,
+ 15, 26, 30, 40, 45, 51, 56, 58,
+ 1, 4, 8, 11, 19, 22, 34, 36,
+ 28, 42, 43, 53, 54, 60, 61, 63,
+ 6, 13, 17, 24, 32, 38, 47, 49
+};
+
+static void idct(int *in, int *out, PREC * quant, PREC off, int max)
+{
+ PREC t0, t1, t2, t3, t4, t5, t6, t7, t;
+ PREC tmp[64], *tmpp;
+ int i, j;
+ unsigned char *zig2p;
+
+ t0 = off;
+ if (max == 1) {
+ t0 += in[0] * quant[0];
+ for (i = 0; i < 64; i++)
+ out[i] = ITOINT(t0);
+ return;
+ }
+ zig2p = zig2;
+ tmpp = tmp;
+ for (i = 0; i < 8; i++) {
+ j = *zig2p++;
+ t0 += in[j] * quant[j];
+ j = *zig2p++;
+ t5 = in[j] * quant[j];
+ j = *zig2p++;
+ t2 = in[j] * quant[j];
+ j = *zig2p++;
+ t7 = in[j] * quant[j];
+ j = *zig2p++;
+ t1 = in[j] * quant[j];
+ j = *zig2p++;
+ t4 = in[j] * quant[j];
+ j = *zig2p++;
+ t3 = in[j] * quant[j];
+ j = *zig2p++;
+ t6 = in[j] * quant[j];
+ IDCT;
+ tmpp[0 * 8] = t0;
+ tmpp[1 * 8] = t1;
+ tmpp[2 * 8] = t2;
+ tmpp[3 * 8] = t3;
+ tmpp[4 * 8] = t4;
+ tmpp[5 * 8] = t5;
+ tmpp[6 * 8] = t6;
+ tmpp[7 * 8] = t7;
+ tmpp++;
+ t0 = 0;
+ }
+ for (i = 0; i < 8; i++) {
+ t0 = tmp[8 * i + 0];
+ t1 = tmp[8 * i + 1];
+ t2 = tmp[8 * i + 2];
+ t3 = tmp[8 * i + 3];
+ t4 = tmp[8 * i + 4];
+ t5 = tmp[8 * i + 5];
+ t6 = tmp[8 * i + 6];
+ t7 = tmp[8 * i + 7];
+ IDCT;
+ out[8 * i + 0] = ITOINT(t0);
+ out[8 * i + 1] = ITOINT(t1);
+ out[8 * i + 2] = ITOINT(t2);
+ out[8 * i + 3] = ITOINT(t3);
+ out[8 * i + 4] = ITOINT(t4);
+ out[8 * i + 5] = ITOINT(t5);
+ out[8 * i + 6] = ITOINT(t6);
+ out[8 * i + 7] = ITOINT(t7);
+ }
+}
+
+static unsigned char zig[64] = {
+ 0, 1, 5, 6, 14, 15, 27, 28,
+ 2, 4, 7, 13, 16, 26, 29, 42,
+ 3, 8, 12, 17, 25, 30, 41, 43,
+ 9, 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63
+};
+
+static PREC aaidct[8] = {
+ IFIX(0.3535533906), IFIX(0.4903926402),
+ IFIX(0.4619397663), IFIX(0.4157348062),
+ IFIX(0.3535533906), IFIX(0.2777851165),
+ IFIX(0.1913417162), IFIX(0.0975451610)
+};
+
+
+static void idctqtab(unsigned char *qin, PREC * qout)
+{
+ int i, j;
+
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < 8; j++)
+ qout[zig[i * 8 + j]] = qin[zig[i * 8 + j]] *
+ IMULT(aaidct[i], aaidct[j]);
+}
+
+static void scaleidctqtab(PREC * q, PREC sc)
+{
+ int i;
+
+ for (i = 0; i < 64; i++)
+ q[i] = IMULT(q[i], sc);
+}
+
+/****************************************************************/
+/************** color decoder ***************/
+/****************************************************************/
+
+#define ROUND
+
+/*
+ * YCbCr Color transformation:
+ *
+ * y:0..255 Cb:-128..127 Cr:-128..127
+ *
+ * R = Y + 1.40200 * Cr
+ * G = Y - 0.34414 * Cb - 0.71414 * Cr
+ * B = Y + 1.77200 * Cb
+ *
+ * =>
+ * Cr *= 1.40200;
+ * Cb *= 1.77200;
+ * Cg = 0.19421 * Cb + .50937 * Cr;
+ * R = Y + Cr;
+ * G = Y - Cg;
+ * B = Y + Cb;
+ *
+ * =>
+ * Cg = (50 * Cb + 130 * Cr + 128) >> 8;
+ */
+
+static void initcol(PREC q[][64])
+{
+ scaleidctqtab(q[1], IFIX(1.77200));
+ scaleidctqtab(q[2], IFIX(1.40200));
+}
+
+/* This is optimized for the stupid sun SUNWspro compiler. */
+#define STORECLAMP(a,x) \
+( \
+ (a) = (x), \
+ (unsigned int)(x) >= 256 ? \
+ ((a) = (x) < 0 ? 0 : 255) \
+ : \
+ 0 \
+)
+
+#define CLAMP(x) ((unsigned int)(x) >= 256 ? ((x) < 0 ? 0 : 255) : (x))
+
+#ifdef ROUND
+
+#define CBCRCG(yin, xin) \
+( \
+ cb = outc[0 +yin*8+xin], \
+ cr = outc[64+yin*8+xin], \
+ cg = (50 * cb + 130 * cr + 128) >> 8 \
+)
+
+#else
+
+#define CBCRCG(yin, xin) \
+( \
+ cb = outc[0 +yin*8+xin], \
+ cr = outc[64+yin*8+xin], \
+ cg = (3 * cb + 8 * cr) >> 4 \
+)
+
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define PIC(yin, xin, p, xout) \
+( \
+ y = outy[(yin) * 8 + xin], \
+ STORECLAMP(p[(xout) * 3 + 2], y + cr), \
+ STORECLAMP(p[(xout) * 3 + 1], y - cg), \
+ STORECLAMP(p[(xout) * 3 + 0], y + cb) \
+)
+#else
+#define PIC(yin, xin, p, xout) \
+( \
+ y = outy[(yin) * 8 + xin], \
+ STORECLAMP(p[(xout) * 3 + 0], y + cr), \
+ STORECLAMP(p[(xout) * 3 + 1], y - cg), \
+ STORECLAMP(p[(xout) * 3 + 2], y + cb) \
+)
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define PIC_16(yin, xin, p, xout, add) \
+( \
+ y = outy[(yin) * 8 + xin], \
+ y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \
+ ((CLAMP(y - cg + add ) & 0xfc) << 3) | \
+ ((CLAMP(y + cb + add*2+1) ) >> 3), \
+ p[(xout) * 2 + 0] = y & 0xff, \
+ p[(xout) * 2 + 1] = y >> 8 \
+)
+#else
+#ifdef CONFIG_PPC
+#define PIC_16(yin, xin, p, xout, add) \
+( \
+ y = outy[(yin) * 8 + xin], \
+ y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 7) | \
+ ((CLAMP(y - cg + add*2+1) & 0xf8) << 2) | \
+ ((CLAMP(y + cb + add*2+1) ) >> 3), \
+ p[(xout) * 2 + 0] = y >> 8, \
+ p[(xout) * 2 + 1] = y & 0xff \
+)
+#else
+#define PIC_16(yin, xin, p, xout, add) \
+( \
+ y = outy[(yin) * 8 + xin], \
+ y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \
+ ((CLAMP(y - cg + add ) & 0xfc) << 3) | \
+ ((CLAMP(y + cb + add*2+1) ) >> 3), \
+ p[(xout) * 2 + 0] = y >> 8, \
+ p[(xout) * 2 + 1] = y & 0xff \
+)
+#endif
+#endif
+
+#define PIC_32(yin, xin, p, xout) \
+( \
+ y = outy[(yin) * 8 + xin], \
+ STORECLAMP(p[(xout) * 4 + 0], y + cr), \
+ STORECLAMP(p[(xout) * 4 + 1], y - cg), \
+ STORECLAMP(p[(xout) * 4 + 2], y + cb), \
+ p[(xout) * 4 + 3] = 0 \
+)
+
+#define PIC221111(xin) \
+( \
+ CBCRCG(0, xin), \
+ PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \
+ PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1), \
+ PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \
+ PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \
+)
+
+#define PIC221111_16(xin) \
+( \
+ CBCRCG(0, xin), \
+ PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0, 3), \
+ PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1, 0), \
+ PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0, 1), \
+ PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1, 2) \
+)
+
+#define PIC221111_32(xin) \
+( \
+ CBCRCG(0, xin), \
+ PIC_32(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \
+ PIC_32(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1), \
+ PIC_32(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \
+ PIC_32(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \
+)
+
+static void col221111(int *out, unsigned char *pic, int width)
+{
+ int i, j, k;
+ unsigned char *pic0, *pic1;
+ int *outy, *outc;
+ int cr, cg, cb, y;
+
+ pic0 = pic;
+ pic1 = pic + width;
+ outy = out;
+ outc = out + 64 * 4;
+ for (i = 2; i > 0; i--) {
+ for (j = 4; j > 0; j--) {
+ for (k = 0; k < 8; k++) {
+ PIC221111(k);
+ }
+ outc += 8;
+ outy += 16;
+ pic0 += 2 * width;
+ pic1 += 2 * width;
+ }
+ outy += 64 * 2 - 16 * 4;
+ }
+}
+
+static void col221111_16(int *out, unsigned char *pic, int width)
+{
+ int i, j, k;
+ unsigned char *pic0, *pic1;
+ int *outy, *outc;
+ int cr, cg, cb, y;
+
+ pic0 = pic;
+ pic1 = pic + width;
+ outy = out;
+ outc = out + 64 * 4;
+ for (i = 2; i > 0; i--) {
+ for (j = 4; j > 0; j--) {
+ for (k = 0; k < 8; k++) {
+ PIC221111_16(k);
+ }
+ outc += 8;
+ outy += 16;
+ pic0 += 2 * width;
+ pic1 += 2 * width;
+ }
+ outy += 64 * 2 - 16 * 4;
+ }
+}
+
+static void col221111_32(int *out, unsigned char *pic, int width)
+{
+ int i, j, k;
+ unsigned char *pic0, *pic1;
+ int *outy, *outc;
+ int cr, cg, cb, y;
+
+ pic0 = pic;
+ pic1 = pic + width;
+ outy = out;
+ outc = out + 64 * 4;
+ for (i = 2; i > 0; i--) {
+ for (j = 4; j > 0; j--) {
+ for (k = 0; k < 8; k++) {
+ PIC221111_32(k);
+ }
+ outc += 8;
+ outy += 16;
+ pic0 += 2 * width;
+ pic1 += 2 * width;
+ }
+ outy += 64 * 2 - 16 * 4;
+ }
+}
diff --git a/roms/seabios-hppa/src/kbd.c b/roms/seabios-hppa/src/kbd.c
new file mode 100644
index 000000000..15e5ae789
--- /dev/null
+++ b/roms/seabios-hppa/src/kbd.c
@@ -0,0 +1,599 @@
+// 16bit code to handle keyboard requests.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_BDA
+#include "bregs.h" // struct bregs
+#include "config.h" // CONFIG_*
+#include "hw/ps2port.h" // ps2_kbd_command
+#include "hw/usb-hid.h" // usb_kbd_command
+#include "output.h" // debug_enter
+#include "stacks.h" // yield
+#include "string.h" // memset
+#include "util.h" // kbd_init
+
+void
+kbd_init(void)
+{
+ dprintf(3, "init keyboard\n");
+ u16 x = offsetof(struct bios_data_area_s, kbd_buf);
+ SET_BDA(kbd_flag1, KF1_101KBD);
+ SET_BDA(kbd_buf_head, x);
+ SET_BDA(kbd_buf_tail, x);
+ SET_BDA(kbd_buf_start_offset, x);
+
+ SET_BDA(kbd_buf_end_offset
+ , x + FIELD_SIZEOF(struct bios_data_area_s, kbd_buf));
+}
+
+u8
+enqueue_key(u16 keycode)
+{
+ u16 buffer_start = GET_BDA(kbd_buf_start_offset);
+ u16 buffer_end = GET_BDA(kbd_buf_end_offset);
+
+ u16 buffer_head = GET_BDA(kbd_buf_head);
+ u16 buffer_tail = GET_BDA(kbd_buf_tail);
+
+ u16 temp_tail = buffer_tail;
+ buffer_tail += 2;
+ if (buffer_tail >= buffer_end)
+ buffer_tail = buffer_start;
+
+ if (buffer_tail == buffer_head)
+ return 0;
+
+ SET_FARVAR(SEG_BDA, *(u16*)(temp_tail+0), keycode);
+ SET_BDA(kbd_buf_tail, buffer_tail);
+ return 1;
+}
+
+static void
+dequeue_key(struct bregs *regs, int incr, int extended)
+{
+ yield();
+ u16 buffer_head;
+ u16 buffer_tail;
+ for (;;) {
+ buffer_head = GET_BDA(kbd_buf_head);
+ buffer_tail = GET_BDA(kbd_buf_tail);
+
+ if (buffer_head != buffer_tail)
+ break;
+ if (!incr) {
+ regs->flags |= F_ZF;
+ return;
+ }
+ yield_toirq();
+ }
+
+ u16 keycode = GET_FARVAR(SEG_BDA, *(u16*)(buffer_head+0));
+ u8 ascii = keycode & 0xff;
+ if (!extended) {
+ // Translate extended keys
+ if (ascii == 0xe0 && keycode & 0xff00)
+ keycode &= 0xff00;
+ else if (keycode == 0xe00d || keycode == 0xe00a)
+ // Extended enter key
+ keycode = 0x1c00 | ascii;
+ else if (keycode == 0xe02f)
+ // Extended '/' key
+ keycode = 0x352f;
+ // Technically, if the ascii value is 0xf0 or if the
+ // 'scancode' is greater than 0x84 then the key should be
+ // discarded. However, there seems no harm in passing on the
+ // extended values in these cases.
+ }
+ if (ascii == 0xf0 && keycode & 0xff00)
+ keycode &= 0xff00;
+ regs->ax = keycode;
+
+ if (!incr) {
+ regs->flags &= ~F_ZF;
+ return;
+ }
+ u16 buffer_start = GET_BDA(kbd_buf_start_offset);
+ u16 buffer_end = GET_BDA(kbd_buf_end_offset);
+
+ buffer_head += 2;
+ if (buffer_head >= buffer_end)
+ buffer_head = buffer_start;
+ SET_BDA(kbd_buf_head, buffer_head);
+}
+
+static int
+kbd_command(int command, u8 *param)
+{
+ if (usb_kbd_active())
+ return usb_kbd_command(command, param);
+ return ps2_kbd_command(command, param);
+}
+
+// read keyboard input
+static void
+handle_1600(struct bregs *regs)
+{
+ dequeue_key(regs, 1, 0);
+}
+
+// check keyboard status
+static void
+handle_1601(struct bregs *regs)
+{
+ dequeue_key(regs, 0, 0);
+}
+
+// get shift flag status
+static void
+handle_1602(struct bregs *regs)
+{
+ yield();
+ regs->al = GET_BDA(kbd_flag0);
+}
+
+// store key-stroke into buffer
+static void
+handle_1605(struct bregs *regs)
+{
+ regs->al = !enqueue_key(regs->cx);
+}
+
+// GET KEYBOARD FUNCTIONALITY
+static void
+handle_1609(struct bregs *regs)
+{
+ // bit Bochs Description
+ // 7 0 reserved
+ // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
+ // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
+ // 4 1 INT 16/AH=0Ah supported
+ // 3 0 INT 16/AX=0306h supported
+ // 2 0 INT 16/AX=0305h supported
+ // 1 0 INT 16/AX=0304h supported
+ // 0 0 INT 16/AX=0300h supported
+ //
+ regs->al = 0x30;
+}
+
+// GET KEYBOARD ID
+static void noinline
+handle_160a(struct bregs *regs)
+{
+ u8 param[2];
+ int ret = kbd_command(ATKBD_CMD_GETID, param);
+ if (ret) {
+ regs->bx = 0;
+ return;
+ }
+ regs->bx = (param[1] << 8) | param[0];
+}
+
+// read MF-II keyboard input
+static void
+handle_1610(struct bregs *regs)
+{
+ dequeue_key(regs, 1, 1);
+}
+
+// check MF-II keyboard status
+static void
+handle_1611(struct bregs *regs)
+{
+ dequeue_key(regs, 0, 1);
+}
+
+// get extended keyboard status
+static void
+handle_1612(struct bregs *regs)
+{
+ yield();
+ regs->ax = ((GET_BDA(kbd_flag0) & ~((KF1_RCTRL|KF1_RALT) << 8))
+ | ((GET_BDA(kbd_flag1) & (KF1_RCTRL|KF1_RALT)) << 8));
+ //BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
+}
+
+static void
+handle_166f(struct bregs *regs)
+{
+ if (regs->al == 0x08)
+ // unsupported, aka normal keyboard
+ regs->ah = 2;
+}
+
+// keyboard capability check called by DOS 5.0+ keyb
+static void
+handle_1692(struct bregs *regs)
+{
+ // function int16 ah=0x10-0x12 supported
+ regs->ah = 0x80;
+}
+
+// 122 keys capability check called by DOS 5.0+ keyb
+static void
+handle_16a2(struct bregs *regs)
+{
+ // don't change AH : function int16 ah=0x20-0x22 NOT supported
+}
+
+static void
+handle_16XX(struct bregs *regs)
+{
+ warn_unimplemented(regs);
+}
+
+static void noinline
+set_leds(void)
+{
+ u8 shift_flags = (GET_BDA(kbd_flag0) >> 4) & 0x07;
+ u8 kbd_led = GET_BDA(kbd_led);
+ u8 led_flags = kbd_led & 0x07;
+ if (shift_flags == led_flags)
+ return;
+
+ int ret = kbd_command(ATKBD_CMD_SETLEDS, &shift_flags);
+ if (ret)
+ // Error
+ return;
+ kbd_led = (kbd_led & ~0x07) | shift_flags;
+ SET_BDA(kbd_led, kbd_led);
+}
+
+// INT 16h Keyboard Service Entry Point
+void VISIBLE16
+handle_16(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_16);
+ if (! CONFIG_KEYBOARD)
+ return;
+
+ // XXX - set_leds should be called from irq handler
+ set_leds();
+
+ switch (regs->ah) {
+ case 0x00: handle_1600(regs); break;
+ case 0x01: handle_1601(regs); break;
+ case 0x02: handle_1602(regs); break;
+ case 0x05: handle_1605(regs); break;
+ case 0x09: handle_1609(regs); break;
+ case 0x0a: handle_160a(regs); break;
+ case 0x10: handle_1610(regs); break;
+ case 0x11: handle_1611(regs); break;
+ case 0x12: handle_1612(regs); break;
+ case 0x92: handle_1692(regs); break;
+ case 0xa2: handle_16a2(regs); break;
+ case 0x6f: handle_166f(regs); break;
+ default: handle_16XX(regs); break;
+ }
+}
+
+#define none 0
+
+static struct scaninfo {
+ u16 normal;
+ u16 shift;
+ u16 control;
+ u16 alt;
+} scan_to_keycode[] VAR16 = {
+ { none, none, none, none },
+ { 0x011b, 0x011b, 0x011b, 0x01f0 }, /* escape */
+ { 0x0231, 0x0221, none, 0x7800 }, /* 1! */
+ { 0x0332, 0x0340, 0x0300, 0x7900 }, /* 2@ */
+ { 0x0433, 0x0423, none, 0x7a00 }, /* 3# */
+ { 0x0534, 0x0524, none, 0x7b00 }, /* 4$ */
+ { 0x0635, 0x0625, none, 0x7c00 }, /* 5% */
+ { 0x0736, 0x075e, 0x071e, 0x7d00 }, /* 6^ */
+ { 0x0837, 0x0826, none, 0x7e00 }, /* 7& */
+ { 0x0938, 0x092a, none, 0x7f00 }, /* 8* */
+ { 0x0a39, 0x0a28, none, 0x8000 }, /* 9( */
+ { 0x0b30, 0x0b29, none, 0x8100 }, /* 0) */
+ { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200 }, /* -_ */
+ { 0x0d3d, 0x0d2b, none, 0x8300 }, /* =+ */
+ { 0x0e08, 0x0e08, 0x0e7f, 0x0ef0 }, /* backspace */
+ { 0x0f09, 0x0f00, 0x9400, 0xa5f0 }, /* tab */
+ { 0x1071, 0x1051, 0x1011, 0x1000 }, /* Q */
+ { 0x1177, 0x1157, 0x1117, 0x1100 }, /* W */
+ { 0x1265, 0x1245, 0x1205, 0x1200 }, /* E */
+ { 0x1372, 0x1352, 0x1312, 0x1300 }, /* R */
+ { 0x1474, 0x1454, 0x1414, 0x1400 }, /* T */
+ { 0x1579, 0x1559, 0x1519, 0x1500 }, /* Y */
+ { 0x1675, 0x1655, 0x1615, 0x1600 }, /* U */
+ { 0x1769, 0x1749, 0x1709, 0x1700 }, /* I */
+ { 0x186f, 0x184f, 0x180f, 0x1800 }, /* O */
+ { 0x1970, 0x1950, 0x1910, 0x1900 }, /* P */
+ { 0x1a5b, 0x1a7b, 0x1a1b, 0x1af0 }, /* [{ */
+ { 0x1b5d, 0x1b7d, 0x1b1d, 0x1bf0 }, /* ]} */
+ { 0x1c0d, 0x1c0d, 0x1c0a, 0x1cf0 }, /* Enter */
+ { none, none, none, none }, /* L Ctrl */
+ { 0x1e61, 0x1e41, 0x1e01, 0x1e00 }, /* A */
+ { 0x1f73, 0x1f53, 0x1f13, 0x1f00 }, /* S */
+ { 0x2064, 0x2044, 0x2004, 0x2000 }, /* D */
+ { 0x2166, 0x2146, 0x2106, 0x2100 }, /* F */
+ { 0x2267, 0x2247, 0x2207, 0x2200 }, /* G */
+ { 0x2368, 0x2348, 0x2308, 0x2300 }, /* H */
+ { 0x246a, 0x244a, 0x240a, 0x2400 }, /* J */
+ { 0x256b, 0x254b, 0x250b, 0x2500 }, /* K */
+ { 0x266c, 0x264c, 0x260c, 0x2600 }, /* L */
+ { 0x273b, 0x273a, none, 0x27f0 }, /* ;: */
+ { 0x2827, 0x2822, none, 0x28f0 }, /* '" */
+ { 0x2960, 0x297e, none, 0x29f0 }, /* `~ */
+ { none, none, none, none }, /* L shift */
+ { 0x2b5c, 0x2b7c, 0x2b1c, 0x2bf0 }, /* |\ */
+ { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00 }, /* Z */
+ { 0x2d78, 0x2d58, 0x2d18, 0x2d00 }, /* X */
+ { 0x2e63, 0x2e43, 0x2e03, 0x2e00 }, /* C */
+ { 0x2f76, 0x2f56, 0x2f16, 0x2f00 }, /* V */
+ { 0x3062, 0x3042, 0x3002, 0x3000 }, /* B */
+ { 0x316e, 0x314e, 0x310e, 0x3100 }, /* N */
+ { 0x326d, 0x324d, 0x320d, 0x3200 }, /* M */
+ { 0x332c, 0x333c, none, 0x33f0 }, /* ,< */
+ { 0x342e, 0x343e, none, 0x34f0 }, /* .> */
+ { 0x352f, 0x353f, none, 0x35f0 }, /* /? */
+ { none, none, none, none }, /* R Shift */
+ { 0x372a, 0x372a, 0x9600, 0x37f0 }, /* * */
+ { none, none, none, none }, /* L Alt */
+ { 0x3920, 0x3920, 0x3920, 0x3920 }, /* space */
+ { none, none, none, none }, /* caps lock */
+ { 0x3b00, 0x5400, 0x5e00, 0x6800 }, /* F1 */
+ { 0x3c00, 0x5500, 0x5f00, 0x6900 }, /* F2 */
+ { 0x3d00, 0x5600, 0x6000, 0x6a00 }, /* F3 */
+ { 0x3e00, 0x5700, 0x6100, 0x6b00 }, /* F4 */
+ { 0x3f00, 0x5800, 0x6200, 0x6c00 }, /* F5 */
+ { 0x4000, 0x5900, 0x6300, 0x6d00 }, /* F6 */
+ { 0x4100, 0x5a00, 0x6400, 0x6e00 }, /* F7 */
+ { 0x4200, 0x5b00, 0x6500, 0x6f00 }, /* F8 */
+ { 0x4300, 0x5c00, 0x6600, 0x7000 }, /* F9 */
+ { 0x4400, 0x5d00, 0x6700, 0x7100 }, /* F10 */
+ { none, none, none, none }, /* Num Lock */
+ { none, none, none, none }, /* Scroll Lock */
+ { 0x4700, 0x4737, 0x7700, none }, /* 7 Home */
+ { 0x4800, 0x4838, 0x8d00, none }, /* 8 UP */
+ { 0x4900, 0x4939, 0x8400, none }, /* 9 PgUp */
+ { 0x4a2d, 0x4a2d, 0x8e00, 0x4af0 }, /* - */
+ { 0x4b00, 0x4b34, 0x7300, none }, /* 4 Left */
+ { 0x4c00, 0x4c35, 0x8f00, none }, /* 5 */
+ { 0x4d00, 0x4d36, 0x7400, none }, /* 6 Right */
+ { 0x4e2b, 0x4e2b, 0x9000, 0x4ef0 }, /* + */
+ { 0x4f00, 0x4f31, 0x7500, none }, /* 1 End */
+ { 0x5000, 0x5032, 0x9100, none }, /* 2 Down */
+ { 0x5100, 0x5133, 0x7600, none }, /* 3 PgDn */
+ { 0x5200, 0x5230, 0x9200, none }, /* 0 Ins */
+ { 0x5300, 0x532e, 0x9300, none }, /* Del */
+ { none, none, none, none }, /* SysReq */
+ { none, none, none, none },
+ { 0x565c, 0x567c, none, none }, /* \| */
+ { 0x8500, 0x8700, 0x8900, 0x8b00 }, /* F11 */
+ { 0x8600, 0x8800, 0x8a00, 0x8c00 }, /* F12 */
+};
+
+struct scaninfo key_ext_enter VAR16 = {
+ 0xe00d, 0xe00d, 0xe00a, 0xa600
+};
+struct scaninfo key_ext_slash VAR16 = {
+ 0xe02f, 0xe02f, 0x9500, 0xa400
+};
+
+u16 ascii_to_keycode(u8 ascii)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(scan_to_keycode); i++) {
+ if ((GET_GLOBAL(scan_to_keycode[i].normal) & 0xff) == ascii)
+ return GET_GLOBAL(scan_to_keycode[i].normal);
+ if ((GET_GLOBAL(scan_to_keycode[i].shift) & 0xff) == ascii)
+ return GET_GLOBAL(scan_to_keycode[i].shift);
+ if ((GET_GLOBAL(scan_to_keycode[i].control) & 0xff) == ascii)
+ return GET_GLOBAL(scan_to_keycode[i].control);
+ }
+ return 0;
+}
+
+// Handle a ps2 style scancode read from the keyboard.
+static void
+kbd_set_flag(int key_release, u16 set_bit0, u8 set_bit1, u16 toggle_bit)
+{
+ u16 flags0 = GET_BDA(kbd_flag0);
+ u8 flags1 = GET_BDA(kbd_flag1);
+ if (key_release) {
+ flags0 &= ~set_bit0;
+ flags1 &= ~set_bit1;
+ } else {
+ flags0 ^= toggle_bit;
+ flags0 |= set_bit0;
+ flags1 |= set_bit1;
+ }
+ SET_BDA(kbd_flag0, flags0);
+ SET_BDA(kbd_flag1, flags1);
+}
+
+static void
+kbd_ctrl_break(int key_release)
+{
+ if (!key_release)
+ return;
+ // Clear keyboard buffer and place 0x0000 in buffer
+ u16 buffer_start = GET_BDA(kbd_buf_start_offset);
+ SET_BDA(kbd_buf_head, buffer_start);
+ SET_BDA(kbd_buf_tail, buffer_start+2);
+ SET_FARVAR(SEG_BDA, *(u16*)(buffer_start+0), 0x0000);
+ // Set break flag
+ SET_BDA(break_flag, 0x80);
+ // Generate int 0x1b
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ call16_int(0x1b, &br);
+}
+
+static void
+kbd_sysreq(int key_release)
+{
+ // SysReq generates int 0x15/0x85
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.ah = 0x85;
+ br.al = key_release ? 0x01 : 0x00;
+ br.flags = F_IF;
+ call16_int(0x15, &br);
+}
+
+static void
+kbd_prtscr(int key_release)
+{
+ if (key_release)
+ return;
+ // PrtScr generates int 0x05 (ctrl-prtscr has keycode 0x7200?)
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ call16_int(0x05, &br);
+}
+
+// Handle a ps2 style scancode read from the keyboard.
+static void
+__process_key(u8 scancode)
+{
+ // Check for multi-scancode key sequences
+ u8 flags1 = GET_BDA(kbd_flag1);
+ if (scancode == 0xe0 || scancode == 0xe1) {
+ // Start of two byte extended (e0) or three byte pause key (e1) sequence
+ u8 eflag = scancode == 0xe0 ? KF1_LAST_E0 : KF1_LAST_E1;
+ SET_BDA(kbd_flag1, flags1 | eflag);
+ return;
+ }
+ int key_release = scancode & 0x80;
+ scancode &= ~0x80;
+ if (flags1 & (KF1_LAST_E0|KF1_LAST_E1)) {
+ if (flags1 & KF1_LAST_E1 && scancode == 0x1d)
+ // Ignore second byte of pause key (e1 1d 45 / e1 9d c5)
+ return;
+ // Clear E0/E1 flag in memory for next key event
+ SET_BDA(kbd_flag1, flags1 & ~(KF1_LAST_E0|KF1_LAST_E1));
+ }
+
+ // Check for special keys
+ switch (scancode) {
+ case 0x3a: /* Caps Lock */
+ kbd_set_flag(key_release, KF0_CAPS, 0, KF0_CAPSACTIVE);
+ return;
+ case 0x2a: /* L Shift */
+ if (flags1 & KF1_LAST_E0)
+ // Ignore fake shifts
+ return;
+ kbd_set_flag(key_release, KF0_LSHIFT, 0, 0);
+ return;
+ case 0x36: /* R Shift */
+ if (flags1 & KF1_LAST_E0)
+ // Ignore fake shifts
+ return;
+ kbd_set_flag(key_release, KF0_RSHIFT, 0, 0);
+ return;
+ case 0x1d: /* Ctrl */
+ if (flags1 & KF1_LAST_E0)
+ kbd_set_flag(key_release, KF0_CTRLACTIVE, KF1_RCTRL, 0);
+ else
+ kbd_set_flag(key_release, KF0_CTRLACTIVE | KF0_LCTRL, 0, 0);
+ return;
+ case 0x38: /* Alt */
+ if (flags1 & KF1_LAST_E0)
+ kbd_set_flag(key_release, KF0_ALTACTIVE, KF1_RALT, 0);
+ else
+ kbd_set_flag(key_release, KF0_ALTACTIVE | KF0_LALT, 0, 0);
+ return;
+ case 0x45: /* Num Lock */
+ if (flags1 & KF1_LAST_E1)
+ // XXX - pause key.
+ return;
+ kbd_set_flag(key_release, KF0_NUM, 0, KF0_NUMACTIVE);
+ return;
+ case 0x46: /* Scroll Lock */
+ if (flags1 & KF1_LAST_E0) {
+ kbd_ctrl_break(key_release);
+ return;
+ }
+ kbd_set_flag(key_release, KF0_SCROLL, 0, KF0_SCROLLACTIVE);
+ return;
+
+ case 0x37: /* * */
+ if (flags1 & KF1_LAST_E0) {
+ kbd_prtscr(key_release);
+ return;
+ }
+ break;
+ case 0x54: /* SysReq */
+ kbd_sysreq(key_release);
+ return;
+ case 0x53: /* Del */
+ if ((GET_BDA(kbd_flag0) & (KF0_CTRLACTIVE|KF0_ALTACTIVE))
+ == (KF0_CTRLACTIVE|KF0_ALTACTIVE) && !key_release) {
+ // Ctrl+alt+del - reset machine.
+ SET_BDA(soft_reset_flag, 0x1234);
+ reset();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Handle generic keys
+ if (key_release)
+ // ignore key releases
+ return;
+ if (!scancode || scancode >= ARRAY_SIZE(scan_to_keycode)) {
+ dprintf(1, "__process_key unknown scancode read: 0x%02x!\n", scancode);
+ return;
+ }
+ struct scaninfo *info = &scan_to_keycode[scancode];
+ if (flags1 & KF1_LAST_E0 && (scancode == 0x1c || scancode == 0x35))
+ info = (scancode == 0x1c ? &key_ext_enter : &key_ext_slash);
+ u16 flags0 = GET_BDA(kbd_flag0);
+ u16 keycode;
+ if (flags0 & KF0_ALTACTIVE) {
+ keycode = GET_GLOBAL(info->alt);
+ } else if (flags0 & KF0_CTRLACTIVE) {
+ keycode = GET_GLOBAL(info->control);
+ } else {
+ u8 useshift = flags0 & (KF0_RSHIFT|KF0_LSHIFT) ? 1 : 0;
+ u8 ascii = GET_GLOBAL(info->normal) & 0xff;
+ if ((flags0 & KF0_NUMACTIVE && scancode >= 0x47 && scancode <= 0x53)
+ || (flags0 & KF0_CAPSACTIVE && ascii >= 'a' && ascii <= 'z'))
+ // Numlock/capslock toggles shift on certain keys
+ useshift ^= 1;
+ if (useshift)
+ keycode = GET_GLOBAL(info->shift);
+ else
+ keycode = GET_GLOBAL(info->normal);
+ }
+ if (flags1 & KF1_LAST_E0 && scancode >= 0x47 && scancode <= 0x53) {
+ /* extended keys handling */
+ if (flags0 & KF0_ALTACTIVE)
+ keycode = (scancode + 0x50) << 8;
+ else
+ keycode = (keycode & 0xff00) | 0xe0;
+ }
+ if (keycode)
+ enqueue_key(keycode);
+}
+
+void
+process_key(u8 key)
+{
+ if (!CONFIG_KEYBOARD)
+ return;
+
+ if (CONFIG_KBD_CALL_INT15_4F) {
+ // allow for keyboard intercept
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.eax = (0x4f << 8) | key;
+ br.flags = F_IF|F_CF;
+ call16_int(0x15, &br);
+ if (!(br.flags & F_CF))
+ return;
+ key = br.eax;
+ }
+ __process_key(key);
+}
diff --git a/roms/seabios-hppa/src/list.h b/roms/seabios-hppa/src/list.h
new file mode 100644
index 000000000..94512e306
--- /dev/null
+++ b/roms/seabios-hppa/src/list.h
@@ -0,0 +1,91 @@
+#ifndef __LIST_H
+#define __LIST_H
+
+#include "types.h" // container_of
+
+
+/****************************************************************
+ * hlist - Double linked lists with a single pointer list head
+ ****************************************************************/
+
+struct hlist_node {
+ struct hlist_node *next, **pprev;
+};
+
+struct hlist_head {
+ struct hlist_node *first;
+};
+
+static inline int
+hlist_empty(const struct hlist_head *h)
+{
+ return !h->first;
+}
+
+static inline void
+hlist_del(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+ *pprev = next;
+ if (next)
+ next->pprev = pprev;
+}
+
+static inline void
+hlist_add(struct hlist_node *n, struct hlist_node **pprev)
+{
+ struct hlist_node *next = *pprev;
+ n->pprev = pprev;
+ n->next = next;
+ if (next)
+ next->pprev = &n->next;
+ *pprev = n;
+}
+
+static inline void
+hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+ hlist_add(n, &h->first);
+}
+
+static inline void
+hlist_add_before(struct hlist_node *n, struct hlist_node *next)
+{
+ hlist_add(n, next->pprev);
+}
+
+static inline void
+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) \
+ ; pos = container_of(pos->member.next, typeof(*pos), member))
+
+#define hlist_for_each_entry_safe(pos, n, head, member) \
+ for (pos = container_of((head)->first, typeof(*pos), member) \
+ ; pos != container_of(NULL, typeof(*pos), member) \
+ && ({ n = pos->member.next; 1; }) \
+ ; pos = container_of(n, typeof(*pos), member))
+
+#define hlist_for_each_entry_pprev(pos, pprev, head, member) \
+ for (pprev = &(head)->first \
+ ; *pprev && ({ pos=container_of(*pprev, typeof(*pos), member); 1; }) \
+ ; pprev = &(*pprev)->next)
+
+
+#endif // list.h
diff --git a/roms/seabios-hppa/src/malloc.c b/roms/seabios-hppa/src/malloc.c
new file mode 100644
index 000000000..b840883df
--- /dev/null
+++ b/roms/seabios-hppa/src/malloc.c
@@ -0,0 +1,561 @@
+// Internal dynamic memory allocations.
+//
+// Copyright (C) 2009-2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#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" // PAGE_SIZE
+#include "output.h" // dprintf
+#include "stacks.h" // wait_preempt
+#include "std/optionrom.h" // OPTION_ROM_ALIGN
+#include "string.h" // memset
+
+// Information on a reserved area.
+struct allocinfo_s {
+ struct hlist_node node;
+ u32 range_start, range_end, alloc_size;
+};
+
+// Information on a tracked memory allocation.
+struct allocdetail_s {
+ struct allocinfo_s detailinfo;
+ struct allocinfo_s datainfo;
+ u32 handle;
+};
+
+// The various memory zones.
+struct zone_s {
+ struct hlist_head head;
+};
+
+struct zone_s ZoneLow VARVERIFY32INIT, ZoneHigh VARVERIFY32INIT;
+struct zone_s ZoneFSeg VARVERIFY32INIT;
+struct zone_s ZoneTmpLow VARVERIFY32INIT, ZoneTmpHigh VARVERIFY32INIT;
+
+static struct zone_s *Zones[] VARVERIFY32INIT = {
+ &ZoneTmpLow, &ZoneLow, &ZoneFSeg, &ZoneTmpHigh, &ZoneHigh
+};
+
+
+/****************************************************************
+ * low-level memory reservations
+ ****************************************************************/
+
+// Find and reserve space from a given zone
+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) {
+ 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.
+ fill->range_start = new_range_end;
+ fill->range_end = range_end;
+ fill->alloc_size = size;
+
+ info->range_end = new_range_end;
+ hlist_add_before(&fill->node, &info->node);
+ return new_range_end;
+ }
+ }
+ return 0;
+}
+
+// Reserve space for a 'struct allocdetail_s' and fill
+static struct allocdetail_s *
+alloc_new_detail(struct allocdetail_s *temp)
+{
+ 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
+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->range_start < start)
+ break;
+ }
+
+ // Add space using temporary allocation info.
+ struct allocdetail_s tempdetail;
+ 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 = alloc_new_detail(&tempdetail);
+ if (!detail)
+ hlist_del(&tempdetail.datainfo.node);
+}
+
+// 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 alloc_new()
+static struct allocinfo_s *
+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->range_start == data)
+ return info;
+ }
+ }
+ return NULL;
+}
+
+// Find the lowest memory range added by alloc_add()
+static struct allocinfo_s *
+alloc_find_lowest(struct zone_s *zone)
+{
+ struct allocinfo_s *info, *last = NULL;
+ hlist_for_each_entry(info, &zone->head, node) {
+ last = info;
+ }
+ return last;
+}
+
+
+/****************************************************************
+ * ebda movement
+ ****************************************************************/
+
+// Move ebda
+static int
+relocate_ebda(u32 newebda, u32 oldebda, u8 ebda_size)
+{
+ u32 lowram = GET_BDA(mem_size_kb) * 1024;
+ if (oldebda != lowram)
+ // EBDA isn't at end of ram - give up.
+ return -1;
+
+ // Do copy
+ memmove((void*)newebda, (void*)oldebda, ebda_size * 1024);
+
+ // Update indexes
+ dprintf(1, "ebda moved from %x to %x\n", oldebda, newebda);
+ SET_BDA(mem_size_kb, newebda / 1024);
+ SET_BDA(ebda_seg, FLATPTR_TO_SEG(newebda));
+ return 0;
+}
+
+// Support expanding the ZoneLow dynamically.
+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())) {
+ u32 data = alloc_new(&ZoneLow, size, align, fill);
+ if (data)
+ return data;
+ }
+
+ struct allocinfo_s *info = alloc_find_lowest(&ZoneLow);
+ if (!info)
+ return 0;
+ u32 oldpos = info->range_end;
+ u32 newpos = ALIGN_DOWN(oldpos - size, align);
+ u32 bottom = info->range_start + info->alloc_size;
+ if (newpos >= bottom && newpos <= oldpos)
+ // Space already present.
+ 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);
+ u32 ebda_end = ebda_pos + ebda_size * 1024;
+ if (ebda_end != bottom)
+ // Something else is after ebda - can't use any existing space.
+ newpos = ALIGN_DOWN(ebda_end - size, align);
+ u32 newbottom = ALIGN_DOWN(newpos, 1024);
+ u32 newebda = ALIGN_DOWN(newbottom - ebda_size * 1024, 1024);
+ if (newebda < BUILD_EBDA_MINIMUM)
+ // Not enough space.
+ return 0;
+
+ // Move ebda
+ int ret = relocate_ebda(newebda, ebda_pos, ebda_size);
+ if (ret)
+ return 0;
+
+ // Update zone
+ if (ebda_end == bottom)
+ info->range_start = newbottom;
+ else
+ alloc_add(&ZoneLow, newbottom, ebda_end);
+
+ return alloc_new(&ZoneLow, size, align, fill);
+}
+
+
+/****************************************************************
+ * tracked memory allocations
+ ****************************************************************/
+
+// Allocate physical memory from the given zone and track it as a PMM allocation
+unsigned long
+malloc_palloc(struct zone_s *zone, u32 size, u32 align)
+{
+ ASSERT32FLAT();
+ if (!size)
+ return 0;
+
+ // Find and reserve space for main allocation
+ 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, &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, "phys_alloc zone=%p size=%d align=%x ret=%x (detail=%p)\n"
+ , zone, size, align, data, detail);
+
+ return data;
+}
+
+// Allocate virtual memory from the given zone
+void * __malloc
+x86_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
+malloc_pfree(u32 data)
+{
+ ASSERT32FLAT();
+ 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, "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)
+{
+ // XXX - doesn't account for ZoneLow being able to grow.
+ // XXX - results not reliable when CONFIG_THREAD_OPTIONROMS
+ u32 maxspace = 0;
+ struct allocinfo_s *info;
+ hlist_for_each_entry(info, &zone->head, node) {
+ u32 space = info->range_end - info->range_start - info->alloc_size;
+ if (space > maxspace)
+ maxspace = space;
+ }
+
+ if (zone != &ZoneTmpHigh && zone != &ZoneTmpLow)
+ return maxspace;
+ // Account for space needed for PMM tracking.
+ u32 reserve = ALIGN(sizeof(struct allocdetail_s), MALLOC_MIN_ALIGN);
+ if (maxspace <= reserve)
+ return 0;
+ return maxspace - reserve;
+}
+
+// Set a handle associated with an allocation.
+void
+malloc_sethandle(u32 data, u32 handle)
+{
+ ASSERT32FLAT();
+ 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 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->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.range_start;
+ }
+ }
+ return 0;
+}
+
+
+/****************************************************************
+ * 0xc0000-0xf0000 management
+ ****************************************************************/
+
+static u32 RomEnd = BUILD_ROM_START;
+static struct allocinfo_s *RomBase;
+
+#define OPROM_HEADER_RESERVE 16
+
+// Return the maximum memory position option roms may use.
+u32
+rom_get_max(void)
+{
+ if (CONFIG_MALLOC_UPPERMEMORY)
+ return ALIGN_DOWN(RomBase->range_end - OPROM_HEADER_RESERVE
+ , OPTION_ROM_ALIGN);
+ return SYMBOL(final_readonly_start);
+}
+
+// Return the end of the last deployed option rom.
+u32
+rom_get_last(void)
+{
+ return RomEnd;
+}
+
+// Request space for an optionrom in 0xc0000-0xf0000 area.
+struct rom_header *
+rom_reserve(u32 size)
+{
+ u32 newend = ALIGN(RomEnd + size, OPTION_ROM_ALIGN);
+ if (newend > rom_get_max())
+ return NULL;
+ if (CONFIG_MALLOC_UPPERMEMORY) {
+ if (newend < SYMBOL(zonelow_base))
+ newend = SYMBOL(zonelow_base);
+ RomBase->range_start = newend + OPROM_HEADER_RESERVE;
+ }
+ return (void*)RomEnd;
+}
+
+// Confirm space as in use by an optionrom.
+int
+rom_confirm(u32 size)
+{
+ void *new = rom_reserve(size);
+ if (!new) {
+ warn_noalloc();
+ return -1;
+ }
+ RomEnd = ALIGN(RomEnd + size, OPTION_ROM_ALIGN);
+ return 0;
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+void
+malloc_preinit(void)
+{
+ ASSERT32FLAT();
+ dprintf(3, "malloc preinit\n");
+
+ // Don't declare any memory between 0xa0000 and 0x100000
+ e820_remove(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END);
+
+ // Mark known areas as reserved.
+ e820_add(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED);
+
+ // Populate temp high ram
+ u32 highram = 0;
+ int i;
+ for (i=e820_count-1; i>=0; i--) {
+ struct e820entry *en = &e820_list[i];
+ u64 end = en->start + en->size;
+ if (end < 1024*1024)
+ break;
+ if (en->type != E820_RAM || end > 0xffffffff)
+ continue;
+ u32 s = en->start, e = end;
+ if (!highram) {
+ u32 newe = ALIGN_DOWN(e - BUILD_MAX_HIGHTABLE, MALLOC_MIN_ALIGN);
+ if (newe <= e && newe >= s) {
+ highram = newe;
+ e = newe;
+ }
+ }
+ alloc_add(&ZoneTmpHigh, s, e);
+ }
+
+ // Populate regions
+ alloc_add(&ZoneTmpLow, BUILD_STACK_ADDR, BUILD_EBDA_MINIMUM);
+ if (highram) {
+ alloc_add(&ZoneHigh, highram, highram + BUILD_MAX_HIGHTABLE);
+ e820_add(highram, BUILD_MAX_HIGHTABLE, E820_RESERVED);
+ }
+}
+
+void
+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) {
+ 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 {
+ alloc_add(&ZoneTmpHigh, hi_pmm, hi_pmm + hi_pmm_size);
+ }
+ alloc_add(&ZoneTmpLow, low_pmm, low_pmm + low_pmm_size);
+}
+
+u32 LegacyRamSize VARFSEG;
+
+// Calculate the maximum ramsize (less than 4gig) from e820 map.
+static void
+calcRamSize(void)
+{
+ u32 rs = 0;
+ int i;
+ for (i=e820_count-1; i>=0; i--) {
+ struct e820entry *en = &e820_list[i];
+ u64 end = en->start + en->size;
+ u32 type = en->type;
+ if (end <= 0xffffffff && (type == E820_ACPI || type == E820_RAM)) {
+ rs = end;
+ break;
+ }
+ }
+ LegacyRamSize = rs >= 1024*1024 ? rs : 1024*1024;
+}
+
+// Update pointers after code relocation.
+void
+malloc_init(void)
+{
+ ASSERT32FLAT();
+ dprintf(3, "malloc init\n");
+
+ if (CONFIG_RELOCATE_INIT) {
+ // Fixup malloc pointers after relocation
+ int i;
+ for (i=0; i<ARRAY_SIZE(Zones); i++) {
+ struct zone_s *zone = Zones[i];
+ if (zone->head.first)
+ zone->head.first->pprev = &zone->head.first;
+ }
+ }
+
+ // Initialize low-memory region
+ memmove(VSYMBOL(final_varlow_start), VSYMBOL(varlow_start)
+ , SYMBOL(varlow_end) - SYMBOL(varlow_start));
+ if (CONFIG_MALLOC_UPPERMEMORY) {
+ alloc_add(&ZoneLow, SYMBOL(zonelow_base) + OPROM_HEADER_RESERVE
+ , SYMBOL(final_varlow_start));
+ RomBase = alloc_find_lowest(&ZoneLow);
+ } else {
+ alloc_add(&ZoneLow, ALIGN_DOWN(SYMBOL(final_varlow_start), 1024)
+ , SYMBOL(final_varlow_start));
+ }
+
+ // Add space available in f-segment to ZoneFSeg
+ memset(VSYMBOL(zonefseg_start), 0
+ , SYMBOL(zonefseg_end) - SYMBOL(zonefseg_start));
+ alloc_add(&ZoneFSeg, SYMBOL(zonefseg_start), SYMBOL(zonefseg_end));
+
+ calcRamSize();
+}
+
+void
+malloc_prepboot(void)
+{
+ ASSERT32FLAT();
+ dprintf(3, "malloc finalize\n");
+
+ u32 base = rom_get_max();
+ memset((void*)RomEnd, 0, base-RomEnd);
+ if (CONFIG_MALLOC_UPPERMEMORY) {
+ // Place an optionrom signature around used low mem area.
+ struct rom_header *dummyrom = (void*)base;
+ dummyrom->signature = OPTION_ROM_SIGNATURE;
+ int size = (BUILD_BIOS_ADDR - base) / 512;
+ dummyrom->size = (size > 255) ? 255 : size;
+ }
+
+ // Reserve more low-mem if needed.
+ u32 endlow = GET_BDA(mem_size_kb)*1024;
+ e820_add(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED);
+
+ // Clear unused f-seg ram.
+ 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, info->range_start, info->range_end);
+
+ // Give back unused high ram.
+ info = alloc_find_lowest(&ZoneHigh);
+ if (info) {
+ 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);
+ }
+
+ calcRamSize();
+}
diff --git a/roms/seabios-hppa/src/malloc.h b/roms/seabios-hppa/src/malloc.h
new file mode 100644
index 000000000..73962b40f
--- /dev/null
+++ b/roms/seabios-hppa/src/malloc.h
@@ -0,0 +1,74 @@
+#ifndef __MALLOC_H
+#define __MALLOC_H
+
+#include "autoconf.h" // CONFIG_*
+#include "types.h" // u32
+
+// malloc.c
+extern struct zone_s ZoneLow, ZoneHigh, ZoneFSeg, ZoneTmpLow, ZoneTmpHigh;
+u32 rom_get_max(void);
+u32 rom_get_last(void);
+struct rom_header *rom_reserve(u32 size);
+int rom_confirm(u32 size);
+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);
+unsigned long malloc_palloc(struct zone_s *zone, u32 size, u32 align);
+void *parisc_malloc(u32 size, u32 align);
+void *x86_malloc(struct zone_s *zone, u32 size, u32 align);
+#define _malloc(zone, size, align) \
+ (CONFIG_X86 ? x86_malloc(zone, size, align) : parisc_malloc(size, align))
+int malloc_pfree(u32 data);
+void free(void *data);
+u32 malloc_getspace(struct zone_s *zone);
+void malloc_sethandle(u32 data, u32 handle);
+u32 malloc_findhandle(u32 handle);
+
+#define MALLOC_DEFAULT_HANDLE 0xFFFFFFFF
+// Minimum alignment of malloc'd memory
+#define MALLOC_MIN_ALIGN 16
+// Helper functions for memory allocation.
+static inline void *malloc_low(u32 size) {
+ return _malloc(&ZoneLow, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_high(u32 size) {
+ return _malloc(&ZoneHigh, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_fseg(u32 size) {
+ return _malloc(&ZoneFSeg, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_tmplow(u32 size) {
+ return _malloc(&ZoneTmpLow, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_tmphigh(u32 size) {
+ return _malloc(&ZoneTmpHigh, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_tmp(u32 size) {
+ void *ret = malloc_tmphigh(size);
+ if (ret)
+ return ret;
+ return malloc_tmplow(size);
+}
+static inline void *memalign_low(u32 align, u32 size) {
+ return _malloc(&ZoneLow, size, align);
+}
+static inline void *memalign_high(u32 align, u32 size) {
+ return _malloc(&ZoneHigh, size, align);
+}
+static inline void *memalign_tmplow(u32 align, u32 size) {
+ return _malloc(&ZoneTmpLow, size, align);
+}
+static inline void *memalign_tmphigh(u32 align, u32 size) {
+ return _malloc(&ZoneTmpHigh, size, align);
+}
+static inline void *memalign_tmp(u32 align, u32 size) {
+ void *ret = memalign_tmphigh(align, size);
+ if (ret)
+ return ret;
+ return memalign_tmplow(align, size);
+}
+
+#endif // malloc.h
diff --git a/roms/seabios-hppa/src/memmap.h b/roms/seabios-hppa/src/memmap.h
new file mode 100644
index 000000000..22bd4bcb8
--- /dev/null
+++ b/roms/seabios-hppa/src/memmap.h
@@ -0,0 +1,21 @@
+#ifndef __MEMMAP_H
+#define __MEMMAP_H
+
+#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;
+}
+
+// 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 // memmap.h
diff --git a/roms/seabios-hppa/src/misc.c b/roms/seabios-hppa/src/misc.c
new file mode 100644
index 000000000..b51173043
--- /dev/null
+++ b/roms/seabios-hppa/src/misc.c
@@ -0,0 +1,195 @@
+// Code for misc 16bit handlers and variables.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_BDA
+#include "bregs.h" // struct bregs
+#include "hw/pic.h" // enable_hwirq
+#include "output.h" // debug_enter
+#include "stacks.h" // call16_int
+#include "string.h" // memset
+
+#define PORT_MATH_CLEAR 0x00f0
+
+// Indicator if POST phase has been started (and if it has completed).
+int HaveRunPost VARFSEG;
+
+int
+in_post(void)
+{
+ return GET_GLOBAL(HaveRunPost) == 1;
+}
+
+
+/****************************************************************
+ * Misc 16bit ISRs
+ ****************************************************************/
+
+// INT 12h Memory Size Service Entry Point
+void VISIBLE16
+handle_12(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_12);
+ regs->ax = GET_BDA(mem_size_kb);
+}
+
+// INT 11h Equipment List Service Entry Point
+void VISIBLE16
+handle_11(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_11);
+ regs->ax = GET_BDA(equipment_list_flags);
+}
+
+// INT 05h Print Screen Service Entry Point
+void VISIBLE16
+handle_05(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_05);
+}
+
+// NMI handler
+void VISIBLE16
+handle_02(void)
+{
+ debug_isr(DEBUG_ISR_02);
+}
+
+void
+mathcp_setup(void)
+{
+ dprintf(3, "math cp init\n");
+ // 80x87 coprocessor installed
+ set_equipment_flags(0x02, 0x02);
+ enable_hwirq(13, FUNC16(entry_75));
+}
+
+// INT 75 - IRQ13 - MATH COPROCESSOR EXCEPTION
+void VISIBLE16
+handle_75(void)
+{
+ debug_isr(DEBUG_ISR_75);
+
+ // clear irq13
+ outb(0, PORT_MATH_CLEAR);
+ // clear interrupt
+ pic_eoi2();
+ // legacy nmi call
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ call16_int(0x02, &br);
+}
+
+
+/****************************************************************
+ * BIOS_CONFIG_TABLE
+ ****************************************************************/
+
+// DMA channel 3 used by hard disk BIOS
+#define CBT_F1_DMA3USED (1<<7)
+// 2nd interrupt controller (8259) installed
+#define CBT_F1_2NDPIC (1<<6)
+// Real-Time Clock installed
+#define CBT_F1_RTC (1<<5)
+// INT 15/AH=4Fh called upon INT 09h
+#define CBT_F1_INT154F (1<<4)
+// wait for external event (INT 15/AH=41h) supported
+#define CBT_F1_WAITEXT (1<<3)
+// extended BIOS area allocated (usually at top of RAM)
+#define CBT_F1_EBDA (1<<2)
+// bus is Micro Channel instead of ISA
+#define CBT_F1_MCA (1<<1)
+// system has dual bus (Micro Channel + ISA)
+#define CBT_F1_MCAISA (1<<0)
+
+// INT 16/AH=09h (keyboard functionality) supported
+#define CBT_F2_INT1609 (1<<6)
+
+struct bios_config_table_s BIOS_CONFIG_TABLE VARFSEGFIXED(0xe6f5) = {
+ .size = sizeof(BIOS_CONFIG_TABLE) - 2,
+ .model = BUILD_MODEL_ID,
+ .submodel = BUILD_SUBMODEL_ID,
+ .biosrev = BUILD_BIOS_REVISION,
+ .feature1 = (
+ CBT_F1_2NDPIC | CBT_F1_RTC | CBT_F1_EBDA
+ | (CONFIG_KBD_CALL_INT15_4F ? CBT_F1_INT154F : 0)),
+ .feature2 = CBT_F2_INT1609,
+ .feature3 = 0,
+ .feature4 = 0,
+ .feature5 = 0,
+};
+
+
+/****************************************************************
+ * GDT and IDT tables
+ ****************************************************************/
+
+// Real mode IDT descriptor
+struct descloc_s rmode_IDT_info VARFSEG = {
+ .length = sizeof(struct rmode_IVT) - 1,
+ .addr = (u32)MAKE_FLATPTR(SEG_IVT, 0),
+};
+
+// Dummy IDT that forces a machine shutdown if an irq happens in
+// protected mode.
+u8 dummy_IDT VARFSEG;
+
+// Protected mode IDT descriptor
+struct descloc_s pmode_IDT_info VARFSEG = {
+ .length = sizeof(dummy_IDT) - 1,
+ .addr = (u32)&dummy_IDT,
+};
+
+// GDT
+u64 rombios32_gdt[] VARFSEG __aligned(8) = {
+ // First entry can't be used.
+ 0x0000000000000000LL,
+ // 32 bit flat code segment (SEG32_MODE32_CS)
+ GDT_GRANLIMIT(0xffffffff) | GDT_CODE | GDT_B,
+ // 32 bit flat data segment (SEG32_MODE32_DS)
+ GDT_GRANLIMIT(0xffffffff) | GDT_DATA | GDT_B,
+ // 16 bit code segment base=0xf0000 limit=0xffff (SEG32_MODE16_CS)
+ GDT_LIMIT(BUILD_BIOS_SIZE-1) | GDT_CODE | GDT_BASE(BUILD_BIOS_ADDR),
+ // 16 bit data segment base=0x0 limit=0xffff (SEG32_MODE16_DS)
+ GDT_LIMIT(0x0ffff) | GDT_DATA,
+ // 16 bit code segment base=0xf0000 limit=0xffffffff (SEG32_MODE16BIG_CS)
+ GDT_GRANLIMIT(0xffffffff) | GDT_CODE | GDT_BASE(BUILD_BIOS_ADDR),
+ // 16 bit data segment base=0 limit=0xffffffff (SEG32_MODE16BIG_DS)
+ GDT_GRANLIMIT(0xffffffff) | GDT_DATA,
+};
+
+// GDT descriptor
+struct descloc_s rombios32_gdt_48 VARFSEG = {
+ .length = sizeof(rombios32_gdt) - 1,
+ .addr = (u32)rombios32_gdt,
+};
+
+
+/****************************************************************
+ * Misc fixed vars
+ ****************************************************************/
+
+// BIOS build date
+char BiosDate[] VARFSEGFIXED(0xfff5) = "06/23/99";
+
+u8 BiosModelId VARFSEGFIXED(0xfffe) = BUILD_MODEL_ID;
+
+u8 BiosChecksum VARFSEGFIXED(0xffff);
+
+struct floppy_dbt_s diskette_param_table VARFSEGFIXED(0xefc7);
+
+// Old Fixed Disk Parameter Table (newer tables are in the ebda).
+struct fdpt_s OldFDPT VARFSEGFIXED(0xe401);
+
+// XXX - Baud Rate Generator Table
+u8 BaudTable[16] VARFSEGFIXED(0xe729);
+
+// XXX - Initial Interrupt Vector Offsets Loaded by POST
+u8 InitVectors[13] VARFSEGFIXED(0xfef3);
+
+// XXX - INT 1D - SYSTEM DATA - VIDEO PARAMETER TABLES
+u8 VideoParams[88] VARFSEGFIXED(0xf0a4);
diff --git a/roms/seabios-hppa/src/mouse.c b/roms/seabios-hppa/src/mouse.c
new file mode 100644
index 000000000..b7ad7c62a
--- /dev/null
+++ b/roms/seabios-hppa/src/mouse.c
@@ -0,0 +1,342 @@
+// 16bit code to handle mouse events.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_EBDA
+#include "bregs.h" // struct bregs
+#include "hw/ps2port.h" // ps2_mouse_command
+#include "hw/usb-hid.h" // usb_mouse_command
+#include "output.h" // dprintf
+#include "stacks.h" // stack_hop_back
+#include "util.h" // mouse_init
+
+void
+mouse_init(void)
+{
+ if (! CONFIG_MOUSE)
+ return;
+ dprintf(3, "init mouse\n");
+ // pointing device installed
+ set_equipment_flags(0x04, 0x04);
+}
+
+static int
+mouse_command(int command, u8 *param)
+{
+ if (usb_mouse_active())
+ return usb_mouse_command(command, param);
+ return ps2_mouse_command(command, param);
+}
+
+#define RET_SUCCESS 0x00
+#define RET_EINVFUNCTION 0x01
+#define RET_EINVINPUT 0x02
+#define RET_EINTERFACE 0x03
+#define RET_ENEEDRESEND 0x04
+#define RET_ENOHANDLER 0x05
+
+// Disable Mouse
+static void
+mouse_15c20000(struct bregs *regs)
+{
+ int ret = mouse_command(PSMOUSE_CMD_DISABLE, NULL);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
+}
+
+// Enable Mouse
+static void
+mouse_15c20001(struct bregs *regs)
+{
+ u16 ebda_seg = get_ebda_seg();
+ u8 mouse_flags_2 = GET_EBDA(ebda_seg, mouse_flag2);
+ if ((mouse_flags_2 & 0x80) == 0) {
+ set_code_invalid(regs, RET_ENOHANDLER);
+ return;
+ }
+
+ int ret = mouse_command(PSMOUSE_CMD_ENABLE, NULL);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
+}
+
+static void
+mouse_15c200XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EINVFUNCTION);
+}
+
+// Disable/Enable Mouse
+static void
+mouse_15c200(struct bregs *regs)
+{
+ switch (regs->bh) {
+ case 0x00: mouse_15c20000(regs); break;
+ case 0x01: mouse_15c20001(regs); break;
+ default: mouse_15c200XX(regs); break;
+ }
+}
+
+// Reset Mouse
+static void
+mouse_15c201(struct bregs *regs)
+{
+ u8 param[2];
+ int ret = mouse_command(PSMOUSE_CMD_RESET_BAT, param);
+ if (ret) {
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ return;
+ }
+ regs->bl = param[0];
+ regs->bh = param[1];
+ set_code_success(regs);
+}
+
+// Set Sample Rate
+static void
+mouse_15c202(struct bregs *regs)
+{
+ static u8 VAR16 sample_rates[7] = {10, 20, 40, 60, 80, 100, 200};
+ if (regs->bh >= ARRAY_SIZE(sample_rates)) {
+ set_code_invalid(regs, RET_EINVINPUT);
+ return;
+ }
+ u8 mouse_data1 = GET_GLOBAL(sample_rates[regs->bh]);
+ int ret = mouse_command(PSMOUSE_CMD_SETRATE, &mouse_data1);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
+}
+
+// Set Resolution
+static void
+mouse_15c203(struct bregs *regs)
+{
+ // BH:
+ // 0 = 25 dpi, 1 count per millimeter
+ // 1 = 50 dpi, 2 counts per millimeter
+ // 2 = 100 dpi, 4 counts per millimeter
+ // 3 = 200 dpi, 8 counts per millimeter
+ if (regs->bh >= 4) {
+ set_code_invalid(regs, RET_EINVINPUT);
+ return;
+ }
+ u8 param = regs->bh;
+ int ret = mouse_command(PSMOUSE_CMD_SETRES, &param);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
+}
+
+// Get Device ID
+static void
+mouse_15c204(struct bregs *regs)
+{
+ u8 param[2];
+ int ret = mouse_command(PSMOUSE_CMD_GETID, param);
+ if (ret) {
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ return;
+ }
+ regs->bh = param[0];
+ set_code_success(regs);
+}
+
+// Initialize Mouse
+static void
+mouse_15c205(struct bregs *regs)
+{
+ if (regs->bh != 3) {
+ set_code_invalid(regs, RET_EINTERFACE);
+ return;
+ }
+ u16 ebda_seg = get_ebda_seg();
+ SET_EBDA(ebda_seg, mouse_flag1, 0x00);
+ SET_EBDA(ebda_seg, mouse_flag2, regs->bh);
+
+ // Reset Mouse
+ mouse_15c201(regs);
+}
+
+// Return Status
+static void
+mouse_15c20600(struct bregs *regs)
+{
+ u8 param[3];
+ int ret = mouse_command(PSMOUSE_CMD_GETINFO, param);
+ if (ret) {
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ return;
+ }
+ regs->bl = param[0];
+ regs->cl = param[1];
+ regs->dl = param[2];
+ set_code_success(regs);
+}
+
+// Set Scaling Factor to 1:1
+static void
+mouse_15c20601(struct bregs *regs)
+{
+ int ret = mouse_command(PSMOUSE_CMD_SETSCALE11, NULL);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
+}
+
+// Set Scaling Factor to 2:1
+static void
+mouse_15c20602(struct bregs *regs)
+{
+ int ret = mouse_command(PSMOUSE_CMD_SETSCALE21, NULL);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
+}
+
+static void
+mouse_15c206XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EINVFUNCTION);
+}
+
+// Return Status & Set Scaling Factor...
+static void
+mouse_15c206(struct bregs *regs)
+{
+ switch (regs->bh) {
+ case 0x00: mouse_15c20600(regs); break;
+ case 0x01: mouse_15c20601(regs); break;
+ case 0x02: mouse_15c20602(regs); break;
+ default: mouse_15c206XX(regs); break;
+ }
+}
+
+// Set Mouse Handler Address
+static void
+mouse_15c207(struct bregs *regs)
+{
+ struct segoff_s farptr = SEGOFF(regs->es, regs->bx);
+ u16 ebda_seg = get_ebda_seg();
+ u8 mouse_flags_2 = GET_EBDA(ebda_seg, mouse_flag2);
+ if (! farptr.segoff) {
+ /* remove handler */
+ if ((mouse_flags_2 & 0x80) != 0) {
+ mouse_flags_2 &= ~0x80;
+ mouse_command(PSMOUSE_CMD_DISABLE, NULL);
+ }
+ } else {
+ /* install handler */
+ mouse_flags_2 |= 0x80;
+ }
+ SET_EBDA(ebda_seg, mouse_flag2, mouse_flags_2);
+ SET_EBDA(ebda_seg, far_call_pointer, farptr);
+ set_code_success(regs);
+}
+
+static void
+mouse_15c2XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EINVFUNCTION);
+}
+
+void
+handle_15c2(struct bregs *regs)
+{
+ //debug_stub(regs);
+
+ if (! CONFIG_MOUSE) {
+ set_code_invalid(regs, RET_EUNSUPPORTED);
+ return;
+ }
+
+ switch (regs->al) {
+ case 0x00: mouse_15c200(regs); break;
+ case 0x01: mouse_15c201(regs); break;
+ case 0x02: mouse_15c202(regs); break;
+ case 0x03: mouse_15c203(regs); break;
+ case 0x04: mouse_15c204(regs); break;
+ case 0x05: mouse_15c205(regs); break;
+ case 0x06: mouse_15c206(regs); break;
+ case 0x07: mouse_15c207(regs); break;
+ default: mouse_15c2XX(regs); break;
+ }
+}
+
+void VISIBLE16
+invoke_mouse_handler(void)
+{
+ if (!CONFIG_MOUSE)
+ return;
+ if (need_hop_back()) {
+ stack_hop_back(invoke_mouse_handler, 0, 0);
+ return;
+ }
+ ASSERT16();
+ u16 ebda_seg = get_ebda_seg();
+ u16 status = GET_EBDA(ebda_seg, mouse_data[0]);
+ u16 X = GET_EBDA(ebda_seg, mouse_data[1]);
+ u16 Y = GET_EBDA(ebda_seg, mouse_data[2]);
+
+ struct segoff_s func = GET_EBDA(ebda_seg, far_call_pointer);
+ dprintf(16, "mouse farcall s=%04x x=%04x y=%04x func=%04x:%04x\n"
+ , status, X, Y, func.seg, func.offset);
+
+ asm volatile(
+ "pushl %%ebp\n"
+ "sti\n"
+
+ "pushl %0\n"
+ "pushw %w1\n" // status
+ "pushw %w2\n" // X
+ "pushw %w3\n" // Y
+ "pushw $0\n" // Z
+ "lcallw *8(%%esp)\n"
+ "addl $12, %%esp\n"
+
+ "cli\n"
+ "cld\n"
+ "popl %%ebp"
+ : "+a"(func.segoff), "+c"(status), "+d"(X), "+b"(Y)
+ :
+ : "edi", "esi", "cc", "memory");
+}
+
+void
+process_mouse(u8 data)
+{
+ if (!CONFIG_MOUSE)
+ return;
+
+ u16 ebda_seg = get_ebda_seg();
+ u8 mouse_flags_1 = GET_EBDA(ebda_seg, mouse_flag1);
+ u8 mouse_flags_2 = GET_EBDA(ebda_seg, mouse_flag2);
+
+ if (! (mouse_flags_2 & 0x80))
+ // far call handler not installed
+ return;
+
+ u8 package_count = mouse_flags_2 & 0x07;
+ u8 index = mouse_flags_1 & 0x07;
+ SET_EBDA(ebda_seg, mouse_data[index], data);
+
+ if ((index+1) < package_count) {
+ mouse_flags_1++;
+ SET_EBDA(ebda_seg, mouse_flag1, mouse_flags_1);
+ return;
+ }
+
+ SET_EBDA(ebda_seg, mouse_flag1, 0);
+ invoke_mouse_handler();
+}
diff --git a/roms/seabios-hppa/src/optionroms.c b/roms/seabios-hppa/src/optionroms.c
new file mode 100644
index 000000000..e906ab97f
--- /dev/null
+++ b/roms/seabios-hppa/src/optionroms.c
@@ -0,0 +1,499 @@
+// Option rom scanning code.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "bregs.h" // struct bregs
+#include "config.h" // CONFIG_*
+#include "farptr.h" // FLATPTR_TO_SEG
+#include "biosvar.h" // GET_IVT
+#include "hw/pci.h" // pci_config_readl
+#include "hw/pcidevice.h" // foreachpci
+#include "hw/pci_ids.h" // PCI_CLASS_DISPLAY_VGA
+#include "hw/pci_regs.h" // PCI_ROM_ADDRESS
+#include "malloc.h" // rom_confirm
+#include "output.h" // dprintf
+#include "romfile.h" // romfile_loadint
+#include "stacks.h" // farcall16big
+#include "std/optionrom.h" // struct rom_header
+#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;
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Execute a given option rom.
+static void
+__callrom(struct rom_header *rom, u16 offset, u16 bdf)
+{
+ u16 seg = FLATPTR_TO_SEG(rom);
+ dprintf(1, "Running option rom at %04x:%04x\n", seg, offset);
+
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ br.ax = bdf;
+ br.bx = 0xffff;
+ br.dx = 0xffff;
+ br.es = SEG_BIOS;
+ br.di = get_pnp_offset();
+ br.code = SEGOFF(seg, offset);
+ start_preempt();
+ farcall16big(&br);
+ finish_preempt();
+}
+
+// Execute a given option rom at the standard entry vector.
+void
+callrom(struct rom_header *rom, u16 bdf)
+{
+ __callrom(rom, OPTION_ROM_INITVECTOR, bdf);
+}
+
+// Execute a BCV option rom registered via add_bcv().
+void
+call_bcv(u16 seg, u16 ip)
+{
+ __callrom(MAKE_FLATPTR(seg, 0), ip, 0);
+}
+
+// Verify that an option rom looks valid
+static int
+is_valid_rom(struct rom_header *rom)
+{
+ dprintf(6, "Checking rom %p (sig %x size %d)\n"
+ , rom, rom->signature, rom->size);
+ if (rom->signature != OPTION_ROM_SIGNATURE)
+ return 0;
+ if (! rom->size)
+ return 0;
+ u32 len = rom->size * 512;
+ u8 sum = checksum(rom, len);
+ if (sum != 0) {
+ dprintf(1, "Found option rom with bad checksum: loc=%p len=%d sum=%x\n"
+ , rom, len, sum);
+ if (EnforceChecksum)
+ return 0;
+ }
+ return 1;
+}
+
+// Check if a valid option rom has a pnp struct; return it if so.
+static struct pnp_data *
+get_pnp_rom(struct rom_header *rom)
+{
+ struct pnp_data *pnp = (void*)((u8*)rom + rom->pnpoffset);
+ if (pnp->signature != PNP_SIGNATURE)
+ return NULL;
+ return pnp;
+}
+
+// Check for multiple pnp option rom headers.
+static struct pnp_data *
+get_pnp_next(struct rom_header *rom, struct pnp_data *pnp)
+{
+ if (! pnp->nextoffset)
+ return NULL;
+ pnp = (void*)((u8*)rom + pnp->nextoffset);
+ if (pnp->signature != PNP_SIGNATURE)
+ return NULL;
+ return pnp;
+}
+
+// Check if a valid option rom has a pci struct; return it if so.
+static struct pci_data *
+get_pci_rom(struct rom_header *rom)
+{
+ struct pci_data *pd = (void*)((u32)rom + rom->pcioffset);
+ if (pd->signature != PCI_ROM_SIGNATURE)
+ return NULL;
+ if (rom->pcioffset & 3)
+ dprintf(1, "WARNING! Found unaligned PCI rom (vd=%04x:%04x)\n"
+ , pd->vendor, pd->device);
+ return pd;
+}
+
+// Run rom init code and note rom size.
+static int
+init_optionrom(struct rom_header *rom, u16 bdf, int isvga)
+{
+ if (! is_valid_rom(rom))
+ return -1;
+ struct rom_header *newrom = rom_reserve(rom->size * 512);
+ if (!newrom) {
+ warn_noalloc();
+ return -1;
+ }
+ 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);
+
+ return rom_confirm(newrom->size * 512);
+}
+
+#define RS_PCIROM (1LL<<33)
+
+static void
+setRomSource(u64 *sources, struct rom_header *rom, u64 source)
+{
+ if (sources)
+ sources[((u32)rom - BUILD_ROM_START) / OPTION_ROM_ALIGN] = source;
+}
+
+static int
+getRomPriority(u64 *sources, struct rom_header *rom, int instance)
+{
+ u64 source = sources[((u32)rom - BUILD_ROM_START) / OPTION_ROM_ALIGN];
+ if (!source)
+ return -1;
+ if (source & RS_PCIROM)
+ return bootprio_find_pci_rom((void*)(u32)source, instance);
+ struct romfile_s *file = (void*)(u32)source;
+ return bootprio_find_named_rom(file->name, instance);
+}
+
+
+/****************************************************************
+ * Roms in CBFS
+ ****************************************************************/
+
+static struct rom_header *
+deploy_romfile(struct romfile_s *file)
+{
+ u32 size = file->size;
+ struct rom_header *rom = rom_reserve(size);
+ if (!rom) {
+ warn_noalloc();
+ return NULL;
+ }
+ int ret = file->copy(file, rom, size);
+ if (ret <= 0)
+ return NULL;
+ return rom;
+}
+
+// Run all roms in a given CBFS directory.
+static void
+run_file_roms(const char *prefix, int isvga, u64 *sources)
+{
+ struct romfile_s *file = NULL;
+ for (;;) {
+ file = romfile_findprefix(prefix, file);
+ if (!file)
+ break;
+ struct rom_header *rom = deploy_romfile(file);
+ if (rom) {
+ setRomSource(sources, rom, (u32)file);
+ init_optionrom(rom, 0, isvga);
+ }
+ }
+}
+
+
+/****************************************************************
+ * PCI roms
+ ****************************************************************/
+
+// Verify device is a vga device with legacy address decoding enabled.
+int
+is_pci_vga(struct pci_device *pci)
+{
+ if (pci->class != PCI_CLASS_DISPLAY_VGA)
+ return 0;
+ u16 cmd = pci_config_readw(pci->bdf, PCI_COMMAND);
+ if (!(cmd & PCI_COMMAND_IO && cmd & PCI_COMMAND_MEMORY))
+ return 0;
+ while (pci->parent) {
+ pci = pci->parent;
+ u32 ctrl = pci_config_readb(pci->bdf, PCI_BRIDGE_CONTROL);
+ if (!(ctrl & PCI_BRIDGE_CTL_VGA))
+ return 0;
+ }
+ return 1;
+}
+
+// Copy a rom to its permanent location below 1MiB
+static struct rom_header *
+copy_rom(struct rom_header *rom)
+{
+ u32 romsize = rom->size * 512;
+ struct rom_header *newrom = rom_reserve(romsize);
+ if (!newrom) {
+ warn_noalloc();
+ return NULL;
+ }
+ dprintf(4, "Copying option rom (size %d) from %p to %p\n"
+ , romsize, rom, newrom);
+ iomemcpy(newrom, rom, romsize);
+ return newrom;
+}
+
+// Map the option rom of a given PCI device.
+static struct rom_header *
+map_pcirom(struct pci_device *pci)
+{
+ dprintf(6, "Attempting to map option rom on dev %pP\n", pci);
+
+ if ((pci->header_type & 0x7f) != PCI_HEADER_TYPE_NORMAL) {
+ dprintf(6, "Skipping non-normal pci device (type=%x)\n"
+ , pci->header_type);
+ return NULL;
+ }
+
+ u16 bdf = pci->bdf;
+ u32 orig = pci_config_readl(bdf, PCI_ROM_ADDRESS);
+ pci_config_writel(bdf, PCI_ROM_ADDRESS, ~PCI_ROM_ADDRESS_ENABLE);
+ u32 sz = pci_config_readl(bdf, PCI_ROM_ADDRESS);
+
+ dprintf(6, "Option rom sizing returned %x %x\n", orig, sz);
+ orig &= ~PCI_ROM_ADDRESS_ENABLE;
+ if (!sz || sz == 0xffffffff)
+ goto fail;
+
+ if (orig == sz || (u32)(orig + 4*1024*1024) < 20*1024*1024) {
+ // Don't try to map to a pci addresses at its max, in the last
+ // 4MiB of ram, or the first 16MiB of ram.
+ dprintf(6, "Preset rom address doesn't look valid\n");
+ goto fail;
+ }
+
+ // Looks like a rom - enable it.
+ pci_config_writel(bdf, PCI_ROM_ADDRESS, orig | PCI_ROM_ADDRESS_ENABLE);
+
+ struct rom_header *rom = (void*)orig;
+ for (;;) {
+ dprintf(5, "Inspecting possible rom at %p (vd=%04x:%04x bdf=%pP)\n"
+ , rom, pci->vendor, pci->device, pci);
+ if (rom->signature != OPTION_ROM_SIGNATURE) {
+ dprintf(6, "No option rom signature (got %x)\n", rom->signature);
+ goto fail;
+ }
+ struct pci_data *pd = get_pci_rom(rom);
+ if (! pd) {
+ dprintf(6, "No valid pci signature found\n");
+ goto fail;
+ }
+
+ if (pd->vendor == pci->vendor && pd->device == pci->device
+ && pd->type == PCIROM_CODETYPE_X86)
+ // A match
+ break;
+ dprintf(6, "Didn't match dev/ven (got %04x:%04x) or type (got %d)\n"
+ , pd->vendor, pd->device, pd->type);
+ if (pd->indicator & 0x80) {
+ dprintf(6, "No more images left\n");
+ goto fail;
+ }
+ rom = (void*)((u32)rom + pd->ilen * 512);
+ }
+
+ rom = copy_rom(rom);
+ pci_config_writel(bdf, PCI_ROM_ADDRESS, orig);
+ return rom;
+fail:
+ // Not valid - restore original and exit.
+ pci_config_writel(bdf, PCI_ROM_ADDRESS, orig);
+ return NULL;
+}
+
+static int boot_irq_captured(void)
+{
+ return GET_IVT(0x19).segoff != FUNC16(entry_19_official).segoff;
+}
+
+static void boot_irq_restore(void)
+{
+ struct segoff_s seabios;
+
+ seabios = FUNC16(entry_19_official);
+ SET_IVT(0x19, seabios);
+}
+
+// Attempt to map and initialize the option rom on a given PCI device.
+static void
+init_pcirom(struct pci_device *pci, int isvga, u64 *sources)
+{
+ dprintf(4, "Attempting to init PCI bdf %pP (vd %04x:%04x)\n"
+ , pci, pci->vendor, pci->device);
+
+ 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;
+ int irq_was_captured = boot_irq_captured();
+ struct pnp_data *pnp = get_pnp_rom(rom);
+ setRomSource(sources, rom, RS_PCIROM | (u32)pci);
+ init_optionrom(rom, pci->bdf, isvga);
+ if (boot_irq_captured() && !irq_was_captured &&
+ !file && !isvga && pnp) {
+ // This PCI rom is misbehaving - recapture the boot irqs
+ char *desc = MAKE_FLATPTR(FLATPTR_TO_SEG(rom), pnp->productname);
+ dprintf(1, "PnP optionrom \"%s\" (bdf %pP) captured int19, restoring\n",
+ desc, pci);
+ boot_irq_restore();
+ }
+}
+
+
+/****************************************************************
+ * Non-VGA option rom init
+ ****************************************************************/
+
+void
+optionrom_setup(void)
+{
+ if (! CONFIG_OPTIONROMS)
+ return;
+
+ dprintf(1, "Scan for option roms\n");
+ u64 sources[(BUILD_BIOS_ADDR - BUILD_ROM_START) / OPTION_ROM_ALIGN];
+ memset(sources, 0, sizeof(sources));
+ u32 post_vga = rom_get_last();
+
+ // Find and deploy PCI roms.
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->class == PCI_CLASS_DISPLAY_VGA ||
+ pci->class == PCI_CLASS_DISPLAY_OTHER ||
+ pci->have_driver)
+ continue;
+ init_pcirom(pci, 0, sources);
+ }
+
+ // Find and deploy CBFS roms not associated with a device.
+ run_file_roms("genroms/", 0, sources);
+ rom_reserve(0);
+
+ // All option roms found and deployed - now build BEV/BCV vectors.
+
+ u32 pos = post_vga;
+ while (pos < rom_get_last()) {
+ struct rom_header *rom = (void*)pos;
+ if (! is_valid_rom(rom)) {
+ pos += OPTION_ROM_ALIGN;
+ continue;
+ }
+ pos += ALIGN(rom->size * 512, OPTION_ROM_ALIGN);
+ struct pnp_data *pnp = get_pnp_rom(rom);
+ if (! pnp) {
+ // Legacy rom.
+ boot_add_bcv(FLATPTR_TO_SEG(rom), OPTION_ROM_INITVECTOR, 0
+ , getRomPriority(sources, rom, 0));
+ continue;
+ }
+ // PnP rom - check for BEV and BCV boot capabilities.
+ int instance = 0;
+ while (pnp) {
+ if (pnp->bev)
+ boot_add_bev(FLATPTR_TO_SEG(rom), pnp->bev, pnp->productname
+ , getRomPriority(sources, rom, instance++));
+ else if (pnp->bcv)
+ boot_add_bcv(FLATPTR_TO_SEG(rom), pnp->bcv, pnp->productname
+ , getRomPriority(sources, rom, instance++));
+ else
+ break;
+ pnp = get_pnp_next(rom, pnp);
+ }
+ }
+}
+
+
+/****************************************************************
+ * VGA init
+ ****************************************************************/
+
+int ScreenAndDebug;
+struct rom_header *VgaROM;
+
+static void try_setup_display_other(void)
+{
+ struct pci_device *pci;
+
+ dprintf(1, "No VGA found, scan for other display\n");
+
+ foreachpci(pci) {
+ if (pci->class != PCI_CLASS_DISPLAY_OTHER)
+ continue;
+ struct rom_header *rom = map_pcirom(pci);
+ if (!rom)
+ continue;
+ dprintf(1, "Other display found at %pP\n", pci);
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+ init_optionrom(rom, pci->bdf, 1);
+ return;
+ }
+}
+
+// Call into vga code to turn on console.
+void
+vgarom_setup(void)
+{
+ int have_vga = 0;
+
+ if (! CONFIG_OPTIONROMS)
+ return;
+
+ dprintf(1, "Scan for VGA option rom\n");
+
+ // 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);
+
+ // Clear option rom memory
+ memset((void*)BUILD_ROM_START, 0, rom_get_max() - BUILD_ROM_START);
+
+ // Find and deploy PCI VGA rom.
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (!is_pci_vga(pci))
+ continue;
+ vgahook_setup(pci);
+ init_pcirom(pci, 1, NULL);
+ have_vga = 1;
+ break;
+ }
+ if (!have_vga)
+ try_setup_display_other();
+
+ // Find and deploy CBFS vga-style roms not associated with a device.
+ run_file_roms("vgaroms/", 1, NULL);
+ rom_reserve(0);
+
+ if (rom_get_last() != BUILD_ROM_START)
+ // VGA rom found
+ VgaROM = (void*)BUILD_ROM_START;
+}
+
+void
+s3_resume_vga(void)
+{
+ if (!S3ResumeVga)
+ return;
+ if (!VgaROM || ! is_valid_rom(VgaROM))
+ return;
+ callrom(VgaROM, 0);
+}
diff --git a/roms/seabios-hppa/src/output.c b/roms/seabios-hppa/src/output.c
new file mode 100644
index 000000000..fcbc3f92c
--- /dev/null
+++ b/roms/seabios-hppa/src/output.c
@@ -0,0 +1,602 @@
+// Raw screen writing and debug output code.
+//
+// Copyright (C) 2008-2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include <stdarg.h> // va_list
+
+#include "farptr.h" // GET_VAR
+#include "bregs.h" // struct bregs
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+#include "hw/pci.h" // pci_bdf_to_bus
+#include "hw/pcidevice.h" // pci_device
+#include "hw/serialio.h" // serial_debug_putc
+#include "malloc.h" // malloc_tmp
+#include "output.h" // dprintf
+#include "stacks.h" // call16_int
+#include "string.h" // memset
+#include "util.h" // ScreenAndDebug
+#if CONFIG_PARISC
+#include "parisc/sticore.h"
+#endif
+
+struct putcinfo {
+ void (*func)(struct putcinfo *info, char c);
+};
+
+
+/****************************************************************
+ * Debug output
+ ****************************************************************/
+
+void
+debug_banner(void)
+{
+ dprintf(1, "SeaBIOS (version %s)\n", VERSION);
+ dprintf(1, "BUILD: %s\n", BUILDINFO);
+}
+
+// Write a character to debug port(s).
+static void
+debug_putc(struct putcinfo *action, char c)
+{
+ if (! CONFIG_DEBUG_LEVEL)
+ return;
+ qemu_debug_putc(c);
+ if (!MODESEGMENT)
+ coreboot_debug_putc(c);
+ if (!CONFIG_PARISC)
+ serial_debug_putc(c);
+}
+
+// Flush any pending output to debug port(s).
+static void
+debug_flush(void)
+{
+ serial_debug_flush();
+}
+
+// In segmented mode just need a dummy variable (debug_putc is always
+// used anyway), and in 32bit flat mode need a pointer to the 32bit
+// instance of debug_putc().
+#if MODE16
+static struct putcinfo debuginfo VAR16;
+#elif MODESEGMENT
+static struct putcinfo debuginfo VAR32SEG;
+#else
+static struct putcinfo debuginfo = { debug_putc };
+#endif
+
+
+/****************************************************************
+ * Screen writing
+ ****************************************************************/
+
+// Show a character on the screen.
+static void
+screenc(char c)
+{
+#if CONFIG_X86
+ if (!MODESEGMENT && GET_IVT(0x10).segoff == FUNC16(entry_10).segoff)
+ // No need to thunk to 16bit mode if vgabios is not present
+ return;
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ br.ah = 0x0e;
+ br.al = c;
+ br.bl = 0x07;
+ call16_int(0x10, &br);
+#else
+ parisc_screenc(c);
+#endif
+}
+
+// Handle a character from a printf request.
+static void
+screen_putc(struct putcinfo *action, char c)
+{
+ if (ScreenAndDebug)
+ debug_putc(&debuginfo, c);
+ if (CONFIG_X86 && c == '\n')
+ screenc('\r');
+ screenc(c);
+}
+
+static struct putcinfo screeninfo = { screen_putc };
+
+
+/****************************************************************
+ * Xprintf code
+ ****************************************************************/
+
+// Output a character.
+static void
+putc(struct putcinfo *action, char c)
+{
+ if (MODESEGMENT) {
+ // Only debugging output supported in segmented mode.
+ debug_putc(action, c);
+ return;
+ }
+
+ void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
+ func(action, c);
+}
+
+// Ouptut a string.
+static void
+puts(struct putcinfo *action, const char *s)
+{
+ if (!MODESEGMENT && !s)
+ s = "(NULL)";
+ for (; *s; s++)
+ putc(action, *s);
+}
+
+// Output a string that is in the CS segment.
+static void
+puts_cs(struct putcinfo *action, const char *s)
+{
+ char *vs = (char*)s;
+ for (;; vs++) {
+ char c = GET_GLOBAL(*vs);
+ if (!c)
+ break;
+ putc(action, c);
+ }
+}
+
+// Output an unsigned integer.
+static void
+#if CONFIG_X86
+putuint(struct putcinfo *action, u32 val)
+#else
+putuint(struct putcinfo *action, u64 val)
+#endif
+{
+ char buf[40];
+ char *d = &buf[sizeof(buf) - 1];
+ *d-- = '\0';
+ for (;;) {
+ *d = (val % 10) + '0';
+ val /= 10;
+ if (!val)
+ break;
+ d--;
+ }
+ puts(action, d);
+}
+
+// Output a single digit hex character.
+static inline void
+putsinglehex(struct putcinfo *action, u32 val, int uc)
+{
+ if (val <= 9)
+ val = '0' + val;
+ else if (uc)
+ val = 'A' + val - 10;
+ else
+ val = 'a' + val - 10;
+ putc(action, val);
+}
+
+// Output an integer in hexadecimal with a specified width.
+static void
+puthex(struct putcinfo *action, u32 val, int width, int uc)
+{
+ switch (width) {
+ default: putsinglehex(action, (val >> 28) & 0xf, uc);
+ case 7: putsinglehex(action, (val >> 24) & 0xf, uc);
+ case 6: putsinglehex(action, (val >> 20) & 0xf, uc);
+ case 5: putsinglehex(action, (val >> 16) & 0xf, uc);
+ case 4: putsinglehex(action, (val >> 12) & 0xf, uc);
+ case 3: putsinglehex(action, (val >> 8) & 0xf, uc);
+ case 2: putsinglehex(action, (val >> 4) & 0xf, uc);
+ case 1: putsinglehex(action, (val >> 0) & 0xf, uc);
+ }
+}
+
+// Output an integer in hexadecimal with a minimum width.
+static void
+putprettyhex(struct putcinfo *action, u64 val, int width, char padchar, int uc)
+{
+ u64 tmp = val;
+ int count = 1;
+ while (tmp >>= 4)
+ count++;
+ width -= count;
+ while (width-- > 0)
+ putc(action, padchar);
+ puthex(action, val, count, uc);
+}
+
+// Output 'struct pci_device' BDF as %02x:%02x.%x
+static void
+put_pci_device(struct putcinfo *action, struct pci_device *pci)
+{
+ puthex(action, pci_bdf_to_bus(pci->bdf), 2, 0);
+ putc(action, ':');
+ puthex(action, pci_bdf_to_dev(pci->bdf), 2, 0);
+ putc(action, '.');
+ puthex(action, pci_bdf_to_fn(pci->bdf), 1, 0);
+}
+
+static inline int
+isdigit(u8 c)
+{
+ return ((u8)(c - '0')) < 10;
+}
+
+static void
+bvprintf(struct putcinfo *action, const char *fmt, va_list args)
+{
+ const char *s = fmt;
+ int uc;
+ for (;; s++) {
+ char c = GET_GLOBAL(*(u8*)s);
+ if (!c)
+ break;
+ if (c != '%') {
+ putc(action, c);
+ continue;
+ }
+ const char *n = s+1;
+ int field_width = 0;
+ char padchar = ' ';
+ u8 is64 = 0;
+ for (;;) {
+ c = GET_GLOBAL(*(u8*)n);
+ if (!isdigit(c))
+ break;
+ if (!field_width && (c == '0'))
+ padchar = '0';
+ else
+ field_width = field_width * 10 + c - '0';
+ n++;
+ }
+ if (c == 'l') {
+ // Ignore long format indicator
+ n++;
+ c = GET_GLOBAL(*(u8*)n);
+ }
+ if (c == 'l') {
+ is64 = 1;
+ n++;
+ c = GET_GLOBAL(*(u8*)n);
+ }
+ s32 val;
+ s64 val64;
+ const char *sarg;
+ switch (c) {
+ case '%':
+ putc(action, '%');
+ break;
+ case 'd':
+ if (is64)
+ val64 = va_arg(args, s64);
+ else
+ val64 = va_arg(args, s32);
+ if (val64 < 0) {
+ putc(action, '-');
+ val64 = -val64;
+ }
+ putuint(action, val64);
+ break;
+ case 'u':
+ if (is64)
+ val64 = va_arg(args, s64);
+ else
+ val64 = va_arg(args, s32);
+ putuint(action, val64);
+ break;
+ case 'p':
+ val = va_arg(args, s32);
+ if (!MODESEGMENT && GET_GLOBAL(*(u8*)(n+1)) == 'P') {
+ // %pP is 'struct pci_device' printer
+ put_pci_device(action, (void*)val);
+ n++;
+ break;
+ }
+ putc(action, '0');
+ putc(action, 'x');
+ puthex(action, val, 8, 0);
+ break;
+ case 'X':
+ case 'x':
+ uc = (c == 'X');
+ if (is64)
+ val64 = va_arg(args, s64);
+ else
+ val64 = va_arg(args, s32);
+ putprettyhex(action, val64, field_width, padchar, uc);
+ break;
+ case 'c':
+ val = va_arg(args, int);
+ putc(action, val);
+ break;
+ case '.':
+ // Hack to support "%.s" - meaning string on stack.
+ if (GET_GLOBAL(*(u8*)(n+1)) != 's')
+ break;
+ n++;
+ sarg = va_arg(args, const char *);
+ puts(action, sarg);
+ break;
+ case 's':
+ sarg = va_arg(args, const char *);
+ puts_cs(action, sarg);
+ break;
+ default:
+ putc(action, '%');
+ n = s;
+ }
+ s = n;
+ }
+}
+
+void
+panic(const char *fmt, ...)
+{
+ if (CONFIG_DEBUG_LEVEL) {
+ va_list args;
+ va_start(args, fmt);
+ bvprintf(&debuginfo, fmt, args);
+ va_end(args);
+ debug_flush();
+ }
+
+ // XXX - use PANIC PORT.
+ irq_disable();
+ for (;;)
+ hlt();
+}
+
+void
+__dprintf(const char *fmt, ...)
+{
+ if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
+ && *fmt != '\\' && *fmt != '/') {
+ struct thread_info *cur = getCurThread();
+ if (cur != &MainThread) {
+ // Show "thread id" for this debug message.
+ debug_putc(&debuginfo, '|');
+ puthex(&debuginfo, (u32)cur, 8, 0);
+ debug_putc(&debuginfo, '|');
+ debug_putc(&debuginfo, ' ');
+ }
+ }
+
+ va_list args;
+ va_start(args, fmt);
+ bvprintf(&debuginfo, fmt, args);
+ va_end(args);
+ debug_flush();
+}
+
+void
+printf(const char *fmt, ...)
+{
+ ASSERT32FLAT();
+ va_list args;
+ va_start(args, fmt);
+ bvprintf(&screeninfo, fmt, args);
+ va_end(args);
+ if (ScreenAndDebug)
+ debug_flush();
+}
+
+
+/****************************************************************
+ * snprintf
+ ****************************************************************/
+
+struct snprintfinfo {
+ struct putcinfo info;
+ char *str, *end;
+};
+
+static void
+putc_str(struct putcinfo *info, char c)
+{
+ struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
+ if (sinfo->str >= sinfo->end)
+ return;
+ *sinfo->str = c;
+ sinfo->str++;
+}
+
+// Build a formatted string. Note, this function returns the actual
+// number of bytes used (not including null) even in the overflow
+// case.
+int
+snprintf(char *str, size_t size, const char *fmt, ...)
+{
+ ASSERT32FLAT();
+ if (!size)
+ return 0;
+ struct snprintfinfo sinfo = { { putc_str }, str, str + size };
+ va_list args;
+ va_start(args, fmt);
+ bvprintf(&sinfo.info, fmt, args);
+ va_end(args);
+ char *end = sinfo.str;
+ if (end >= sinfo.end)
+ end = sinfo.end - 1;
+ *end = '\0';
+ return end - str;
+}
+
+// Build a formatted string - malloc'ing the memory.
+char *
+znprintf(size_t size, const char *fmt, ...)
+{
+ ASSERT32FLAT();
+ if (!size)
+ return NULL;
+ char *str = malloc_tmp(size);
+ if (!str) {
+ warn_noalloc();
+ return NULL;
+ }
+ struct snprintfinfo sinfo = { { putc_str }, str, str + size };
+ va_list args;
+ va_start(args, fmt);
+ bvprintf(&sinfo.info, fmt, args);
+ va_end(args);
+ char *end = sinfo.str;
+ if (end >= sinfo.end)
+ end = sinfo.end - 1;
+ *end = '\0';
+ return str;
+}
+
+
+/****************************************************************
+ * Misc helpers
+ ****************************************************************/
+
+void
+hexdump(const void *d, int len)
+{
+ int count=0;
+ while (len > 0) {
+ if (count % 8 == 0) {
+ putc(&debuginfo, '\n');
+ puthex(&debuginfo, count*4, 8, 0);
+ putc(&debuginfo, ':');
+ } else {
+ putc(&debuginfo, ' ');
+ }
+ puthex(&debuginfo, *(u32*)d, 8, 0);
+ count++;
+ len-=4;
+ d+=4;
+ }
+ putc(&debuginfo, '\n');
+ debug_flush();
+}
+
+static void
+dump_regs(struct bregs *regs)
+{
+ if (!regs) {
+ dprintf(1, " NULL\n");
+ return;
+ }
+ dprintf(1, " a=%08x b=%08x c=%08x d=%08x ds=%04x es=%04x ss=%04x\n"
+ , regs->eax, regs->ebx, regs->ecx, regs->edx
+ , regs->ds, regs->es, GET_SEG(SS));
+ dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
+ , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
+ , regs->code.seg, regs->code.offset, regs->flags);
+}
+
+// Report entry to an Interrupt Service Routine (ISR).
+void
+__debug_isr(const char *fname)
+{
+ puts_cs(&debuginfo, fname);
+ putc(&debuginfo, '\n');
+ debug_flush();
+}
+
+// Function called on handler startup.
+void
+__debug_enter(struct bregs *regs, const char *fname)
+{
+ dprintf(1, "enter %s:\n", fname);
+ dump_regs(regs);
+}
+
+// Send debugging output info.
+void
+__debug_stub(struct bregs *regs, int lineno, const char *fname)
+{
+ dprintf(1, "stub %s:%d:\n", fname, lineno);
+ dump_regs(regs);
+}
+
+// Report on an invalid parameter.
+void
+__warn_invalid(struct bregs *regs, int lineno, const char *fname)
+{
+ if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
+ dprintf(1, "invalid %s:%d:\n", fname, lineno);
+ dump_regs(regs);
+ }
+}
+
+// Report on an unimplemented feature.
+void
+__warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
+{
+ if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
+ dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
+ dump_regs(regs);
+ }
+}
+
+// Report a detected internal inconsistency.
+void
+__warn_internalerror(int lineno, const char *fname)
+{
+ dprintf(1, "WARNING - internal error detected at %s:%d!\n"
+ , fname, lineno);
+}
+
+// Report on an allocation failure.
+void
+__warn_noalloc(int lineno, const char *fname)
+{
+ dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
+ , fname, lineno);
+}
+
+// Report on a timeout exceeded.
+void
+__warn_timeout(int lineno, const char *fname)
+{
+ dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
+}
+
+// Report a handler reporting an invalid parameter to the caller.
+void
+__set_invalid(struct bregs *regs, int lineno, const char *fname)
+{
+ __warn_invalid(regs, lineno, fname);
+ set_invalid_silent(regs);
+}
+
+// Report a call of an unimplemented function.
+void
+__set_unimplemented(struct bregs *regs, int lineno, const char *fname)
+{
+ __warn_unimplemented(regs, lineno, fname);
+ set_invalid_silent(regs);
+}
+
+// Report a handler reporting an invalid parameter code to the
+// caller. Note, the lineno and return code are encoded in the same
+// parameter as gcc does a better job of scheduling function calls
+// when there are 3 or less parameters.
+void
+__set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
+{
+ u8 code = linecode;
+ u32 lineno = linecode >> 8;
+ __warn_invalid(regs, lineno, fname);
+ set_code_invalid_silent(regs, code);
+}
+
+// Report a call of an unimplemented function.
+void
+__set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
+{
+ u8 code = linecode;
+ u32 lineno = linecode >> 8;
+ __warn_unimplemented(regs, lineno, fname);
+ set_code_invalid_silent(regs, code);
+}
diff --git a/roms/seabios-hppa/src/output.h b/roms/seabios-hppa/src/output.h
new file mode 100644
index 000000000..14288cf50
--- /dev/null
+++ b/roms/seabios-hppa/src/output.h
@@ -0,0 +1,68 @@
+#ifndef __OUTPUT_H
+#define __OUTPUT_H
+
+#include "config.h" // CONFIG_DEBUG_LEVEL
+#include "types.h" // u32
+
+// output.c
+void debug_banner(void);
+void panic(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2))) __noreturn;
+void printf(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+int snprintf(char *str, size_t size, const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
+char * znprintf(size_t size, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+void __dprintf(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+struct bregs;
+void __debug_enter(struct bregs *regs, const char *fname);
+void __debug_isr(const char *fname);
+void __debug_stub(struct bregs *regs, int lineno, const char *fname);
+void __warn_invalid(struct bregs *regs, int lineno, const char *fname);
+void __warn_unimplemented(struct bregs *regs, int lineno, const char *fname);
+void __warn_internalerror(int lineno, const char *fname);
+void __warn_noalloc(int lineno, const char *fname);
+void __warn_timeout(int lineno, const char *fname);
+void __set_invalid(struct bregs *regs, int lineno, const char *fname);
+void __set_unimplemented(struct bregs *regs, int lineno, const char *fname);
+void __set_code_invalid(struct bregs *regs, u32 linecode, const char *fname);
+void __set_code_unimplemented(struct bregs *regs, u32 linecode
+ , const char *fname);
+void hexdump(const void *d, int len);
+
+#define dprintf(lvl, fmt, args...) do { \
+ if (CONFIG_DEBUG_LEVEL && (lvl) <= CONFIG_DEBUG_LEVEL) \
+ __dprintf((fmt) , ##args ); \
+ } while (0)
+#define debug_enter(regs, lvl) do { \
+ if ((lvl) && (lvl) <= CONFIG_DEBUG_LEVEL) \
+ __debug_enter((regs), __func__); \
+ } while (0)
+#define debug_isr(lvl) do { \
+ if ((lvl) && (lvl) <= CONFIG_DEBUG_LEVEL) \
+ __debug_isr(__func__); \
+ } while (0)
+#define debug_stub(regs) \
+ __debug_stub((regs), __LINE__, __func__)
+#define warn_invalid(regs) \
+ __warn_invalid((regs), __LINE__, __func__)
+#define warn_unimplemented(regs) \
+ __warn_unimplemented((regs), __LINE__, __func__)
+#define warn_internalerror() \
+ __warn_internalerror(__LINE__, __func__)
+#define warn_noalloc() \
+ __warn_noalloc(__LINE__, __func__)
+#define warn_timeout() \
+ __warn_timeout(__LINE__, __func__)
+#define set_invalid(regs) \
+ __set_invalid((regs), __LINE__, __func__)
+#define set_code_invalid(regs, code) \
+ __set_code_invalid((regs), (code) | (__LINE__ << 8), __func__)
+#define set_unimplemented(regs) \
+ __set_unimplemented((regs), __LINE__, __func__)
+#define set_code_unimplemented(regs, code) \
+ __set_code_unimplemented((regs), (code) | (__LINE__ << 8), __func__)
+
+#endif // output.h
diff --git a/roms/seabios-hppa/src/parisc/b160l.h b/roms/seabios-hppa/src/parisc/b160l.h
new file mode 100644
index 000000000..0e057fa84
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/b160l.h
@@ -0,0 +1,630 @@
+/* AUTO-GENERATED FILE FOR QEMU */
+#define PARISC_MODEL "9000/778/B160L"
+#define PARISC_PDC_MODEL 0x5020, 0x481, 0x0,\
+0x2020202, 0x7794d7fe, 0x100000f0, 0x4, 0xba, 0xba
+#define PARISC_PDC_VERSION 0x0008
+#define PARISC_PDC_CPUID 0x01e8
+#define PARISC_PDC_CAPABILITIES 0x0002
+#define PARISC_PDC_ENTRY_ORG 0x4800
+#define PARISC_PDC_CACHE_INFO\
+ 0x10000, 0x41402000, 0x0000, 0x0020, 0x0400\
+ , 0x0002, 0x10000, 0x41402000, 0x0000, 0x0020\
+ , 0x0400, 0x0002, 0x0060, 0xd2000, 0x0000\
+ , 0x0000, 0x0001, 0x0000, 0x0000, 0x0001\
+ , 0x0001, 0x0060, 0xd2000, 0x0000, 0x0000\
+ , 0x0001, 0x0000, 0x0000, 0x0001, 0x0001
+
+#define HPA_ffc00000_DESCRIPTION "Phantom PseudoBC GSC+ Port"
+static struct pdc_system_map_mod_info mod_info_hpa_ffc00000 = {
+ .mod_addr = 0xffc00000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffc00000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .mod = 0x8 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffc00000 = {
+ .hversion_model = 0x0050,
+ .hversion = 0x0040,
+ .spa = 0x0000,
+ .type = 0x0007,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0000,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffc00000_num_addr 0
+#define HPA_ffc00000_add_addr 0
+
+#define HPA_fff80000_DESCRIPTION "Dino PCI Bridge"
+static struct pdc_system_map_mod_info mod_info_hpa_fff80000 = {
+ .mod_addr = 0xfff80000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fff80000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x8 }, .mod = 0x0 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fff80000 = {
+ .hversion_model = 0x0068,
+ .hversion = 0x0003,
+ .spa = 0x0000,
+ .type = 0x004d,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0005,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_fff80000_num_addr 0
+#define HPA_fff80000_add_addr 0
+
+#define HPA_fff83000_DESCRIPTION "Merlin+ 132 Dino RS-232"
+static struct pdc_system_map_mod_info mod_info_hpa_fff83000 = {
+ .mod_addr = 0xfff83000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fff83000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x0 }, .mod = 0x3f },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fff83000 = {
+ .hversion_model = 0x0002,
+ .hversion = 0x0020,
+ .spa = 0x0000,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0046,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x6729,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_fff83000_num_addr 0
+#define HPA_fff83000_add_addr 0
+
+#define HPA_fff8c000_DESCRIPTION "Merlin 160 Core FW-SCSI"
+static struct pdc_system_map_mod_info mod_info_hpa_fff8c000 = {
+ .mod_addr = 0xfff8c000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fff8c000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x8 }, .mod = 0xc },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fff8c000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0000,
+ .type = 0x0084,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0044,
+ .sversion_opt = 0x00c0,
+ .rev = 0x0099,
+ .dep = 0x0000,
+ .features = 0x0001,
+ .checksum = 0xc5e9,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_fff8c000_num_addr 0
+#define HPA_fff8c000_add_addr 0
+
+#define HPA_ffd00000_DESCRIPTION "Merlin 160 Core BA"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd00000 = {
+ .mod_addr = 0xffd00000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x2,
+};
+static struct pdc_module_path mod_path_hpa_ffd00000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x8 }, .mod = 0x10 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd00000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0080,
+ .type = 0x004b,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0040,
+ .sversion_opt = 0x0080,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd00000_num_addr 2
+#define HPA_ffd00000_add_addr 0xffd0c000, 0xffc00000,
+
+#define HPA_ffd05000_DESCRIPTION "Merlin 160 Core RS-232"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd05000 = {
+ .mod_addr = 0xffd05000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffd05000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x4 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd05000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0000,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0046,
+ .sversion_opt = 0x0000,
+ .rev = 0x0001,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x6309,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd05000_num_addr 0
+#define HPA_ffd05000_add_addr 0
+
+#define HPA_ffd06000_DESCRIPTION "Merlin 160 Core SCSI"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd06000 = {
+ .mod_addr = 0xffd06000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffd06000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x5 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd06000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0080,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0041,
+ .sversion_opt = 0x0000,
+ .rev = 0x0099,
+ .dep = 0x0000,
+ .features = 0x0001,
+ .checksum = 0x4d41,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd06000_num_addr 0
+#define HPA_ffd06000_add_addr 0
+
+#define HPA_ffd07000_DESCRIPTION "Merlin 160 Core LAN (802.3)"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd07000 = {
+ .mod_addr = 0xffd07000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffd07000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x6 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd07000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0080,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0045,
+ .sversion_opt = 0x0000,
+ .rev = 0x0002,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0xd8fa,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd07000_num_addr 0
+#define HPA_ffd07000_add_addr 0
+
+#define HPA_ffd02000_DESCRIPTION "Merlin 160 Core Centronics"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd02000 = {
+ .mod_addr = 0xffd02000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x2,
+};
+static struct pdc_module_path mod_path_hpa_ffd02000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x0 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd02000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0080,
+ .type = 0x000a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x003a,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd02000_num_addr 2
+#define HPA_ffd02000_add_addr 0xffd01000, 0xffd03000,
+
+#define HPA_ffd04000_DESCRIPTION "Merlin 160 Core Audio"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd04000 = {
+ .mod_addr = 0xffd04000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffd04000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x1 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd04000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d4,
+ .spa = 0x0080,
+ .type = 0x000a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x003d,
+ .sversion_opt = 0x0080,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd04000_num_addr 0
+#define HPA_ffd04000_add_addr 0
+
+#define HPA_ffd08000_DESCRIPTION "Merlin 160 Core PS/2 Port"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd08000 = {
+ .mod_addr = 0xffd08000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffd08000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x7 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd08000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0000,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0042,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x6e05,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd08000_num_addr 0
+#define HPA_ffd08000_add_addr 0
+
+#define HPA_ffd08100_DESCRIPTION "Merlin 160 Core PS/2 Port"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd08100 = {
+ .mod_addr = 0xffd08100,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffd08100 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x8 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd08100 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0000,
+ .type = 0x000a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0042,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd08100_num_addr 0
+#define HPA_ffd08100_add_addr 0
+
+#define HPA_fa000000_DESCRIPTION "Coral SGC Graphics"
+static struct pdc_system_map_mod_info mod_info_hpa_fa000000 = {
+ .mod_addr = 0xfa000000,
+ .mod_pgs = 0x2000,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fa000000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x8 }, .mod = 0x4 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fa000000 = {
+ .hversion_model = 0x0000,
+ .hversion = 0x0040,
+ .spa = 0x0000,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x003b,
+ .sversion_opt = 0x0080,
+ .rev = 0x00fa,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x67d0,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_fa000000_num_addr 0
+#define HPA_fa000000_add_addr 0
+
+#define HPA_f4000000_DESCRIPTION "Coral SGC Graphics"
+static struct pdc_system_map_mod_info mod_info_hpa_f4000000 = {
+ .mod_addr = 0xf4000000,
+ .mod_pgs = 0x2000,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_f4000000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x8 }, .mod = 0x8 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_f4000000 = {
+ .hversion_model = 0x0000,
+ .hversion = 0x0040,
+ .spa = 0x0000,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x003b,
+ .sversion_opt = 0x0080,
+ .rev = 0x00f4,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x67d0,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_f4000000_num_addr 0
+#define HPA_f4000000_add_addr 0
+
+#define HPA_f8000000_DESCRIPTION "Gecko GSC Core Graphics"
+static struct pdc_system_map_mod_info mod_info_hpa_f8000000 = {
+ .mod_addr = 0xf8000000,
+ .mod_pgs = 0x2000,
+ .add_addrs = 0x1,
+};
+static struct pdc_module_path mod_path_hpa_f8000000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .mod = 0x1 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_f8000000 = {
+ .hversion_model = 0x0001,
+ .hversion = 0x0060,
+ .spa = 0x0000,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0042,
+ .sversion_opt = 0x0080,
+ .rev = 0x0001,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x67d0,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_f8000000_num_addr 0
+#define HPA_f8000000_add_addr 0
+
+#define HPA_fff10000_DESCRIPTION "Merlin L2 160 (9000/778/B160L)"
+static struct pdc_system_map_mod_info mod_info_hpa_fff10000 = {
+ .mod_addr = CPU_HPA,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fff10000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .mod = 0x3e },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fff10000 = {
+ .hversion_model = 0x0050,
+ .hversion = 0x0020,
+ .spa = 0x0000,
+ .type = 0x0040,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0002,
+ .sversion_opt = 0x0040,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_fff10000_num_addr 0
+#define HPA_fff10000_add_addr 0
+
+#define HPA_fffbf000_DESCRIPTION "Memory"
+static struct pdc_system_map_mod_info mod_info_hpa_fffbf000 = {
+ .mod_addr = 0xfffbf000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fffbf000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .mod = 0x3f },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fffbf000 = {
+ .hversion_model = 0x0006,
+ .hversion = 0x0070,
+ .spa = 0x001f,
+ .type = 0x0041,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0004,
+ .sversion_opt = 0x0080,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_fffbf000_num_addr 0
+#define HPA_fffbf000_add_addr 0
+
+#define HPA_fff81000_DESCRIPTION "Merlin+ 132 Dino PS/2 Port"
+static struct pdc_system_map_mod_info mod_info_hpa_fff81000 = {
+ .mod_addr = 0x0,
+ .mod_pgs = 0x0,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fff81000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x8 }, .mod = 0x0 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fff81000 = {
+ .hversion_model = 0x0002,
+ .hversion = 0x0020,
+ .spa = 0x0080,
+ .type = 0x004a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x004b,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_fff81000_num_addr 0
+#define HPA_fff81000_add_addr 0
+
+#define PARISC_DEVICE_LIST \
+ { .hpa = 0xffc00000,\
+ .iodc = &iodc_data_hpa_ffc00000,\
+ .mod_info = &mod_info_hpa_ffc00000,\
+ .mod_path = &mod_path_hpa_ffc00000,\
+ .num_addr = HPA_ffc00000_num_addr,\
+ .add_addr = { HPA_ffc00000_add_addr } },\
+ { .hpa = 0xfff80000,\
+ .iodc = &iodc_data_hpa_fff80000,\
+ .mod_info = &mod_info_hpa_fff80000,\
+ .mod_path = &mod_path_hpa_fff80000,\
+ .num_addr = HPA_fff80000_num_addr,\
+ .add_addr = { HPA_fff80000_add_addr } },\
+ { .hpa = 0xfff83000,\
+ .iodc = &iodc_data_hpa_fff83000,\
+ .mod_info = &mod_info_hpa_fff83000,\
+ .mod_path = &mod_path_hpa_fff83000,\
+ .num_addr = HPA_fff83000_num_addr,\
+ .add_addr = { HPA_fff83000_add_addr } },\
+ { .hpa = 0xfff8c000,\
+ .iodc = &iodc_data_hpa_fff8c000,\
+ .mod_info = &mod_info_hpa_fff8c000,\
+ .mod_path = &mod_path_hpa_fff8c000,\
+ .num_addr = HPA_fff8c000_num_addr,\
+ .add_addr = { HPA_fff8c000_add_addr } },\
+ { .hpa = 0xffd00000,\
+ .iodc = &iodc_data_hpa_ffd00000,\
+ .mod_info = &mod_info_hpa_ffd00000,\
+ .mod_path = &mod_path_hpa_ffd00000,\
+ .num_addr = HPA_ffd00000_num_addr,\
+ .add_addr = { HPA_ffd00000_add_addr } },\
+ { .hpa = 0xffd05000,\
+ .iodc = &iodc_data_hpa_ffd05000,\
+ .mod_info = &mod_info_hpa_ffd05000,\
+ .mod_path = &mod_path_hpa_ffd05000,\
+ .num_addr = HPA_ffd05000_num_addr,\
+ .add_addr = { HPA_ffd05000_add_addr } },\
+ { .hpa = 0xffd06000,\
+ .iodc = &iodc_data_hpa_ffd06000,\
+ .mod_info = &mod_info_hpa_ffd06000,\
+ .mod_path = &mod_path_hpa_ffd06000,\
+ .num_addr = HPA_ffd06000_num_addr,\
+ .add_addr = { HPA_ffd06000_add_addr } },\
+ { .hpa = 0xffd07000,\
+ .iodc = &iodc_data_hpa_ffd07000,\
+ .mod_info = &mod_info_hpa_ffd07000,\
+ .mod_path = &mod_path_hpa_ffd07000,\
+ .num_addr = HPA_ffd07000_num_addr,\
+ .add_addr = { HPA_ffd07000_add_addr } },\
+ { .hpa = 0xffd02000,\
+ .iodc = &iodc_data_hpa_ffd02000,\
+ .mod_info = &mod_info_hpa_ffd02000,\
+ .mod_path = &mod_path_hpa_ffd02000,\
+ .num_addr = HPA_ffd02000_num_addr,\
+ .add_addr = { HPA_ffd02000_add_addr } },\
+ { .hpa = 0xffd04000,\
+ .iodc = &iodc_data_hpa_ffd04000,\
+ .mod_info = &mod_info_hpa_ffd04000,\
+ .mod_path = &mod_path_hpa_ffd04000,\
+ .num_addr = HPA_ffd04000_num_addr,\
+ .add_addr = { HPA_ffd04000_add_addr } },\
+ { .hpa = 0xffd08000,\
+ .iodc = &iodc_data_hpa_ffd08000,\
+ .mod_info = &mod_info_hpa_ffd08000,\
+ .mod_path = &mod_path_hpa_ffd08000,\
+ .num_addr = HPA_ffd08000_num_addr,\
+ .add_addr = { HPA_ffd08000_add_addr } },\
+ { .hpa = 0xffd08100,\
+ .iodc = &iodc_data_hpa_ffd08100,\
+ .mod_info = &mod_info_hpa_ffd08100,\
+ .mod_path = &mod_path_hpa_ffd08100,\
+ .num_addr = HPA_ffd08100_num_addr,\
+ .add_addr = { HPA_ffd08100_add_addr } },\
+ { .hpa = 0xfa000000,\
+ .iodc = &iodc_data_hpa_fa000000,\
+ .mod_info = &mod_info_hpa_fa000000,\
+ .mod_path = &mod_path_hpa_fa000000,\
+ .num_addr = HPA_fa000000_num_addr,\
+ .add_addr = { HPA_fa000000_add_addr } },\
+ { .hpa = 0xf4000000,\
+ .iodc = &iodc_data_hpa_f4000000,\
+ .mod_info = &mod_info_hpa_f4000000,\
+ .mod_path = &mod_path_hpa_f4000000,\
+ .num_addr = HPA_f4000000_num_addr,\
+ .add_addr = { HPA_f4000000_add_addr } },\
+ { .hpa = 0xf8000000,\
+ .iodc = &iodc_data_hpa_f8000000,\
+ .mod_info = &mod_info_hpa_f8000000,\
+ .mod_path = &mod_path_hpa_f8000000,\
+ .num_addr = HPA_f8000000_num_addr,\
+ .add_addr = { HPA_f8000000_add_addr } },\
+ { .hpa = CPU_HPA,\
+ .iodc = &iodc_data_hpa_fff10000,\
+ .mod_info = &mod_info_hpa_fff10000,\
+ .mod_path = &mod_path_hpa_fff10000,\
+ .num_addr = HPA_fff10000_num_addr,\
+ .add_addr = { HPA_fff10000_add_addr } },\
+ { .hpa = 0xfffbf000,\
+ .iodc = &iodc_data_hpa_fffbf000,\
+ .mod_info = &mod_info_hpa_fffbf000,\
+ .mod_path = &mod_path_hpa_fffbf000,\
+ .num_addr = HPA_fffbf000_num_addr,\
+ .add_addr = { HPA_fffbf000_add_addr } },\
+ { .hpa = 0xfff81000,\
+ .iodc = &iodc_data_hpa_fff81000,\
+ .mod_info = &mod_info_hpa_fff81000,\
+ .mod_path = &mod_path_hpa_fff81000,\
+ .num_addr = HPA_fff81000_num_addr,\
+ .add_addr = { HPA_fff81000_add_addr } },\
+ { 0, }
diff --git a/roms/seabios-hppa/src/parisc/head.S b/roms/seabios-hppa/src/parisc/head.S
new file mode 100644
index 000000000..48699463a
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/head.S
@@ -0,0 +1,319 @@
+/*
+ * Startup glue code for parisc firmware
+ *
+ * (C) 2017-2021 Helge Deller <deller@gmx.de>
+ */
+
+#include "parisc/hppa_hardware.h"
+#include "autoconf.h"
+#include "autoversion.h"
+
+ /* load 32-bit 'value' into 'reg' compensating for the ldil
+ * sign-extension when running in wide mode.
+ * WARNING!! neither 'value' nor 'reg' can be expressions
+ * containing '.'!!!! */
+ .macro load32 value, reg
+ ldil L%\value, \reg
+ ldo R%\value(\reg), \reg
+ .endm
+
+#define ENTRY(name) \
+ .export name !\
+ .align 4 !\
+name:
+
+#define END(name) \
+ .size name, .-name
+
+#define ENDPROC(name) \
+ .type name, @function !\
+ END(name)
+
+#define BOOTADDR(x) (x)
+
+ .macro loadgp
+ ldil L%$global$, %r27
+ ldo R%$global$(%r27), %r27
+ .endm
+
+#ifdef CONFIG_64BIT
+#define LDREG ldd
+#define STREG std
+#define LDREGX ldd,s
+#define LDREGM ldd,mb
+#define STREGM std,ma
+#define SHRREG shrd
+#define SHLREG shld
+#define ANDCM andcm,*
+#define COND(x) * ## x
+#define RP_OFFSET 16
+#define FRAME_SIZE 128
+#define CALLEE_REG_FRAME_SIZE 144
+#define ASM_ULONG_INSN .dword
+#else /* CONFIG_64BIT */
+#define LDREG ldw
+#define STREG stw
+#define LDREGX ldwx,s
+#define LDREGM ldwm
+#define STREGM stwm
+#define SHRREG shr
+#define SHLREG shlw
+#define ANDCM andcm
+#define COND(x) x
+#define RP_OFFSET 20
+#define FRAME_SIZE 64
+#define CALLEE_REG_FRAME_SIZE 128
+#define ASM_ULONG_INSN .word
+#endif
+
+ .import $global$
+ .section ".head.text","ax"
+ .level 1.1
+
+ /* On HPMC, the CPUs will start here at 0xf0000000 */
+hpmc_entry:
+ b,n . /* TODO! */
+
+reset_entry:
+ /* at reset, the CPU begins fetching instructions from address 0xf0000004. */
+ b,n startup
+
+ /* file identification */
+ .stringz "PA-RISC/HPPA PDC Firmware (SeaBIOS fork)"
+ .stringz "https://github.com/hdeller/seabios-hppa"
+ .stringz BUILD_VERSION
+
+/*******************************************************
+ Firmware startup code
+ *******************************************************/
+
+ .align 0x80
+ENTRY(startup)
+ /* Make sure space registers are set to zero */
+ mtsp %r0,%sr0
+ mtsp %r0,%sr1
+ mtsp %r0,%sr2
+ mtsp %r0,%sr3
+ mtsp %r0,%sr4
+ mtsp %r0,%sr5
+ mtsp %r0,%sr6
+ mtsp %r0,%sr7
+
+#define PSW_W_SM 0x200
+#define PSW_W_BIT 36
+
+ ;! nuke the W bit
+ .level 2.0
+ rsm PSW_W_SM, %r0
+ .level 1.1
+
+ /* Save CPU HPA in cr7, hopefully HP-UX will not use that register. */
+ mtctl %r5, CPU_HPA_CR_REG /* store CPU HPA */
+
+ /* branch if this is the monarch cpu */
+ load32 CPU_HPA,%r1
+ comb,= %r5,%r1,$is_monarch_cpu
+ nop
+
+ENTRY(enter_smp_idle_loop)
+ /* IDLE LOOP for SMP CPUs - wait for rendenzvous. */
+ mfctl CPU_HPA_CR_REG, %r25 /* get CPU HPA from cr7 */
+
+ /* Load IVT for SMT tiny loop exit */
+#define CR_IVA 14
+ load32 BOOTADDR(smp_ivt),%r1
+ mtctl %r1, CR_IVA
+
+ /* enable CPU local interrupts */
+#define CR_EIEM 15
+#define PSW_I 1
+ ldi -1, %r1 /* allow IRQ0 (Timer) */
+ mtctl %r1, CR_EIEM
+ ssm PSW_I, %r9
+
+ /* endless idle loop, exits to $smp_exit_loop by IRQ only */
+$smp_idle_loop:
+ b $smp_idle_loop
+ or %r10,%r10,%r10
+
+$smp_exit_loop:
+ mtsm %r9
+ mtctl %r0, CR_EIEM
+
+ /* on 64bit: Address of PDCE_PROC for each non-monarch processor in GR26. */
+ load32 BOOTADDR(pdc_entry), %r26
+
+ /* jump to rendevouz */
+ ldw 0x10(%r0),%r3 /* MEM_RENDEZ */
+ /* ldw 0x28(%r0),%r0 MEM_RENDEZ_HI - assume addr < 4GB */
+ bv 0(%r3)
+ copy %r0,%r2
+
+
+$is_monarch_cpu:
+ /* Initialize stack pointer */
+ load32 BOOTADDR(parisc_stack),%r1
+ ldo FRAME_SIZE(%r1),%sp
+
+ /* Initialize the global data pointer */
+ loadgp
+
+ /* Clear BSS on monarch CPU */
+ .import _bss,data
+ .import _ebss,data
+
+ load32 BOOTADDR(_bss),%r3
+ load32 BOOTADDR(_ebss),%r4
+$bss_loop:
+ cmpb,<<,n %r3,%r4,$bss_loop
+ stw,ma %r0,4(%r3)
+
+ /* Save boot args */
+ load32 BOOTADDR(boot_args),%r1
+ stw,ma %r26,4(%r1)
+ stw,ma %r25,4(%r1)
+ stw,ma %r24,4(%r1)
+ stw,ma %r23,4(%r1)
+ stw,ma %r22,4(%r1)
+ stw,ma %r21,4(%r1)
+ stw,ma %r20,4(%r1)
+ stw,ma %r19,4(%r1)
+
+ load32 BOOTADDR(start_parisc_firmware),%r3
+ bv 0(%r3)
+ copy %r0,%r2
+END(startup)
+
+
+/*******************************************************
+ SMP Interrupt vector table (IVT)
+ *******************************************************/
+
+ .macro DEF_IVA_ENTRY
+ .align 32
+ load32 BOOTADDR($smp_exit_loop),%r1
+ bv 0(%r1)
+ nop
+ .endm
+
+ .align 32 /* should be 4k aligned but qemu does not check */
+ENTRY(smp_ivt)
+ .rept 32
+ DEF_IVA_ENTRY
+ .endr
+END(smp_ivt)
+
+
+/*******************************************************
+ PDC and IODC entry
+ *******************************************************/
+
+ENTRY(pdc_entry)
+ stw %rp,-20(%sp)
+ stw %dp,-32(%sp)
+ stw %arg0,-36(%sp)
+ stw %arg1,-40(%sp)
+ stw %arg2,-44(%sp)
+ stw %arg3,-48(%sp)
+ ldo -FRAME_SIZE(%sp),%arg0
+
+ loadgp
+ b,l parisc_pdc_entry, %rp
+ ldo FRAME_SIZE(%sp),%sp
+
+ ldo -FRAME_SIZE(%sp),%sp
+ ldw -20(%sp),%rp
+ bv %r0(%rp)
+ ldw -32(%sp),%dp
+END(pdc_entry)
+
+/* pdc_entry_table will be copied into low memory. */
+ENTRY(pdc_entry_table)
+ load32 pdc_entry,%r1
+ bv,n %r0(%r1)
+END(pdc_entry_table)
+
+ENTRY(iodc_entry_table)
+ load32 parisc_iodc_ENTRY_INIT, %r1
+ load32 parisc_iodc_ENTRY_IO, %r1
+ load32 parisc_iodc_ENTRY_SPA, %r1
+ load32 parisc_iodc_ENTRY_CONFIG, %r1
+ load32 hlt, %r1 /* obsolete */
+ load32 parisc_iodc_ENTRY_TEST, %r1
+ load32 parisc_iodc_ENTRY_TLB, %r1
+END(iodc_entry_table)
+
+ENTRY(iodc_entry)
+ load32 parisc_iodc_ENTRY_IO, %r1
+
+ stw %rp,-20(%sp)
+ stw %dp,-32(%sp)
+ stw %arg0,-36(%sp)
+ stw %arg1,-40(%sp)
+ stw %arg2,-44(%sp)
+ stw %arg3,-48(%sp)
+ ldo -FRAME_SIZE(%sp),%arg0
+
+ loadgp
+ load32 .iodc_ret, %rp
+ bv %r0(%r1)
+ ldo FRAME_SIZE(%sp),%sp
+.iodc_ret:
+ ldo -FRAME_SIZE(%sp),%sp
+ ldw -20(%sp),%rp
+ bv %r0(%rp)
+ ldw -32(%sp),%dp
+END(iodc_entry)
+
+ .data
+ENTRY(boot_args)
+ .word 0 /* r26: ramsize */
+ .word 0 /* r25: kernel entry point */
+ .word 0 /* r24: cmdline */
+ .word 0 /* r23: initrd_start */
+ .word 0 /* r22: initrd_end */
+ .word 0 /* r21: num CPUs */
+ .word 0 /* r20: pdc_debug */
+ .word 0 /* r19: fw_cfg port */
+END(boot_args)
+
+
+/****************************************************************
+ * Rom Header for VGA / STI
+ ****************************************************************/
+
+#if 0 // def CONFIG_BUILD_VGABIOS
+
+ .section .rom.header
+ .global _rom_header, _rom_header_size, _rom_header_checksum
+_rom_header:
+ .word 0xaa55
+_rom_header_size:
+ .byte 0
+_rom_header_entry:
+ .word _optionrom_entry // b,n ?
+_rom_header_checksum:
+ .byte 0
+_rom_header_other:
+ .space 17
+_rom_header_pcidata:
+#if CONFIG_VGA_PCI == 1
+ .word rom_pci_data
+#else
+ .word 0
+#endif
+_rom_header_pnpdata:
+ .word 0
+_rom_header_other2:
+ .word 0
+_rom_header_signature:
+ .asciz "IBM"
+
+
+ENTRY(_optionrom_entry)
+ .import vga_post
+ load32 BOOTADDR(vga_post), %r1
+ bv,n %r0(%r1)
+END(_optionrom_entry)
+
+#endif /* CONFIG_BUILD_VGABIOS */
diff --git a/roms/seabios-hppa/src/parisc/hppa.h b/roms/seabios-hppa/src/parisc/hppa.h
new file mode 100644
index 000000000..ca81a4396
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/hppa.h
@@ -0,0 +1,375 @@
+#ifndef HPPA_H
+#define HPPA_H
+/* this file is included by x86.h */
+
+#include "parisc/hppa_hardware.h"
+
+#ifndef __ASSEMBLY__
+
+#include "types.h" // u32
+#include "byteorder.h" // le16_to_cpu
+
+#define PSW_I 0x00000001
+
+static inline unsigned long arch_local_save_flags(void)
+{
+ unsigned long flags;
+ asm volatile("ssm 0, %0" : "=r" (flags) : : "memory");
+ return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+ asm volatile("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+ asm volatile("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory");
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+ unsigned long flags;
+ asm volatile("rsm %1,%0" : "=r" (flags) : "i" (PSW_I) : "memory");
+ return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+ asm volatile("mtsm %0" : : "r" (flags) : "memory");
+}
+
+static inline void irq_disable(void)
+{
+ arch_local_irq_disable();
+}
+
+static inline void irq_enable(void)
+{
+ arch_local_irq_enable();
+}
+
+static inline u32 save_flags(void)
+{
+ return arch_local_irq_save();
+}
+
+static inline void restore_flags(u32 flags)
+{
+ arch_local_irq_restore(flags);
+}
+
+
+
+static inline void cpu_relax(void)
+{
+ asm volatile("nop": : :"memory");
+}
+
+static inline void nop(void)
+{
+ asm volatile("nop");
+}
+
+extern void hlt(void);
+
+static inline void wbinvd(void)
+{
+ asm volatile("sync": : :"memory");
+}
+
+#define mfctl(reg) ({ \
+ unsigned long cr; \
+ __asm__ __volatile__( \
+ "mfctl %1,%0" : \
+ "=r" (cr) : "i" (reg) \
+ ); \
+ cr; \
+})
+
+#define mtctl(gr, cr) \
+ __asm__ __volatile__("mtctl %0,%1" \
+ : /* no outputs */ \
+ : "r" (gr), "i" (cr) : "memory")
+
+/* these are here to de-mystefy the calling code, and to provide hooks */
+/* which I needed for debugging EIEM problems -PB */
+#define get_eiem() mfctl(15)
+static inline void set_eiem(unsigned long val)
+{
+ mtctl(val, 15);
+}
+
+#define mfsp(reg) ({ \
+ unsigned long cr; \
+ __asm__ __volatile__( \
+ "mfsp " #reg ",%0" : \
+ "=r" (cr) \
+ ); \
+ cr; \
+})
+
+#define mtsp(val, cr) \
+ { if (__builtin_constant_p(val) && ((val) == 0)) \
+ __asm__ __volatile__("mtsp %%r0,%0" : : "i" (cr) : "memory"); \
+ else \
+ __asm__ __volatile__("mtsp %0,%1" \
+ : /* no outputs */ \
+ : "r" (val), "i" (cr) : "memory"); }
+
+static inline unsigned long rdtscll(void)
+{
+ return mfctl(16);
+}
+
+static inline u32 __ffs(u32 x)
+{
+ unsigned long ret;
+
+ if (!x)
+ return 0;
+
+ __asm__(
+#ifdef CONFIG_64BIT
+ " ldi 63,%1\n"
+ " extrd,u,*<> %0,63,32,%%r0\n"
+ " extrd,u,*TR %0,31,32,%0\n" /* move top 32-bits down */
+ " addi -32,%1,%1\n"
+#else
+ " ldi 31,%1\n"
+#endif
+ " extru,<> %0,31,16,%%r0\n"
+ " extru,TR %0,15,16,%0\n" /* xxxx0000 -> 0000xxxx */
+ " addi -16,%1,%1\n"
+ " extru,<> %0,31,8,%%r0\n"
+ " extru,TR %0,23,8,%0\n" /* 0000xx00 -> 000000xx */
+ " addi -8,%1,%1\n"
+ " extru,<> %0,31,4,%%r0\n"
+ " extru,TR %0,27,4,%0\n" /* 000000x0 -> 0000000x */
+ " addi -4,%1,%1\n"
+ " extru,<> %0,31,2,%%r0\n"
+ " extru,TR %0,29,2,%0\n" /* 0000000y, 1100b -> 0011b */
+ " addi -2,%1,%1\n"
+ " extru,= %0,31,1,%%r0\n" /* check last bit */
+ " addi -1,%1,%1\n"
+ : "+r" (x), "=r" (ret) );
+ return ret;
+}
+
+static inline u32 __fls(u32 x)
+{
+ int ret;
+ if (!x)
+ return 0;
+
+ __asm__(
+ " ldi 1,%1\n"
+ " extru,<> %0,15,16,%%r0\n"
+ " zdep,TR %0,15,16,%0\n" /* xxxx0000 */
+ " addi 16,%1,%1\n"
+ " extru,<> %0,7,8,%%r0\n"
+ " zdep,TR %0,23,24,%0\n" /* xx000000 */
+ " addi 8,%1,%1\n"
+ " extru,<> %0,3,4,%%r0\n"
+ " zdep,TR %0,27,28,%0\n" /* x0000000 */
+ " addi 4,%1,%1\n"
+ " extru,<> %0,1,2,%%r0\n"
+ " zdep,TR %0,29,30,%0\n" /* y0000000 (y&3 = 0) */
+ " addi 2,%1,%1\n"
+ " extru,= %0,0,1,%%r0\n"
+ " addi 1,%1,%1\n" /* if y & 8, add 1 */
+ : "+r" (x), "=r" (ret) );
+
+ return ret;
+}
+
+static inline u32 rol(u32 val, u16 rol) {
+ u32 res, resr;
+ res = val << rol;
+ resr = val >> (32-rol);
+ res |= resr;
+ return res;
+}
+
+static inline u32 ror(u32 word, unsigned int shift)
+{
+ return (word >> (shift & 31)) | (word << ((-shift) & 31));
+}
+
+#define pci_ioport_addr(port) ((port >= 0x1000) && (port < FIRMWARE_START))
+
+static inline void outl(u32 value, portaddr_t port) {
+ if (!pci_ioport_addr(port)) {
+ *(volatile u32 *)(port) = be32_to_cpu(value);
+ } else {
+ /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */
+ outl(port, DINO_HPA + 0x064);
+ /* write value to PCI_IO_DATA */
+ outl(value, DINO_HPA + 0x06c);
+ }
+}
+
+static inline void outw(u16 value, portaddr_t port) {
+ if (!pci_ioport_addr(port)) {
+ *(volatile u16 *)(port) = be16_to_cpu(value);
+ } else {
+ /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */
+ outl(port, DINO_HPA + 0x064);
+ /* write value to PCI_IO_DATA */
+ outw(value, DINO_HPA + 0x06c);
+ }
+}
+
+static inline void outb(u8 value, portaddr_t port) {
+ if (!pci_ioport_addr(port)) {
+ *(volatile u8 *)(port) = value;
+ } else {
+ /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */
+ outl(port & ~3U, DINO_HPA + 0x064);
+ /* write value to PCI_IO_DATA */
+ outb(value, DINO_HPA + 0x06c + (port & 3));
+ }
+}
+
+static inline u8 inb(portaddr_t port) {
+ if (!pci_ioport_addr(port)) {
+ return *(volatile u8 *)(port);
+ } else {
+ /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */
+ outl(port & ~3U, DINO_HPA + 0x064);
+ /* read value to PCI_IO_DATA */
+ return inb(DINO_HPA + 0x06c + (port & 3));
+ }
+}
+
+static inline u16 inw(portaddr_t port) {
+ if (!pci_ioport_addr(port)) {
+ return *(volatile u16 *)(port);
+ } else {
+ /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */
+ outl(port & ~3U, DINO_HPA + 0x064);
+ /* read value to PCI_IO_DATA */
+ return inw(DINO_HPA + 0x06c + (port & 3));
+ }
+}
+static inline u32 inl(portaddr_t port) {
+ if (!pci_ioport_addr(port)) {
+ return *(volatile u32 *)(port);
+ } else {
+ /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */
+ outl(port & ~3U, DINO_HPA + 0x064);
+ /* read value to PCI_IO_DATA */
+ return inl(DINO_HPA + 0x06c + (port & 3));
+ }
+}
+
+static inline void insb(portaddr_t port, u8 *data, u32 count) {
+ while (count--)
+ *data++ = inb(port);
+}
+static inline void insw(portaddr_t port, u16 *data, u32 count) {
+ while (count--)
+ if (pci_ioport_addr(port))
+ *data++ = be16_to_cpu(inw(port));
+ else
+ *data++ = inw(port);
+}
+static inline void insl(portaddr_t port, u32 *data, u32 count) {
+ while (count--)
+ if (pci_ioport_addr(port))
+ *data++ = be32_to_cpu(inl(port));
+ else
+ *data++ = inl(port);
+}
+// XXX - outs not limited to es segment
+static inline void outsb(portaddr_t port, u8 *data, u32 count) {
+ while (count--)
+ outb(*data++, port);
+}
+static inline void outsw(portaddr_t port, u16 *data, u32 count) {
+ while (count--) {
+ if (pci_ioport_addr(port))
+ outw(cpu_to_be16(*data), port);
+ else
+ outw(*data, port);
+ data++;
+ }
+}
+static inline void outsl(portaddr_t port, u32 *data, u32 count) {
+ while (count--) {
+ if (pci_ioport_addr(port))
+ outl(cpu_to_be32(*data), port);
+ else
+ outl(*data, port);
+ data++;
+ }
+}
+
+/* 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;
+}
+static inline void writew(void *addr, u16 val) {
+ barrier();
+ *(volatile u16 *)addr = val;
+}
+static inline void writeb(void *addr, u8 val) {
+ barrier();
+ *(volatile u8 *)addr = val;
+}
+static inline u64 readq(const void *addr) {
+ u64 val = *(volatile const u64 *)addr;
+ barrier();
+ return val;
+}
+static inline u32 readl(const void *addr) {
+ u32 val = *(volatile const u32 *)addr;
+ barrier();
+ return val;
+}
+static inline u16 readw(const void *addr) {
+ u16 val = *(volatile const u16 *)addr;
+ barrier();
+ return val;
+}
+static inline u8 readb(const void *addr) {
+ u8 val = *(volatile const u8 *)addr;
+ barrier();
+ return val;
+}
+
+// FLASH_FLOPPY not supported
+#define GDT_CODE (0)
+#define GDT_DATA (0)
+#define GDT_B (0)
+#define GDT_G (0)
+#define GDT_BASE(v) ((v) & 0)
+#define GDT_LIMIT(v) ((v) & 0)
+#define GDT_GRANLIMIT(v) ((v) & 0)
+
+static inline u8 get_a20(void) {
+ return 0;
+}
+
+static inline u8 set_a20(u8 cond) {
+ return 0;
+}
+
+static inline void wrmsr(u32 index, u64 val)
+{
+}
+
+// x86.c
+void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx);
+
+#endif // !__ASSEMBLY__
+#endif
diff --git a/roms/seabios-hppa/src/parisc/hppa_hardware.h b/roms/seabios-hppa/src/parisc/hppa_hardware.h
new file mode 100644
index 000000000..099a49228
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/hppa_hardware.h
@@ -0,0 +1,49 @@
+/* HPPA cores and system support chips. */
+
+#ifndef HW_HPPA_HPPA_HARDWARE_H
+#define HW_HPPA_HPPA_HARDWARE_H
+
+#define FIRMWARE_START 0xf0000000
+#define FIRMWARE_END 0xf0800000
+
+#define DEVICE_HPA_LEN 0x00100000
+
+#define GSC_HPA 0xffc00000
+#define DINO_HPA 0xfff80000
+#define DINO_UART_HPA 0xfff83000
+#define DINO_UART_BASE 0xfff83800
+#define DINO_SCSI_HPA 0xfff8c000
+#define LASI_HPA 0xffd00000
+#define LASI_UART_HPA 0xffd05000
+#define LASI_SCSI_HPA 0xffd06000
+#define LASI_LAN_HPA 0xffd07000
+#define LASI_RTC_HPA 0xffd09000
+#define LASI_LPT_HPA 0xffd02000
+#define LASI_AUDIO_HPA 0xffd04000
+#define LASI_PS2KBD_HPA 0xffd08000
+#define LASI_PS2MOU_HPA 0xffd08100
+#define LASI_GFX_HPA 0xf8000000
+#define ARTIST_FB_ADDR 0xf9000000
+#define CPU_HPA 0xfffb0000
+#define MEMORY_HPA 0xfffbf000
+
+#define PCI_HPA DINO_HPA /* PCI bus */
+#define IDE_HPA 0xf9000000 /* Boot disc controller */
+
+/* offsets to DINO HPA: */
+#define DINO_PCI_ADDR 0x064
+#define DINO_CONFIG_DATA 0x068
+#define DINO_IO_DATA 0x06c
+
+#define PORT_PCI_CMD (PCI_HPA + DINO_PCI_ADDR)
+#define PORT_PCI_DATA (PCI_HPA + DINO_CONFIG_DATA)
+
+#define PORT_SERIAL1 (DINO_UART_HPA + 0x800)
+#define PORT_SERIAL2 (LASI_UART_HPA + 0x800)
+
+#define HPPA_MAX_CPUS 8 /* max. number of SMP CPUs */
+#define CPU_CLOCK_MHZ 250 /* emulate a 250 MHz CPU */
+
+#define CPU_HPA_CR_REG 7 /* store CPU HPA in cr7 (SeaBIOS internal) */
+
+#endif
diff --git a/roms/seabios-hppa/src/parisc/lasips2.c b/roms/seabios-hppa/src/parisc/lasips2.c
new file mode 100644
index 000000000..119c21468
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/lasips2.c
@@ -0,0 +1,66 @@
+/* LASI PS2 keyboard support code
+ *
+ * Copyright (C) 2019 Sven Schnelle <svens@stackframe.org>
+ *
+ * This file may be distributed under the terms of the GNU LGPLv2 license.
+ */
+
+#include "bregs.h"
+#include "autoconf.h"
+#include "types.h"
+#include "output.h"
+#include "hw/ps2port.h"
+#include "util.h"
+#include "string.h"
+#include "lasips2.h"
+
+int lasips2_kbd_in(char *c, int max)
+{
+ struct bregs regs;
+ volatile int count = 0;
+
+ while((readl(LASIPS2_KBD_STATUS) & LASIPS2_KBD_STATUS_RBNE)) {
+ process_key(readb(LASIPS2_KBD_DATA));
+ }
+
+ while(count < max) {
+ memset(&regs, 0, sizeof(regs));
+ regs.ah = 0x10;
+ handle_16(&regs);
+ if (!regs.ah)
+ break;
+ *c++ = regs.ah;
+ count++;
+ }
+ return count;
+}
+
+
+int ps2_kbd_command(int command, u8 *param)
+{
+ return 0;
+}
+
+int lasips2_command(u16 cmd)
+{
+ while(readl(LASIPS2_KBD_STATUS) & LASIPS2_KBD_STATUS_TBNE)
+ udelay(10);
+ writeb(LASIPS2_KBD_DATA, cmd & 0xff);
+
+ while(!(readl(LASIPS2_KBD_STATUS) & LASIPS2_KBD_STATUS_RBNE))
+ udelay(10);
+ return readb(LASIPS2_KBD_DATA);
+}
+
+void ps2port_setup(void)
+{
+ writeb(LASIPS2_KBD_RESET, 0);
+ udelay(1000);
+ writeb(LASIPS2_KBD_CONTROL, LASIPS2_KBD_CONTROL_EN);
+ lasips2_command(ATKBD_CMD_RESET_BAT);
+ lasips2_command(ATKBD_CMD_RESET_DIS);
+ lasips2_command(ATKBD_CMD_SSCANSET);
+ lasips2_command(0x01);
+ lasips2_command(ATKBD_CMD_ENABLE);
+ kbd_init();
+}
diff --git a/roms/seabios-hppa/src/parisc/lasips2.h b/roms/seabios-hppa/src/parisc/lasips2.h
new file mode 100644
index 000000000..efdd66b93
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/lasips2.h
@@ -0,0 +1,17 @@
+#ifndef PARISC_LASIPS2_H
+#define PARISC_LASIPS2_H
+
+void ps2port_setup(void);
+
+int lasips2_kbd_in(char *c, int max);
+
+#define LASIPS2_KBD_RESET ((void *)(LASI_PS2KBD_HPA+0x00))
+#define LASIPS2_KBD_DATA ((void *)(LASI_PS2KBD_HPA+0x04))
+#define LASIPS2_KBD_CONTROL ((void *)(LASI_PS2KBD_HPA+0x08))
+#define LASIPS2_KBD_STATUS ((void *)(LASI_PS2KBD_HPA+0x0c))
+
+#define LASIPS2_KBD_CONTROL_EN 0x01
+#define LASIPS2_KBD_STATUS_RBNE 0x01
+#define LASIPS2_KBD_STATUS_TBNE 0x02
+
+#endif
diff --git a/roms/seabios-hppa/src/parisc/malloc.c b/roms/seabios-hppa/src/parisc/malloc.c
new file mode 100644
index 000000000..c4e46e622
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/malloc.c
@@ -0,0 +1,91 @@
+// Internal dynamic memory allocations.
+//
+// Copyright (C) 2009-2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#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" // PAGE_SIZE
+#include "output.h" // dprintf
+#include "stacks.h" // wait_preempt
+#include "std/optionrom.h" // OPTION_ROM_ALIGN
+#include "string.h" // memset
+
+static unsigned long stackptr;
+
+/****************************************************************
+ * tracked memory allocations
+ ****************************************************************/
+
+// Allocate physical memory from the given zone and track it as a PMM allocation
+unsigned long
+malloc_palloc(struct zone_s *zone, u32 size, u32 align)
+{
+ unsigned long data;
+
+ ASSERT32FLAT();
+ if (!size)
+ return 0;
+
+ stackptr = (stackptr + align-1) & ~(align-1);
+ data = stackptr;
+ stackptr += size;
+
+ dprintf(8, "size=%d align=%d ret=0x%lx\n" , size, align, data);
+
+ return data;
+}
+
+// Allocate virtual memory from the given zone
+void * __malloc
+parisc_malloc(u32 size, u32 align)
+{
+ return (void*) malloc_palloc(NULL, size, align);
+}
+
+// Free a data block allocated with phys_alloc
+int
+malloc_pfree(u32 data)
+{
+ return 0;
+}
+
+void
+free(void *data)
+{
+}
+
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+void
+malloc_preinit(void)
+{
+ ASSERT32FLAT();
+ dprintf(3, "malloc preinit\n");
+ extern u8 _ebss;
+ stackptr = (unsigned long) &_ebss;
+}
+
+u32 LegacyRamSize VARFSEG;
+
+void
+malloc_init(void)
+{
+ ASSERT32FLAT();
+ dprintf(3, "malloc init\n");
+}
+
+void
+malloc_prepboot(void)
+{
+ ASSERT32FLAT();
+ dprintf(3, "malloc finalize\n");
+}
diff --git a/roms/seabios-hppa/src/parisc/pafirmware.lds.S b/roms/seabios-hppa/src/parisc/pafirmware.lds.S
new file mode 100644
index 000000000..e246c84a2
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/pafirmware.lds.S
@@ -0,0 +1,69 @@
+#include "parisc/hppa_hardware.h"
+
+OUTPUT_FORMAT("elf32-hppa-linux")
+OUTPUT_ARCH(hppa)
+ENTRY(startup)
+SECTIONS
+{
+ . = FIRMWARE_START;
+
+ /* align on next page boundary */
+ . = ALIGN(4096);
+ .text : {
+ _text = .; /* Text */
+ *(.head.text)
+ *(.text)
+ *(.text.*)
+ _etext = . ;
+ }
+
+ . = ALIGN(4096);
+ .sti : {
+ _sti_rom_start = .;
+ *(.sti.hdr)
+ *(.sti.text.init_graph)
+ *(.sti.text.state_mgmt)
+ *(.sti.text.font_unpmv)
+ *(.sti.text.block_move)
+ *(.sti.text.self_test)
+ *(.sti.text.excep_hdlr)
+ *(.sti.text.inq_conf)
+ *(.sti.text.set_cm_entry)
+ *(.sti.text.dma_ctrl)
+ *(.sti.text)
+ *(.sti.data)
+ *(.sti.text.end)
+ . = ALIGN(4096);
+ _sti_rom_end = .;
+ }
+
+ . = ALIGN(8);
+ .rodata : {
+ _rodata = . ;
+ *(.rodata) /* read-only data */
+ *(.rodata.*)
+ _erodata = . ;
+ }
+ . = ALIGN(8);
+ .data : {
+ _data = . ;
+ *(.data)
+ *(.data.*)
+ _edata = . ;
+ }
+ . = ALIGN(8);
+ .bss : {
+ _bss = . ;
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ _ebss = .;
+ }
+
+ /* STABS_DEBUG */
+ .note 0 : { *(.note) }
+
+ /* Sections to be discarded */
+ /DISCARD/ : {
+ }
+}
diff --git a/roms/seabios-hppa/src/parisc/parisc.c b/roms/seabios-hppa/src/parisc/parisc.c
new file mode 100644
index 000000000..2715c8e59
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/parisc.c
@@ -0,0 +1,2002 @@
+// Glue code for parisc architecture
+//
+// Copyright (C) 2017-2021 Helge Deller <deller@gmx.de>
+// Copyright (C) 2019 Sven Schnelle <svens@stackframe.org>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_BDA
+#include "bregs.h" // struct bregs
+#include "hw/pic.h" // enable_hwirq
+#include "output.h" // debug_enter
+#include "stacks.h" // call16_int
+#include "string.h" // memset
+#include "util.h" // serial_setup
+#include "malloc.h" // malloc
+#include "hw/serialio.h" // qemu_debug_port
+#include "hw/pcidevice.h" // foreachpci
+#include "hw/pci.h" // pci_config_readl
+#include "hw/pci_ids.h" // PCI IDs
+#include "hw/pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "hw/ata.h"
+#include "hw/blockcmd.h" // scsi_is_ready()
+#include "hw/rtc.h"
+#include "fw/paravirt.h" // PlatformRunningOn
+#include "vgahw.h"
+#include "parisc/hppa_hardware.h" // DINO_UART_BASE
+#include "parisc/pdc.h"
+#include "parisc/b160l.h"
+#include "parisc/sticore.h"
+#include "parisc/lasips2.h"
+
+#include "vgabios.h"
+
+#define SEABIOS_HPPA_VERSION 2
+
+/*
+ * Various variables which are needed by x86 code.
+ * Defined here to be able to link seabios.
+ */
+int HaveRunPost;
+u8 ExtraStack[BUILD_EXTRA_STACK_SIZE+1] __aligned(8);
+u8 *StackPos;
+u8 __VISIBLE parisc_stack[32*1024] __aligned(64);
+
+u8 BiosChecksum;
+
+char zonefseg_start, zonefseg_end; // SYMBOLS
+char varlow_start, varlow_end, final_varlow_start;
+char final_readonly_start;
+char code32flat_start, code32flat_end;
+char zonelow_base;
+
+struct bios_data_area_s __VISIBLE bios_data_area;
+struct vga_bda_s __VISIBLE vga_bios_data_area;
+struct floppy_dbt_s diskette_param_table;
+struct bregs regs;
+unsigned long parisc_vga_mem;
+unsigned long parisc_vga_mmio;
+struct segoff_s ivt_table[256];
+
+void mtrr_setup(void) { }
+void mouse_init(void) { }
+void pnp_init(void) { }
+u16 get_pnp_offset(void) { return 0; }
+void mathcp_setup(void) { }
+void smp_setup(void) { }
+void bios32_init(void) { }
+void yield_toirq(void) { }
+void farcall16(struct bregs *callregs) { }
+void farcall16big(struct bregs *callregs) { }
+void mutex_lock(struct mutex_s *mutex) { }
+void mutex_unlock(struct mutex_s *mutex) { }
+void start_preempt(void) { }
+void finish_preempt(void) { }
+int wait_preempt(void) { return 0; }
+
+void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
+{
+ *eax = *ebx = *ecx = *edx = 0;
+}
+
+void wrmsr_smp(u32 index, u64 val) { }
+
+/********************************************************
+ * PA-RISC specific constants and functions.
+ ********************************************************/
+
+/* Pointer to zero-page of PA-RISC */
+#define PAGE0 ((volatile struct zeropage *) 0UL)
+
+/* variables provided by qemu */
+extern unsigned long boot_args[];
+#define ram_size (boot_args[0])
+#define linux_kernel_entry (boot_args[1])
+#define cmdline (boot_args[2])
+#define initrd_start (boot_args[3])
+#define initrd_end (boot_args[4])
+#define smp_cpus (boot_args[5])
+#define pdc_debug (boot_args[6])
+#define fw_cfg_port (boot_args[7])
+
+/* flags for pdc_debug */
+#define DEBUG_PDC 0x0001
+#define DEBUG_IODC 0x0002
+
+unsigned long PORT_QEMU_CFG_CTL;
+unsigned int tlb_entries = 256;
+unsigned int btlb_entries = 8;
+
+#define PARISC_SERIAL_CONSOLE PORT_SERIAL1
+
+extern char pdc_entry;
+extern char pdc_entry_table[12];
+extern char iodc_entry[512];
+extern char iodc_entry_table[14*4];
+
+/* args as handed over for firmware calls */
+#define ARG0 arg[7-0]
+#define ARG1 arg[7-1]
+#define ARG2 arg[7-2]
+#define ARG3 arg[7-3]
+#define ARG4 arg[7-4]
+#define ARG5 arg[7-5]
+#define ARG6 arg[7-6]
+#define ARG7 arg[7-7]
+
+/* size of I/O block used in HP firmware */
+#define FW_BLOCKSIZE 2048
+
+#define MIN_RAM_SIZE (16*1024*1024) // 16 MB
+
+#define MEM_PDC_ENTRY 0x4800 /* as in a B160L */
+
+#define CPU_HPA_IDX(i) (CPU_HPA + (i)*0x1000) /* CPU_HPA of CPU#i */
+
+static int index_of_CPU_HPA(unsigned long hpa) {
+ int i;
+ for (i = 0; i < smp_cpus; i++) {
+ if (hpa == CPU_HPA_IDX(i))
+ return i;
+ }
+ return -1;
+}
+
+static unsigned long GoldenMemory = MIN_RAM_SIZE;
+
+static unsigned int chassis_code = 0;
+
+/*
+ * Emulate the power switch button flag in head section of firmware.
+ * Bit 31 (the lowest bit) is the status of the power switch.
+ * This bit is "1" if the button is NOT pressed.
+ */
+int powersw_nop;
+int *powersw_ptr;
+
+void __VISIBLE __noreturn hlt(void)
+{
+ if (pdc_debug)
+ printf("HALT initiated from %p\n", __builtin_return_address(0));
+ printf("SeaBIOS wants SYSTEM HALT.\n\n");
+ asm volatile("\t.word 0xfffdead0": : :"memory");
+ while (1);
+}
+
+static void check_powersw_button(void)
+{
+ /* halt immediately if power button was pressed. */
+ if ((*powersw_ptr & 1) == 0) {
+ printf("SeaBIOS machine power switch was pressed.\n");
+ hlt();
+ }
+}
+
+void __noreturn reset(void)
+{
+ if (pdc_debug)
+ printf("RESET initiated from %p\n", __builtin_return_address(0));
+ printf("SeaBIOS wants SYSTEM RESET.\n"
+ "***************************\n");
+ check_powersw_button();
+ PAGE0->imm_soft_boot = 1;
+ asm volatile("\t.word 0xfffdead1": : :"memory");
+ while (1);
+}
+
+#undef BUG_ON
+#define BUG_ON(cond) \
+ if (unlikely(cond)) \
+{ printf("ERROR in %s:%d\n", __FUNCTION__, __LINE__); hlt(); }
+
+void flush_data_cache(char *start, size_t length)
+{
+ char *end = start + length;
+
+ do
+ {
+ asm volatile("fdc 0(%0)" : : "r" (start));
+ asm volatile("fic 0(%%sr0,%0)" : : "r" (start));
+ start += 16;
+ } while (start < end);
+ asm volatile("fdc 0(%0)" : : "r" (end));
+
+ asm ("sync");
+}
+
+void memdump(void *mem, unsigned long len)
+{
+ printf("memdump @ 0x%x : ", (unsigned int) mem);
+ while (len--) {
+ printf("0x%x ", (unsigned int) *(unsigned char *)mem);
+ mem++;
+ }
+ printf("\n");
+}
+
+/********************************************************
+ * Boot drives
+ ********************************************************/
+
+static struct drive_s *boot_drive; // really currently booted drive
+static struct drive_s *parisc_boot_harddisc; // first hard disc
+static struct drive_s *parisc_boot_cdrom; // first DVD or CD-ROM
+
+static struct pdc_module_path mod_path_emulated_drives = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0x8, 0x0, 0x0 }, .mod = 0x0 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } // first two layer entries get replaced
+};
+
+/********************************************************
+ * FIRMWARE IO Dependent Code (IODC) HANDLER
+ ********************************************************/
+
+typedef struct {
+ unsigned long hpa;
+ struct pdc_iodc *iodc;
+ struct pdc_system_map_mod_info *mod_info;
+ struct pdc_module_path *mod_path;
+ int num_addr;
+ int add_addr[5];
+} hppa_device_t;
+
+static hppa_device_t parisc_devices[HPPA_MAX_CPUS+16] = { PARISC_DEVICE_LIST };
+
+#define PARISC_KEEP_LIST \
+ GSC_HPA,\
+ DINO_HPA,\
+ DINO_UART_HPA,\
+ /* DINO_SCSI_HPA, */ \
+ LASI_HPA, \
+ LASI_UART_HPA, \
+ LASI_LAN_HPA, \
+ LASI_LPT_HPA, \
+ CPU_HPA,\
+ MEMORY_HPA,\
+ LASI_GFX_HPA,\
+ LASI_PS2KBD_HPA, \
+ LASI_PS2MOU_HPA, \
+ 0
+
+static const char *hpa_name(unsigned long hpa)
+{
+ struct pci_device *pci;
+ int i;
+
+ #define DO(x) if (hpa == x) return #x;
+ DO(GSC_HPA)
+ DO(DINO_HPA)
+ DO(DINO_UART_HPA)
+ DO(DINO_SCSI_HPA)
+ DO(CPU_HPA)
+ DO(MEMORY_HPA)
+ DO(IDE_HPA)
+ DO(LASI_HPA)
+ DO(LASI_UART_HPA)
+ DO(LASI_SCSI_HPA)
+ DO(LASI_LAN_HPA)
+ DO(LASI_LPT_HPA)
+ DO(LASI_AUDIO_HPA)
+ DO(LASI_PS2KBD_HPA)
+ DO(LASI_PS2MOU_HPA)
+ DO(LASI_GFX_HPA)
+ #undef DO
+
+ /* could be one of the SMP CPUs */
+ for (i = 1; i < smp_cpus; i++) {
+ static char CPU_TXT[] = "CPU_HPA_x";
+ if (hpa == CPU_HPA_IDX(i)) {
+ CPU_TXT[8] = '0'+i;
+ return CPU_TXT;
+ }
+ }
+
+ /* could be a PCI device */
+ foreachpci(pci) {
+ unsigned long mem, mmio;
+ mem = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0);
+ mem &= PCI_BASE_ADDRESS_MEM_MASK;
+ if (hpa == mem)
+ return "HPA_PCI_CARD_MEM";
+ mmio = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_2);
+ mmio &= PCI_BASE_ADDRESS_MEM_MASK;
+ if (hpa == mem)
+ return "HPA_PCI_CARD_MMIO";
+ }
+
+ return "UNKNOWN HPA";
+}
+
+int HPA_is_serial_device(unsigned long hpa)
+{
+ return (hpa == DINO_UART_HPA) || (hpa == LASI_UART_HPA);
+}
+
+int HPA_is_storage_device(unsigned long hpa)
+{
+ return (hpa == DINO_SCSI_HPA) || (hpa == IDE_HPA) || (hpa == LASI_SCSI_HPA);
+}
+
+int HPA_is_keyboard_device(unsigned long hpa)
+{
+ return (hpa == LASI_PS2KBD_HPA);
+}
+
+#define GFX_NUM_PAGES 0x2000
+int HPA_is_graphics_device(unsigned long hpa)
+{
+ return (hpa == LASI_GFX_HPA) || (hpa == 0xf4000000) ||
+ (hpa == 0xf8000000) || (hpa == 0xfa000000);
+}
+
+static unsigned long keep_list[] = { PARISC_KEEP_LIST };
+
+static void remove_from_keep_list(unsigned long hpa)
+{
+ int i = 0;
+
+ while (keep_list[i] && keep_list[i] != hpa)
+ i++;
+ while (keep_list[i]) {
+ ++i;
+ keep_list[i-1] = keep_list[i];
+ }
+}
+
+static int keep_this_hpa(unsigned long hpa)
+{
+ int i = 0;
+
+ while (keep_list[i]) {
+ if (keep_list[i] == hpa)
+ return 1;
+ i++;
+ }
+ return 0;
+}
+
+/* Rebuild hardware list and drop all devices which are not listed in
+ * PARISC_KEEP_LIST. Generate num_cpus CPUs. */
+static void remove_parisc_devices(unsigned int num_cpus)
+{
+ static struct pdc_system_map_mod_info modinfo[HPPA_MAX_CPUS] = { {1,}, };
+ static struct pdc_module_path modpath[HPPA_MAX_CPUS] = { {{1,}} };
+ hppa_device_t *cpu_dev = NULL;
+ unsigned long hpa;
+ int i, p, t;
+
+ /* already initialized? */
+ static int uninitialized = 1;
+ if (!uninitialized)
+ return;
+ uninitialized = 0;
+
+ /* check if qemu emulates LASI chip (LASI_IAR exists) */
+ if (*(unsigned long *)(LASI_HPA+16) == 0) {
+ remove_from_keep_list(LASI_UART_HPA);
+ remove_from_keep_list(LASI_LAN_HPA);
+ remove_from_keep_list(LASI_LPT_HPA);
+ } else {
+ /* check if qemu emulates LASI i82596 LAN card */
+ if (*(unsigned long *)(LASI_LAN_HPA+12) != 0xBEEFBABE)
+ remove_from_keep_list(LASI_LAN_HPA);
+ }
+
+ p = t = 0;
+ while ((hpa = parisc_devices[p].hpa) != 0) {
+ if (keep_this_hpa(hpa)) {
+ parisc_devices[t] = parisc_devices[p];
+ if (hpa == CPU_HPA)
+ cpu_dev = &parisc_devices[t];
+ t++;
+ }
+ p++;
+ }
+
+ /* Fix monarch CPU */
+ BUG_ON(!cpu_dev);
+ cpu_dev->mod_info->mod_addr = CPU_HPA;
+ cpu_dev->mod_path->path.mod = (CPU_HPA - DINO_HPA) / 0x1000;
+
+ /* Generate other CPU devices */
+ for (i = 1; i < num_cpus; i++) {
+ unsigned long hpa = CPU_HPA_IDX(i);
+
+ parisc_devices[t] = *cpu_dev;
+ parisc_devices[t].hpa = hpa;
+
+ modinfo[i] = *cpu_dev->mod_info;
+ modinfo[i].mod_addr = hpa;
+ parisc_devices[t].mod_info = &modinfo[i];
+
+ modpath[i] = *cpu_dev->mod_path;
+ modpath[i].path.mod = (hpa - DINO_HPA) / 0x1000;
+ parisc_devices[t].mod_path = &modpath[i];
+
+ t++;
+ }
+
+ BUG_ON(t > ARRAY_SIZE(parisc_devices));
+
+ while (t < ARRAY_SIZE(parisc_devices)) {
+ memset(&parisc_devices[t], 0, sizeof(parisc_devices[0]));
+ t++;
+ }
+}
+
+static int find_hpa_index(unsigned long hpa)
+{
+ int i;
+ if (!hpa)
+ return -1;
+ for (i = 0; i < (ARRAY_SIZE(parisc_devices)-1); i++) {
+ if (hpa == parisc_devices[i].hpa)
+ return i;
+ if (!parisc_devices[i].hpa)
+ return -1;
+ }
+ return -1;
+}
+
+static int compare_module_path(struct pdc_module_path *path,
+ struct pdc_module_path *search,
+ int check_layers)
+{
+ int i;
+
+ if (path->path.mod != search->path.mod)
+ return -1;
+
+ for(i = 0; i < ARRAY_SIZE(path->path.bc); i++) {
+ if (path->path.bc[i] != search->path.bc[i])
+ return -1;
+ }
+
+ if (check_layers) {
+ for(i = 0; i < ARRAY_SIZE(path->layers); i++) {
+ if (path->layers[i] != search->layers[i])
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static hppa_device_t *find_hppa_device_by_path(struct pdc_module_path *search,
+ unsigned long *index, int check_layers)
+{
+ hppa_device_t *dev;
+ int i;
+
+ for (i = 0; i < (ARRAY_SIZE(parisc_devices)-1); i++) {
+ dev = parisc_devices + i;
+ if (!dev->hpa)
+ continue;
+
+ if (!compare_module_path(dev->mod_path, search, check_layers)) {
+ *index = i;
+ return dev;
+ }
+ }
+ return NULL;
+}
+
+#define SERIAL_TIMEOUT 20
+static unsigned long parisc_serial_in(char *c, unsigned long maxchars)
+{
+ const portaddr_t addr = PARISC_SERIAL_CONSOLE;
+ unsigned long end = timer_calc(SERIAL_TIMEOUT);
+ unsigned long count = 0;
+ while (count < maxchars) {
+ u8 lsr = inb(addr+SEROFF_LSR);
+ if (lsr & 0x01) {
+ // Success - can read data
+ *c++ = inb(addr+SEROFF_DATA);
+ count++;
+ }
+ if (timer_check(end))
+ break;
+ }
+ return count;
+}
+
+static void parisc_serial_out(char c)
+{
+ for (;;) {
+ if (c == '\n')
+ parisc_serial_out('\r');
+ const portaddr_t addr = PORT_SERIAL1;
+ u8 lsr = inb(addr+SEROFF_LSR);
+ if ((lsr & 0x60) == 0x60) {
+ // Success - can write data
+ outb(c, addr+SEROFF_DATA);
+ break;
+ }
+ }
+}
+
+void parisc_screenc(char c)
+{
+ if (HPA_is_graphics_device(PAGE0->mem_cons.hpa))
+ sti_putc(c);
+ else
+ parisc_serial_out(c);
+}
+
+void iodc_log_call(unsigned int *arg, const char *func)
+{
+ if (pdc_debug & DEBUG_IODC) {
+ printf("\nIODC %s called: hpa=0x%x (%s) option=0x%x arg2=0x%x arg3=0x%x ", func, ARG0, hpa_name(ARG0), ARG1, ARG2, ARG3);
+ printf("result=0x%x arg5=0x%x arg6=0x%x arg7=0x%x\n", ARG4, ARG5, ARG6, ARG7);
+ }
+}
+
+#define FUNC_MANY_ARGS , \
+ int a0, int a1, int a2, int a3, int a4, int a5, int a6, \
+ int a7, int a8, int a9, int a10, int a11, int a12
+
+
+int __VISIBLE parisc_iodc_ENTRY_IO(unsigned int *arg FUNC_MANY_ARGS)
+{
+ unsigned long hpa = ARG0;
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG4;
+ int ret, len;
+ char *c;
+ struct disk_op_s disk_op;
+
+ if (1 &&
+ (((HPA_is_serial_device(hpa) || HPA_is_graphics_device(hpa)) && option == ENTRY_IO_COUT) ||
+ ((HPA_is_serial_device(hpa) || HPA_is_graphics_device(hpa)) && option == ENTRY_IO_CIN) ||
+ (HPA_is_storage_device(hpa) && option == ENTRY_IO_BOOTIN))) {
+ /* avoid debug messages */
+ } else {
+ iodc_log_call(arg, __FUNCTION__);
+ }
+
+ /* console I/O */
+ switch (option) {
+ case ENTRY_IO_COUT: /* console output */
+ c = (char*)ARG6;
+ result[0] = len = ARG7;
+ if (HPA_is_serial_device(hpa) || HPA_is_graphics_device(hpa)) {
+ while (len--)
+ printf("%c", *c++);
+ }
+ return PDC_OK;
+ case ENTRY_IO_CIN: /* console input, with 5 seconds timeout */
+ c = (char*)ARG6;
+ if (HPA_is_serial_device(hpa))
+ result[0] = parisc_serial_in(c, ARG7);
+ else if (HPA_is_keyboard_device(hpa))
+ result[0] = lasips2_kbd_in(c, ARG7);
+ return PDC_OK;
+ }
+
+ /* boot medium I/O */
+ if (HPA_is_storage_device(hpa))
+ switch (option) {
+ case ENTRY_IO_BOOTIN: /* boot medium IN */
+ case ENTRY_IO_BBLOCK_IN: /* boot block medium IN */
+ disk_op.drive_fl = boot_drive;
+ disk_op.buf_fl = (void*)ARG6;
+ disk_op.command = CMD_READ;
+ if (option == ENTRY_IO_BBLOCK_IN) { /* in 2k blocks */
+ disk_op.count = (ARG7 * ((u64)FW_BLOCKSIZE / disk_op.drive_fl->blksize));
+ disk_op.lba = (ARG5 * ((u64)FW_BLOCKSIZE / disk_op.drive_fl->blksize));
+ } else {
+ disk_op.count = (ARG7 / disk_op.drive_fl->blksize);
+ disk_op.lba = (ARG5 / disk_op.drive_fl->blksize);
+ }
+ // ARG8 = maxsize !!!
+ ret = process_op(&disk_op);
+ // dprintf(0, "\nBOOT IO res %d count = %d\n", ret, ARG7);
+ result[0] = ARG7;
+ if (ret)
+ return PDC_ERROR;
+ return PDC_OK;
+ }
+
+ if (option == ENTRY_IO_CLOSE)
+ return PDC_OK;
+
+ // BUG_ON(1);
+ iodc_log_call(arg, __FUNCTION__);
+
+ return PDC_BAD_OPTION;
+}
+
+
+int __VISIBLE parisc_iodc_ENTRY_INIT(unsigned int *arg FUNC_MANY_ARGS)
+{
+ unsigned long hpa = ARG0;
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG4;
+ int hpa_index;
+
+ iodc_log_call(arg, __FUNCTION__);
+
+ hpa_index = find_hpa_index(hpa);
+ if (hpa_index < 0 && hpa != IDE_HPA)
+ return PDC_INVALID_ARG;
+
+ switch (option) {
+ case ENTRY_INIT_SRCH_FRST: /* 2: Search first */
+ memcpy((void *)ARG3, &mod_path_emulated_drives.layers,
+ sizeof(mod_path_emulated_drives.layers)); /* fill ID_addr */
+ result[0] = 0;
+ result[1] = HPA_is_serial_device(hpa) ? CL_DUPLEX:
+ HPA_is_storage_device(hpa) ? CL_RANDOM : 0;
+ result[2] = result[3] = 0; /* No network card, so no MAC. */
+ return PDC_OK;
+ case ENTRY_INIT_SRCH_NEXT: /* 3: Search next */
+ return PDC_NE_BOOTDEV; /* No further boot devices */
+ case ENTRY_INIT_MOD_DEV: /* 4: Init & test mod & dev */
+ case ENTRY_INIT_DEV: /* 5: Init & test dev */
+ result[0] = 0; /* module IO_STATUS */
+ result[1] = HPA_is_serial_device(hpa) ? CL_DUPLEX:
+ HPA_is_storage_device(hpa) ? CL_RANDOM : 0;
+ result[2] = result[3] = 0; /* TODO?: MAC of network card. */
+ return PDC_OK;
+ case ENTRY_INIT_MOD: /* 6: INIT */
+ result[0] = 0; /* module IO_STATUS */
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+int __VISIBLE parisc_iodc_ENTRY_SPA(unsigned int *arg FUNC_MANY_ARGS)
+{
+ iodc_log_call(arg, __FUNCTION__);
+ return PDC_BAD_OPTION;
+}
+
+int __VISIBLE parisc_iodc_ENTRY_CONFIG(unsigned int *arg FUNC_MANY_ARGS)
+{
+ iodc_log_call(arg, __FUNCTION__);
+ return PDC_BAD_OPTION;
+}
+
+int __VISIBLE parisc_iodc_ENTRY_TEST(unsigned int *arg FUNC_MANY_ARGS)
+{
+ unsigned long hpa = ARG0;
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG4;
+ int hpa_index;
+
+ iodc_log_call(arg, __FUNCTION__);
+
+ hpa_index = find_hpa_index(hpa);
+ if (hpa_index < 0 && hpa != IDE_HPA)
+ return PDC_INVALID_ARG;
+
+ /* The options ARG1=0 and ARG1=1 are required. Others are optional. */
+ if (option == 0) { // Return info
+ unsigned long *list_addr = (unsigned long *)ARG5;
+ list_addr[0] = 0; // no test lists available.
+ result[0] = 0; // data buffer size, no bytes required.
+ result[1] = 0; // message buffer size, no bytes required.
+ return PDC_OK;
+ }
+
+ if (option == 1) { // Execute step
+ result[0] = 0; // fixed address of remote por
+ return PDC_OK;
+ }
+
+ return PDC_BAD_OPTION;
+}
+
+int __VISIBLE parisc_iodc_ENTRY_TLB(unsigned int *arg FUNC_MANY_ARGS)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG4;
+
+ iodc_log_call(arg, __FUNCTION__);
+
+ if (option == 0) {
+ result[0] = 0; /* no TLB */
+ result[1] = 0;
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+/********************************************************
+ * FIRMWARE PDC HANDLER
+ ********************************************************/
+
+#define STABLE_STORAGE_SIZE 512
+static unsigned char stable_storage[STABLE_STORAGE_SIZE];
+
+#define NVOLATILE_STORAGE_SIZE 512
+static unsigned char nvolatile_storage[NVOLATILE_STORAGE_SIZE];
+
+static void init_stable_storage(void)
+{
+ /* see ENGINEERING NOTE on page 4-92 in PDC2.0 doc */
+ memset(&stable_storage, 0, STABLE_STORAGE_SIZE);
+ // no intial paths
+ stable_storage[0x07] = 0xff;
+ stable_storage[0x67] = 0xff;
+ stable_storage[0x87] = 0xff;
+ stable_storage[0xa7] = 0xff;
+ // 0x0e/0x0f => fastsize = all, needed for HPUX
+ stable_storage[0x5f] = 0x0f;
+}
+
+static unsigned long lasi_rtc_read(void)
+{
+ return *(u32 *)LASI_RTC_HPA;
+}
+
+static void lasi_rtc_write(u32 val)
+{
+ *(u32 *)LASI_RTC_HPA = val;
+}
+
+/* values in PDC_CHASSIS */
+const char * const systat[] = {
+ "Off", "Fault", "Test", "Initialize",
+ "Shutdown", "Warning", "Run", "All On"
+};
+
+static const char *pdc_name(unsigned long num)
+{
+#define DO(x) if (num == x) return #x;
+ DO(PDC_POW_FAIL)
+ DO(PDC_CHASSIS)
+ DO(PDC_PIM)
+ DO(PDC_MODEL)
+ DO(PDC_CACHE)
+ DO(PDC_HPA)
+ DO(PDC_COPROC)
+ DO(PDC_IODC)
+ DO(PDC_TOD)
+ DO(PDC_STABLE)
+ DO(PDC_NVOLATILE)
+ DO(PDC_ADD_VALID)
+ DO(PDC_INSTR)
+ DO(PDC_PROC)
+ DO(PDC_BLOCK_TLB)
+ DO(PDC_TLB)
+ DO(PDC_MEM)
+ DO(PDC_PSW)
+ DO(PDC_SYSTEM_MAP)
+ DO(PDC_SOFT_POWER)
+ DO(PDC_CRASH_PREP)
+ DO(PDC_MEM_MAP)
+ DO(PDC_EEPROM)
+ DO(PDC_NVM)
+ DO(PDC_SEED_ERROR)
+ DO(PDC_IO)
+ DO(PDC_BROADCAST_RESET)
+ DO(PDC_LAN_STATION_ID)
+ DO(PDC_CHECK_RANGES)
+ DO(PDC_NV_SECTIONS)
+ DO(PDC_PERFORMANCE)
+ DO(PDC_SYSTEM_INFO)
+ DO(PDC_RDR)
+ DO(PDC_INTRIGUE)
+ DO(PDC_STI)
+ DO(PDC_PCI_INDEX)
+ DO(PDC_RELOCATE)
+ DO(PDC_INITIATOR)
+ DO(PDC_LINK)
+#undef DO
+ return "UNKNOWN!";
+}
+
+static int pdc_chassis(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+ short *display_model = (short *)ARG3;
+
+ switch (option) {
+ case PDC_CHASSIS_DISP:
+ ARG3 = ARG2;
+ result = (unsigned long *)&ARG4; // do not write to ARG2, use &ARG4 instead
+ // fall through
+ case PDC_CHASSIS_DISPWARN:
+ ARG4 = (ARG3 >> 17) & 7;
+ chassis_code = ARG3 & 0xffff;
+ if (0) printf("\nPDC_CHASSIS: %s (%d), %sCHASSIS %0x\n",
+ systat[ARG4], ARG4, (ARG3>>16)&1 ? "blank display, ":"", chassis_code);
+ // fall through
+ case PDC_CHASSIS_WARN:
+ // return warnings regarding fans, batteries and temperature: None!
+ result[0] = 0;
+ return PDC_OK;
+ case PDC_RETURN_CHASSIS_INFO: /* return chassis LED/LCD info */
+ // XXX: Later we could emulate an LCD display here.
+ result[0] = result[1] = 4; // actcnt & maxcnt
+ memset((char *)ARG3, 0, ARG4);
+ display_model[0] = 1; // 1=DISPLAY_MODEL_NONE
+ display_model[1] = 0; // 0=LCD WIDTH is 0
+ return PDC_OK;
+ }
+ return PDC_BAD_PROC;
+}
+
+static int pdc_pim(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ switch (option) {
+ case PDC_PIM_HPMC:
+ break;
+ case PDC_PIM_RETURN_SIZE:
+ *result = sizeof(struct pdc_hpmc_pim_11); // FIXME 64bit!
+ // B160 returns only "2". Why?
+ return PDC_OK;
+ case PDC_PIM_LPMC:
+ case PDC_PIM_SOFT_BOOT:
+ return PDC_BAD_OPTION;
+ case PDC_PIM_TOC:
+ break;
+ }
+ return PDC_BAD_PROC;
+}
+
+static int pdc_model(unsigned int *arg)
+{
+ static unsigned long model[] = { PARISC_PDC_MODEL };
+ static const char model_str[] = PARISC_MODEL;
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ switch (option) {
+ case PDC_MODEL_INFO:
+ memcpy(result, model, sizeof(model));
+ return PDC_OK;
+ case PDC_MODEL_VERSIONS:
+ switch (ARG3) {
+ case 0: /* return CPU0 version */
+ result[0] = 35; // TODO! ???
+ return PDC_OK;
+ case 1: /* return PDC version */
+ result[0] = PARISC_PDC_VERSION;
+ return PDC_OK;
+ }
+ return -4; // invalid c_index
+ case PDC_MODEL_SYSMODEL:
+ result[0] = sizeof(model_str) - 1;
+ strtcpy((char *)ARG4, model_str, sizeof(model_str));
+ return PDC_OK;
+ case PDC_MODEL_ENSPEC:
+ case PDC_MODEL_DISPEC:
+ if (ARG3 != model[7])
+ return -20;
+ return PDC_OK;
+ case PDC_MODEL_CPU_ID:
+ result[0] = PARISC_PDC_CPUID;
+ return PDC_OK;
+ case PDC_MODEL_CAPABILITIES:
+ result[0] = PARISC_PDC_CAPABILITIES;
+ result[0] |= PDC_MODEL_OS32; /* we do support 32-bit */
+ result[0] &= ~PDC_MODEL_OS64; /* but not 64-bit (yet) */
+ return PDC_OK;
+ case PDC_MODEL_GET_INSTALL_KERNEL:
+ // No need to provide a special install kernel during installation of HP-UX
+ return PDC_BAD_OPTION;
+ }
+ dprintf(0, "\n\nSeaBIOS: Unimplemented PDC_MODEL function %d %x %x %x %x\n", ARG1, ARG2, ARG3, ARG4, ARG5);
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_cache(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+ static unsigned long cache_info[] = { PARISC_PDC_CACHE_INFO };
+ static struct pdc_cache_info *machine_cache_info
+ = (struct pdc_cache_info *) &cache_info;
+
+ switch (option) {
+ case PDC_CACHE_INFO:
+ BUG_ON(sizeof(cache_info) != sizeof(*machine_cache_info));
+ machine_cache_info->it_size = tlb_entries;
+ machine_cache_info->dt_size = tlb_entries;
+ machine_cache_info->it_loop = 1;
+ machine_cache_info->dt_loop = 1;
+
+#if 0
+ dprintf(0, "\n\nCACHE IC: %ld %ld %ld DC: %ld %ld %ld\n",
+ machine_cache_info->ic_count, machine_cache_info->ic_loop, machine_cache_info->ic_stride,
+ machine_cache_info->dc_count, machine_cache_info->dc_loop, machine_cache_info->dc_stride);
+#endif
+#if 1
+ /* Increase cc_block from 1 to 11. This increases icache_stride
+ * and dcache_stride to 32768 bytes. Revisit for HP-UX. */
+ machine_cache_info->dc_conf.cc_block = 11;
+ machine_cache_info->ic_conf.cc_block = 11;
+
+ machine_cache_info->ic_size = 0; /* no instruction cache */
+ machine_cache_info->ic_count = 0;
+ machine_cache_info->ic_loop = 0;
+ machine_cache_info->dc_size = 0; /* no data cache */
+ machine_cache_info->dc_count = 0;
+ machine_cache_info->dc_loop = 0;
+#endif
+
+ memcpy(result, cache_info, sizeof(cache_info));
+ return PDC_OK;
+ }
+ dprintf(0, "\n\nSeaBIOS: Unimplemented PDC_CACHE function %d %x %x %x %x\n", ARG1, ARG2, ARG3, ARG4, ARG5);
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_hpa(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+ unsigned long hpa;
+ int i;
+
+ switch (option) {
+ case PDC_HPA_PROCESSOR:
+ hpa = mfctl(CPU_HPA_CR_REG); /* get CPU HPA from cr7 */
+ i = index_of_CPU_HPA(hpa);
+ BUG_ON(i < 0); /* ARGH, someone modified cr7! */
+ result[0] = hpa; /* CPU_HPA */
+ result[1] = i; /* for SMP: 0,1,2,3,4...(num of this cpu) */
+ return PDC_OK;
+ case PDC_HPA_MODULES:
+ return PDC_BAD_OPTION; // all modules on same board as the processor.
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_coproc(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+ unsigned char mask;
+ switch (option) {
+ case PDC_COPROC_CFG:
+ memset(result, 0, 32 * sizeof(unsigned long));
+ mask = ~((1 << (8-smp_cpus))-1);
+ /* set bit per cpu in ccr_functional and ccr_present: */
+ mtctl(mask, 10); /* initialize cr10 */
+ result[0] = mask;
+ result[1] = mask;
+ result[17] = 1; // Revision
+ result[18] = 19; // Model
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_iodc(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+ unsigned long hpa;
+ struct pdc_iodc *iodc_p;
+ int hpa_index;
+ unsigned char *c;
+
+ // dprintf(0, "\n\nSeaBIOS: Info PDC_IODC function %ld ARG3=%x ARG4=%x ARG5=%x ARG6=%x\n", option, ARG3, ARG4, ARG5, ARG6);
+ switch (option) {
+ case PDC_IODC_READ:
+ hpa = ARG3;
+ if (hpa == IDE_HPA) { // do NOT check for DINO_SCSI_HPA, breaks Linux which scans IO areas for unlisted io modules
+ iodc_p = &iodc_data_hpa_fff8c000; // workaround for PCI ATA
+ } else {
+ hpa_index = find_hpa_index(hpa);
+ if (hpa_index < 0)
+ return -4; // not found
+ iodc_p = parisc_devices[hpa_index].iodc;
+ }
+
+ if (ARG4 == PDC_IODC_INDEX_DATA) {
+ // if (hpa == MEMORY_HPA)
+ // ARG6 = 2; // Memory modules return 2 bytes of IODC memory (result2 ret[0] = 0x6701f41 HI !!)
+ memcpy((void*) ARG5, iodc_p, ARG6);
+ c = (unsigned char *) ARG5;
+ // printf("SeaBIOS: PDC_IODC get: hpa = 0x%lx, HV: 0x%x 0x%x IODC_SPA=0x%x type 0x%x, \n", hpa, c[0], c[1], c[2], c[3]);
+ // c[0] = iodc_p->hversion_model; // FIXME. BROKEN HERE !!!
+ // c[1] = iodc_p->hversion_rev || (iodc_p->hversion << 4);
+ *result = ARG6;
+ return PDC_OK;
+ }
+
+ // ARG4 is IODC function to copy.
+ if (ARG4 < PDC_IODC_RI_INIT || ARG4 > PDC_IODC_RI_TLB)
+ return PDC_IODC_INVALID_INDEX;
+
+ *result = 512; /* max size of function iodc_entry */
+ if (ARG6 < *result)
+ return PDC_IODC_COUNT;
+ memcpy((void*) ARG5, &iodc_entry, *result);
+ c = (unsigned char *) &iodc_entry_table;
+ /* calculate offset into jump table. */
+ c += (ARG4 - PDC_IODC_RI_INIT) * 2 * sizeof(unsigned int);
+ memcpy((void*) ARG5, c, 2 * sizeof(unsigned int));
+ // dprintf(0, "\n\nSeaBIOS: Info PDC_IODC function OK\n");
+ flush_data_cache((char*)ARG5, *result);
+ return PDC_OK;
+ break;
+ case PDC_IODC_NINIT: /* non-destructive init */
+ case PDC_IODC_DINIT: /* destructive init */
+ break;
+ case PDC_IODC_MEMERR:
+ result[0] = 0; /* IO_STATUS */
+ result[1] = 0;
+ result[2] = 0;
+ result[3] = 0;
+ return PDC_OK;
+ }
+ dprintf(0, "\n\nSeaBIOS: Unimplemented PDC_IODC function %ld ARG3=%x ARG4=%x ARG5=%x ARG6=%x\n", option, ARG3, ARG4, ARG5, ARG6);
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_tod(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ switch (option) {
+ case PDC_TOD_READ:
+ result[0] = lasi_rtc_read();
+ result[1] = result[2] = result[3] = 0;
+ return PDC_OK;
+ case PDC_TOD_WRITE:
+ lasi_rtc_write(ARG2);
+ return PDC_OK;
+ case 2: /* PDC_TOD_CALIBRATE_TIMERS */
+ /* double-precision floating-point with frequency of Interval Timer in megahertz: */
+ *(double*)&result[0] = (double)CPU_CLOCK_MHZ;
+ /* unsigned 64-bit integers representing clock accuracy in parts per billion: */
+ result[2] = 1000000000; /* TOD_acc */
+ result[3] = 0x5a6c; /* CR_acc (interval timer) */
+ return PDC_OK;
+ }
+ dprintf(0, "\n\nSeaBIOS: Unimplemented PDC_TOD function %ld ARG2=%x ARG3=%x ARG4=%x\n", option, ARG2, ARG3, ARG4);
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_stable(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ // dprintf(0, "\n\nSeaBIOS: PDC_STABLE function %ld ARG2=%x ARG3=%x ARG4=%x\n", option, ARG2, ARG3, ARG4);
+ switch (option) {
+ case PDC_STABLE_READ:
+ if ((ARG2 + ARG4) > STABLE_STORAGE_SIZE)
+ return PDC_INVALID_ARG;
+ memcpy((unsigned char *) ARG3, &stable_storage[ARG2], ARG4);
+ return PDC_OK;
+ case PDC_STABLE_WRITE:
+ if ((ARG2 + ARG4) > STABLE_STORAGE_SIZE)
+ return PDC_INVALID_ARG;
+ memcpy(&stable_storage[ARG2], (unsigned char *) ARG3, ARG4);
+ return PDC_OK;
+ case PDC_STABLE_RETURN_SIZE:
+ result[0] = STABLE_STORAGE_SIZE;
+ return PDC_OK;
+ case PDC_STABLE_VERIFY_CONTENTS:
+ return PDC_OK;
+ case PDC_STABLE_INITIALIZE:
+ init_stable_storage();
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_nvolatile(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ switch (option) {
+ case PDC_NVOLATILE_READ:
+ if ((ARG2 + ARG4) > NVOLATILE_STORAGE_SIZE)
+ return PDC_INVALID_ARG;
+ memcpy((unsigned char *) ARG3, &nvolatile_storage[ARG2], ARG4);
+ return PDC_OK;
+ case PDC_NVOLATILE_WRITE:
+ if ((ARG2 + ARG4) > NVOLATILE_STORAGE_SIZE)
+ return PDC_INVALID_ARG;
+ memcpy(&nvolatile_storage[ARG2], (unsigned char *) ARG3, ARG4);
+ return PDC_OK;
+ case PDC_NVOLATILE_RETURN_SIZE:
+ result[0] = NVOLATILE_STORAGE_SIZE;
+ return PDC_OK;
+ case PDC_NVOLATILE_VERIFY_CONTENTS:
+ return PDC_OK;
+ case PDC_NVOLATILE_INITIALIZE:
+ memset(nvolatile_storage, 0, sizeof(nvolatile_storage));
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_add_valid(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+
+ // dprintf(0, "\n\nSeaBIOS: PDC_ADD_VALID function %ld ARG2=%x called.\n", option, ARG2);
+ if (option != 0)
+ return PDC_BAD_OPTION;
+ if (0 && ARG2 == 0) // should PAGE0 be valid? HP-UX asks for it, but maybe due a bug in our code...
+ return 1;
+ // if (ARG2 < PAGE_SIZE) return PDC_ERROR;
+ if (ARG2 < ram_size)
+ return PDC_OK;
+ if (ARG2 >= (unsigned long)_sti_rom_start &&
+ ARG2 <= (unsigned long)_sti_rom_end)
+ return PDC_OK;
+ if (ARG2 < FIRMWARE_END)
+ return 1;
+ if (ARG2 <= 0xffffffff)
+ return PDC_OK;
+ dprintf(0, "\n\nSeaBIOS: FAILED!!!! PDC_ADD_VALID function %ld ARG2=%x called.\n", option, ARG2);
+ return PDC_REQ_ERR_0; /* Operation completed with a requestor bus error. */
+}
+
+static int pdc_proc(unsigned int *arg)
+{
+ extern void enter_smp_idle_loop(void);
+ unsigned long option = ARG1;
+
+ switch (option) {
+ case 1:
+ if (ARG2 != 0)
+ return PDC_BAD_PROC;
+ /* let the current CPU sleep until rendenzvous. */
+ enter_smp_idle_loop();
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_block_tlb(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ struct pdc_btlb_info *info = (struct pdc_btlb_info *) ARG2;
+
+ switch (option) {
+ case PDC_BTLB_INFO:
+ memset(info, 0, sizeof(*info));
+ if (btlb_entries) {
+ /* TODO: fill in BTLB info */
+ }
+ return PDC_OK;
+ case PDC_BTLB_INSERT:
+ case PDC_BTLB_PURGE:
+ case PDC_BTLB_PURGE_ALL:
+ /* TODO: implement above functions */
+ return PDC_BAD_OPTION;
+
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_tlb(unsigned int *arg)
+{
+#if 0
+ /* still buggy, let's avoid it to keep things simple. */
+ switch (option) {
+ case PDC_TLB_INFO:
+ result[0] = PAGE_SIZE;
+ result[0] = PAGE_SIZE << 2;
+ return PDC_OK;
+ case PDC_TLB_SETUP:
+ result[0] = ARG5 & 1;
+ result[1] = 0;
+ return PDC_OK;
+ }
+#endif
+ return PDC_BAD_PROC;
+}
+
+static int pdc_mem(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ // only implemented on 64bit PDC!
+ if (sizeof(unsigned long) == sizeof(unsigned int))
+ return PDC_BAD_PROC;
+
+ switch (option) {
+ case PDC_MEM_MEMINFO:
+ result[0] = 0; // no PDT entries
+ result[1] = 0; // page entries
+ result[2] = 0; // PDT status
+ result[3] = (unsigned long)-1ULL; // dbe_loc
+ result[4] = GoldenMemory; // good_mem
+ return PDC_OK;
+ case PDC_MEM_READ_PDT:
+ result[0] = 0; // no PDT entries
+ return PDC_OK;
+ case PDC_MEM_GOODMEM:
+ GoldenMemory = ARG3;
+ return PDC_OK;
+ }
+ dprintf(0, "\n\nSeaBIOS: Check PDC_MEM option %ld ARG3=%x ARG4=%x ARG5=%x\n", option, ARG3, ARG4, ARG5);
+ return PDC_BAD_PROC;
+}
+
+static int pdc_psw(unsigned int *arg)
+{
+ static unsigned long psw_defaults = PDC_PSW_ENDIAN_BIT;
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ if (option > PDC_PSW_SET_DEFAULTS)
+ return PDC_BAD_OPTION;
+ /* FIXME: For 64bit support enable PDC_PSW_WIDE_BIT too! */
+ if (option == PDC_PSW_MASK)
+ *result = PDC_PSW_ENDIAN_BIT;
+ if (option == PDC_PSW_GET_DEFAULTS)
+ *result = psw_defaults;
+ if (option == PDC_PSW_SET_DEFAULTS) {
+ psw_defaults = ARG2;
+ }
+ return PDC_OK;
+}
+
+static int pdc_system_map(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+ struct pdc_module_path *mod_path;
+ unsigned long hpa;
+ int hpa_index;
+
+ // dprintf(0, "\n\nSeaBIOS: Info: PDC_SYSTEM_MAP function %ld ARG3=%x ARG4=%x ARG5=%x\n", option, ARG3, ARG4, ARG5);
+ switch (option) {
+ case PDC_FIND_MODULE:
+ hpa_index = ARG4;
+ if (hpa_index >= ARRAY_SIZE(parisc_devices))
+ return PDC_NE_MOD; // Module not found
+ hpa = parisc_devices[hpa_index].hpa;
+ if (!hpa)
+ return PDC_NE_MOD; // Module not found
+
+ mod_path = (struct pdc_module_path *)ARG3;
+ if (mod_path)
+ *mod_path = *parisc_devices[hpa_index].mod_path;
+
+ // *pdc_mod_info = *parisc_devices[hpa_index].mod_info; -> can be dropped.
+ memset(result, 0, 32*sizeof(long));
+ result[0] = hpa; // .mod_addr for PDC_IODC
+ result[1] = HPA_is_graphics_device(hpa) ? GFX_NUM_PAGES : 1;
+ result[2] = parisc_devices[hpa_index].num_addr; // additional addresses
+ return PDC_OK;
+
+ case PDC_FIND_ADDRESS:
+ hpa_index = ARG3;
+ if (hpa_index >= ARRAY_SIZE(parisc_devices))
+ return PDC_NE_MOD; // Module not found
+ hpa = parisc_devices[hpa_index].hpa;
+ if (!hpa)
+ return PDC_NE_MOD; // Module not found
+
+ memset(result, 0, 32*sizeof(long));
+ ARG4 -= 1;
+ if (ARG4 >= parisc_devices[hpa_index].num_addr)
+ return PDC_INVALID_ARG;
+ result[0] = parisc_devices[hpa_index].add_addr[ARG4];
+ result[1] = HPA_is_graphics_device(hpa) ? GFX_NUM_PAGES : 1;
+ return PDC_OK;
+
+ case PDC_TRANSLATE_PATH:
+ mod_path = (struct pdc_module_path *)ARG3;
+ hppa_device_t *dev = find_hppa_device_by_path(mod_path, result+3, 1);
+ if (!dev)
+ return PDC_NE_MOD;
+
+ result[0] = dev->hpa;
+ result[1] = 1;
+ result[2] = 0;
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_soft_power(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ switch (option) {
+ case PDC_SOFT_POWER_INFO:
+ result[0] = (unsigned long) powersw_ptr;
+ return PDC_OK;
+ case PDC_SOFT_POWER_ENABLE:
+ /* put soft power button under hardware (ARG3=0) or
+ * software (ARG3=1) control. */
+ *powersw_ptr = (ARG3 & 1) << 8 | (*powersw_ptr & 1);
+ check_powersw_button();
+ return PDC_OK;
+ }
+ // dprintf(0, "\n\nSeaBIOS: PDC_SOFT_POWER called with ARG2=%x ARG3=%x ARG4=%x\n", ARG2, ARG3, ARG4);
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_mem_map(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ struct pdc_memory_map *memmap = (struct pdc_memory_map *) ARG2;
+ struct device_path *dp = (struct device_path *) ARG3;
+ hppa_device_t *dev;
+ unsigned long index;
+
+ switch (option) {
+ case PDC_MEM_MAP_HPA:
+ // dprintf(0, "\nSeaBIOS: PDC_MEM_MAP_HPA bus = %d, mod = %d\n", dp->bc[4], dp->mod);
+ dev = find_hppa_device_by_path((struct pdc_module_path *) dp, &index, 0);
+ if (!dev)
+ return PDC_NE_MOD;
+ memcpy(memmap, dev->mod_info, sizeof(*memmap));
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_io(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+
+ switch (option) {
+ case PDC_IO_READ_AND_CLEAR_ERRORS:
+ dprintf(0, "\n\nSeaBIOS: PDC_IO called with ARG2=%x ARG3=%x ARG4=%x\n", ARG2, ARG3, ARG4);
+ // return PDC_BAD_OPTION;
+ case PDC_IO_RESET:
+ case PDC_IO_RESET_DEVICES:
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_lan_station_id(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+
+ switch (option) {
+ case PDC_LAN_STATION_ID_READ:
+ if (ARG3 != LASI_LAN_HPA)
+ return PDC_INVALID_ARG;
+ if (!keep_this_hpa(LASI_LAN_HPA))
+ return PDC_INVALID_ARG;
+ /* Let qemu store the MAC of NIC to address @ARG2 */
+ *(unsigned long *)(LASI_LAN_HPA+12) = ARG2;
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_pci_index(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ // dprintf(0, "\n\nSeaBIOS: PDC_PCI_INDEX(%lu) called with ARG2=%x ARG3=%x ARG4=%x\n", option, ARG2, ARG3, ARG4);
+ switch (option) {
+ case PDC_PCI_INTERFACE_INFO:
+ memset(result, 0, 32 * sizeof(unsigned long));
+ result[0] = 2; /* XXX physical hardware returns those ?!? */
+ result[16] = 0x60;
+ result[17] = 0x90;
+ return PDC_OK;
+ case PDC_PCI_GET_INT_TBL_SIZE:
+ case PDC_PCI_GET_INT_TBL:
+ memset(result, 0, 32 * sizeof(unsigned long));
+ result[0] = 2; /* Hardware fills in, even though we return PDC_BAD_OPTION below. */
+ result[16] = 0x60;
+ result[17] = 0x90;
+ return PDC_BAD_OPTION;
+ case PDC_PCI_PCI_PATH_TO_PCI_HPA:
+ result[0] = PCI_HPA;
+ return PDC_OK;
+ case PDC_PCI_PCI_HPA_TO_PCI_PATH:
+ BUG_ON(1);
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_initiator(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ switch (option) {
+ case PDC_GET_INITIATOR:
+ // ARG3 points to the hwpath of device for which initiator is asked for.
+ result[0] = 7; // initiator_id/host_id: 7 to 15.
+ result[1] = 10; // scsi_rate: 1, 2, 5 or 10 for 5, 10, 20 or 40 MT/s
+ result[2] = 7; // firmware suggested value for initiator_id
+ result[3] = 10; // firmware suggested value for scsi_rate
+ result[4] = 0; // width: 0:"Narrow, 1:"Wide"
+ result[5] = 0; // mode: 0:SMODE_SE, 1:SMODE_HVD, 2:SMODE_LVD
+ return PDC_OK;
+ case PDC_SET_INITIATOR:
+ case PDC_DELETE_INITIATOR:
+ case PDC_RETURN_TABLE_SIZE:
+ case PDC_RETURN_TABLE:
+ break;
+ }
+ dprintf(0, "\n\nSeaBIOS: Unimplemented PDC_INITIATOR function %ld ARG3=%x ARG4=%x ARG5=%x\n", option, ARG3, ARG4, ARG5);
+ return PDC_BAD_OPTION;
+}
+
+
+int __VISIBLE parisc_pdc_entry(unsigned int *arg FUNC_MANY_ARGS)
+{
+ unsigned long proc = ARG0;
+ unsigned long option = ARG1;
+
+ if (pdc_debug & DEBUG_PDC) {
+ printf("\nSeaBIOS: Start PDC proc %s(%d) option %d result=0x%x ARG3=0x%x %s ",
+ pdc_name(ARG0), ARG0, ARG1, ARG2, ARG3, (proc == PDC_IODC)?hpa_name(ARG3):"");
+ printf("ARG4=0x%x ARG5=0x%x ARG6=0x%x ARG7=0x%x\n", ARG4, ARG5, ARG6, ARG7);
+ }
+
+ switch (proc) {
+ case PDC_POW_FAIL:
+ break;
+
+ case PDC_CHASSIS: /* chassis functions */
+ return pdc_chassis(arg);
+
+ case PDC_PIM:
+ return pdc_pim(arg);
+
+ case PDC_MODEL: /* model information */
+ return pdc_model(arg);
+
+ case PDC_CACHE:
+ return pdc_cache(arg);
+
+ case PDC_HPA:
+ return pdc_hpa(arg);
+
+ case PDC_COPROC:
+ return pdc_coproc(arg);
+
+ case PDC_IODC: /* Call IODC functions */
+ return pdc_iodc(arg);
+
+ case PDC_TOD: /* Time of day */
+ return pdc_tod(arg);
+
+ case PDC_STABLE:
+ return pdc_stable(arg);
+
+ case PDC_NVOLATILE:
+ return pdc_nvolatile(arg);
+
+ case PDC_ADD_VALID:
+ return pdc_add_valid(arg);
+
+ case PDC_INSTR:
+ return PDC_BAD_PROC;
+
+ case PDC_PROC:
+ return pdc_proc(arg);
+
+ case PDC_CONFIG: /* Obsolete */
+ return PDC_BAD_PROC;
+
+ case PDC_BLOCK_TLB:
+ return pdc_block_tlb(arg);
+
+ case PDC_TLB: /* hardware TLB not used on Linux, but on HP-UX (if available) */
+ return pdc_tlb(arg);
+
+ case PDC_MEM:
+ return pdc_mem(arg);
+
+ case PDC_PSW: /* Get/Set default System Mask */
+ return pdc_psw(arg);
+
+ case PDC_SYSTEM_MAP:
+ return pdc_system_map(arg);
+
+ case PDC_SOFT_POWER: // don't have a soft-power switch
+ return pdc_soft_power(arg);
+
+ case PDC_CRASH_PREP:
+ /* This should actually quiesce all I/O and prepare the System for crash dumping.
+ Ignoring it for now, otherwise the BUG_ON below would quit qemu before we have
+ a chance to see the kernel panic */
+ return PDC_OK;
+
+ case 26: // PDC_SCSI_PARMS is the architected firmware interface to replace the Hversion PDC_INITIATOR procedure.
+ return PDC_BAD_PROC;
+
+ case 64: // Called by HP-UX 11 bootcd during boot. Probably checks PDC_PAT_CELL (even if we are not PAT firmware)
+ case 65: // Called by HP-UX 11 bootcd during boot. Probably checks PDC_PAT_CHASSIS_LOG (even if we are not PAT firmware)
+ dprintf(0, "\n\nSeaBIOS: UNKNOWN PDC proc %lu OPTION %lu called with ARG2=%x ARG3=%x ARG4=%x\n", proc, option, ARG2, ARG3, ARG4);
+ return PDC_BAD_PROC;
+
+ case PDC_MEM_MAP:
+ return pdc_mem_map(arg);
+
+ case 134:
+ if (ARG1 == 1 || ARG1 == 513) /* HP-UX 11.11 ask for it. */
+ return PDC_BAD_PROC;
+ break;
+
+ case PDC_IO:
+ return pdc_io(arg);
+
+ case PDC_BROADCAST_RESET:
+ dprintf(0, "\n\nSeaBIOS: PDC_BROADCAST_RESET (reset system) called with ARG3=%x ARG4=%x\n", ARG3, ARG4);
+ reset();
+ return PDC_OK;
+
+ case PDC_LAN_STATION_ID:
+ return pdc_lan_station_id(arg);
+
+ case PDC_SYSTEM_INFO:
+ if (ARG1 == PDC_SYSINFO_RETURN_INFO_SIZE)
+ return PDC_BAD_PROC;
+ break;
+
+ case PDC_PCI_INDEX:
+ return pdc_pci_index(arg);
+
+ case PDC_RELOCATE:
+ /* We don't want to relocate any firmware. */
+ return PDC_BAD_PROC;
+
+ case PDC_INITIATOR:
+ return pdc_initiator(arg);
+ }
+
+ printf("\n** WARNING **: SeaBIOS: Unimplemented PDC proc %s(%d) option %d result=%x ARG3=%x ",
+ pdc_name(ARG0), ARG0, ARG1, ARG2, ARG3);
+ printf("ARG4=%x ARG5=%x ARG6=%x ARG7=%x\n", ARG4, ARG5, ARG6, ARG7);
+
+ BUG_ON(pdc_debug);
+ return PDC_BAD_PROC;
+}
+
+
+/********************************************************
+ * BOOT MENU
+ ********************************************************/
+
+extern void find_initial_parisc_boot_drives(
+ struct drive_s **harddisc,
+ struct drive_s **cdrom);
+extern struct drive_s *select_parisc_boot_drive(char bootdrive);
+
+static int parisc_boot_menu(unsigned long *iplstart, unsigned long *iplend,
+ char bootdrive)
+{
+ int ret;
+ unsigned int *target = (void *)(PAGE0->mem_free + 32*1024);
+ struct disk_op_s disk_op = {
+ .buf_fl = target,
+ .command = CMD_SEEK,
+ .count = 0,
+ .lba = 0,
+ };
+
+ boot_drive = select_parisc_boot_drive(bootdrive);
+ disk_op.drive_fl = boot_drive;
+ if (boot_drive == NULL) {
+ printf("SeaBIOS: No boot device.\n");
+ return 0;
+ }
+
+ /* seek to beginning of disc/CD */
+ disk_op.drive_fl = boot_drive;
+ ret = process_op(&disk_op);
+ // printf("DISK_SEEK returned %d\n", ret);
+ if (ret)
+ return 0;
+
+ // printf("Boot disc type is 0x%x\n", boot_drive->type);
+ disk_op.drive_fl = boot_drive;
+ if (boot_drive->type == DTYPE_ATA_ATAPI ||
+ boot_drive->type == DTYPE_ATA) {
+ disk_op.command = CMD_ISREADY;
+ ret = process_op(&disk_op);
+ } else {
+ ret = scsi_is_ready(&disk_op);
+ }
+ // printf("DISK_READY returned %d\n", ret);
+
+ /* read boot sector of disc/CD */
+ disk_op.drive_fl = boot_drive;
+ disk_op.buf_fl = target;
+ disk_op.command = CMD_READ;
+ disk_op.count = (FW_BLOCKSIZE / disk_op.drive_fl->blksize);
+ disk_op.lba = 0;
+ // printf("blocksize is %d, count is %d\n", disk_op.drive_fl->blksize, disk_op.count);
+ ret = process_op(&disk_op);
+ // printf("DISK_READ(count=%d) = %d\n", disk_op.count, ret);
+ if (ret)
+ return 0;
+
+ unsigned int ipl_addr = be32_to_cpu(target[0xf0/sizeof(int)]); /* offset 0xf0 in bootblock */
+ unsigned int ipl_size = be32_to_cpu(target[0xf4/sizeof(int)]);
+ unsigned int ipl_entry= be32_to_cpu(target[0xf8/sizeof(int)]);
+
+ /* check LIF header of bootblock */
+ if ((target[0]>>16) != 0x8000) {
+ printf("Not a PA-RISC boot image. LIF magic is 0x%x, should be 0x8000.\n", target[0]>>16);
+ return 0;
+ }
+ // printf("ipl start at 0x%x, size %d, entry 0x%x\n", ipl_addr, ipl_size, ipl_entry);
+ // TODO: check ipl values for out of range. Rules are:
+ // IPL_ADDR - 2 Kbyte aligned, nonzero.
+ // IPL_SIZE - Multiple of 2 Kbytes, nonzero, less than or equal to 256 Kbytes.
+ // IPL_ENTRY- Word aligned, less than IPL_SIZE
+
+ /* seek to beginning of IPL */
+ disk_op.drive_fl = boot_drive;
+ disk_op.command = CMD_SEEK;
+ disk_op.count = 0; // (ipl_size / disk_op.drive_fl->blksize);
+ disk_op.lba = (ipl_addr / disk_op.drive_fl->blksize);
+ ret = process_op(&disk_op);
+ // printf("DISK_SEEK to IPL returned %d\n", ret);
+
+ /* read IPL */
+ disk_op.drive_fl = boot_drive;
+ disk_op.buf_fl = target;
+ disk_op.command = CMD_READ;
+ disk_op.count = (ipl_size / disk_op.drive_fl->blksize);
+ disk_op.lba = (ipl_addr / disk_op.drive_fl->blksize);
+ ret = process_op(&disk_op);
+ // printf("DISK_READ IPL returned %d\n", ret);
+
+ // printf("First word at %p is 0x%x\n", target, target[0]);
+
+ /* execute IPL */
+ // TODO: flush D- and I-cache, not needed in emulation ?
+ *iplstart = *iplend = (unsigned long) target;
+ *iplstart += ipl_entry;
+ *iplend += ALIGN(ipl_size, sizeof(unsigned long));
+ return 1;
+}
+
+
+/********************************************************
+ * FIRMWARE MAIN ENTRY POINT
+ ********************************************************/
+
+static const struct pz_device mem_cons_sti_boot = {
+ .hpa = LASI_GFX_HPA,
+ .iodc_io = (unsigned long)&iodc_entry,
+ .cl_class = CL_DISPL,
+};
+
+static const struct pz_device mem_kbd_sti_boot = {
+ .hpa = LASI_PS2KBD_HPA,
+ .iodc_io = (unsigned long)&iodc_entry,
+ .cl_class = CL_KEYBD,
+};
+
+static const struct pz_device mem_cons_boot = {
+ .hpa = PARISC_SERIAL_CONSOLE - 0x800,
+ .iodc_io = (unsigned long)&iodc_entry,
+ .cl_class = CL_DUPLEX,
+};
+
+static const struct pz_device mem_kbd_boot = {
+ .hpa = PARISC_SERIAL_CONSOLE - 0x800,
+ .iodc_io = (unsigned long)&iodc_entry,
+ .cl_class = CL_KEYBD,
+};
+
+static const struct pz_device mem_boot_boot = {
+ .dp.flags = PF_AUTOBOOT,
+ .hpa = IDE_HPA, // DINO_SCSI_HPA, // IDE_HPA
+ .iodc_io = (unsigned long) &iodc_entry,
+ .cl_class = CL_RANDOM,
+};
+
+static void find_pci_slot_for_dev(unsigned int pciid, char *pci_slot)
+{
+ struct pci_device *pci;
+
+ foreachpci(pci)
+ if (pci->vendor == pciid) {
+ *pci_slot = (pci->bdf >> 3) & 0x0f;
+ return;
+ }
+}
+
+/* Prepare boot paths in PAGE0 and stable memory */
+static void prepare_boot_path(volatile struct pz_device *dest,
+ const struct pz_device *source,
+ unsigned int stable_offset)
+{
+ int hpa_index;
+ unsigned long hpa;
+ struct pdc_module_path *mod_path;
+
+ hpa = source->hpa;
+ hpa_index = find_hpa_index(hpa);
+
+ if (HPA_is_storage_device(hpa))
+ mod_path = &mod_path_emulated_drives;
+ else if (hpa == LASI_UART_HPA) // HPA_is_serial_device(hpa))
+ mod_path = &mod_path_hpa_ffd05000;
+ else if (hpa == DINO_UART_HPA) // HPA_is_serial_device(hpa))
+ mod_path = &mod_path_hpa_fff83000;
+ else {
+ BUG_ON(hpa_index < 0);
+ mod_path = parisc_devices[hpa_index].mod_path;
+ }
+
+ /* copy device path to entry in PAGE0 */
+ memcpy((void*)dest, source, sizeof(*source));
+ memcpy((void*)&dest->dp, mod_path, sizeof(struct device_path));
+
+ /* copy device path to stable storage */
+ memcpy(&stable_storage[stable_offset], mod_path, sizeof(*mod_path));
+
+ BUG_ON(sizeof(*mod_path) != 0x20);
+ BUG_ON(sizeof(struct device_path) != 0x20);
+}
+
+static int artist_present(void)
+{
+ return !!(*(u32 *)0xf8380004 == 0x6dc20006);
+}
+
+unsigned long _atoul(char *str)
+{
+ unsigned long val = 0;
+ while (*str) {
+ val *= 10;
+ val += *str - '0';
+ str++;
+ }
+ return val;
+}
+
+unsigned long romfile_loadstring_to_int(const char *name, unsigned long defval)
+{
+ char *str = romfile_loadfile(name, NULL);
+ if (str)
+ return _atoul(str);
+ return defval;
+}
+
+void __VISIBLE start_parisc_firmware(void)
+{
+ unsigned int i, cpu_hz;
+ unsigned long iplstart, iplend;
+
+ unsigned long interactive = (linux_kernel_entry == 1) ? 1:0;
+ char bootdrive = (char)cmdline; // c = hdd, d = CD/DVD
+
+ if (smp_cpus > HPPA_MAX_CPUS)
+ smp_cpus = HPPA_MAX_CPUS;
+
+ if (ram_size >= FIRMWARE_START)
+ ram_size = FIRMWARE_START;
+
+ /* Initialize malloc stack */
+ malloc_preinit();
+
+ /* Initialize qemu fw_cfg interface */
+ PORT_QEMU_CFG_CTL = fw_cfg_port;
+ qemu_cfg_init();
+
+ /* Initialize boot structures. Needs working fw_cfg for bootprio option. */
+ boot_init();
+
+ i = romfile_loadint("/etc/firmware-min-version", 0);
+ if (i && i > SEABIOS_HPPA_VERSION) {
+ printf("\nSeaBIOS firmware is version %d, but version %d is required. "
+ "Please update.\n", (int)SEABIOS_HPPA_VERSION, i);
+ hlt();
+ }
+
+ tlb_entries = romfile_loadint("/etc/cpu/tlb_entries", 256);
+ dprintf(0, "fw_cfg: TLB entries %d\n", tlb_entries);
+
+ btlb_entries = romfile_loadint("/etc/cpu/btlb_entries", 8);
+ dprintf(0, "fw_cfg: BTLB entries %d\n", btlb_entries);
+
+ powersw_ptr = (int *) (unsigned long)
+ romfile_loadint("/etc/power-button-addr", (unsigned long)&powersw_nop);
+
+ /* use -fw_cfg opt/pdc_debug,string=255 to enable all firmware debug infos */
+ pdc_debug = romfile_loadstring_to_int("opt/pdc_debug", 0);
+
+ /* Initialize PAGE0 */
+ memset((void*)PAGE0, 0, sizeof(*PAGE0));
+
+ /* copy pdc_entry entry into low memory. */
+ memcpy((void*)MEM_PDC_ENTRY, &pdc_entry_table, 3*4);
+ flush_data_cache((char*)MEM_PDC_ENTRY, 3*4);
+
+ PAGE0->memc_cont = ram_size;
+ PAGE0->memc_phsize = ram_size;
+ PAGE0->memc_adsize = ram_size;
+ PAGE0->mem_pdc_hi = (MEM_PDC_ENTRY + 0ULL) >> 32;
+ PAGE0->mem_free = 0x6000; // min PAGE_SIZE
+ PAGE0->mem_hpa = CPU_HPA; // HPA of boot-CPU
+ PAGE0->mem_pdc = MEM_PDC_ENTRY;
+ PAGE0->mem_10msec = CPU_CLOCK_MHZ*(1000000ULL/100);
+
+ BUG_ON(PAGE0->mem_free <= MEM_PDC_ENTRY);
+ BUG_ON(smp_cpus < 1 || smp_cpus > HPPA_MAX_CPUS);
+
+ /* Put QEMU/SeaBIOS marker in PAGE0.
+ * The Linux kernel will search for it. */
+ memcpy((char*)&PAGE0->pad0, "SeaBIOS", 8);
+ PAGE0->pad0[2] = ((unsigned long long)PORT_QEMU_CFG_CTL) >> 32; /* store as 64bit value */
+ PAGE0->pad0[3] = PORT_QEMU_CFG_CTL;
+ *powersw_ptr = 0x01; /* button not pressed, hw controlled. */
+
+ PAGE0->imm_hpa = MEMORY_HPA;
+ PAGE0->imm_spa_size = ram_size;
+ PAGE0->imm_max_mem = ram_size;
+
+ // Initialize boot paths (disc, display & keyboard)
+ if (artist_present()) {
+ sti_rom_init();
+ sti_console_init(&sti_proc_rom);
+ ps2port_setup();
+ prepare_boot_path(&(PAGE0->mem_cons), &mem_cons_sti_boot, 0x60);
+ prepare_boot_path(&(PAGE0->mem_kbd), &mem_kbd_sti_boot, 0xa0);
+ PAGE0->proc_sti = (u32)&sti_proc_rom;
+ } else {
+ remove_from_keep_list(LASI_GFX_HPA);
+ remove_from_keep_list(LASI_PS2KBD_HPA);
+ remove_from_keep_list(LASI_PS2MOU_HPA);
+ prepare_boot_path(&(PAGE0->mem_cons), &mem_cons_boot, 0x60);
+ prepare_boot_path(&(PAGE0->mem_kbd), &mem_kbd_boot, 0xa0);
+ }
+
+ /* Initialize device list */
+ remove_parisc_devices(smp_cpus);
+
+ /* Show list of HPA devices which are still returned by firmware. */
+ if (0) { for (i=0; parisc_devices[i].hpa; i++)
+ printf("Kept #%d at 0x%lx\n", i, parisc_devices[i].hpa);
+ }
+
+ // Initialize stable storage
+ init_stable_storage();
+
+ chassis_code = 0;
+
+ // set Qemu serial debug port
+ DebugOutputPort = PARISC_SERIAL_CONSOLE;
+ // PlatformRunningOn = PF_QEMU; // emulate runningOnQEMU()
+
+ cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */
+ dprintf(1, "\nPARISC SeaBIOS Firmware, %ld x PA7300LC (PCX-L2) at %d.%06d MHz, %lu MB RAM.\n",
+ smp_cpus, cpu_hz / 1000000, cpu_hz % 1000000,
+ ram_size/1024/1024);
+
+ if (ram_size < MIN_RAM_SIZE) {
+ printf("\nSeaBIOS: Machine configured with too little "
+ "memory (%ld MB), minimum is %d MB.\n\n",
+ ram_size/1024/1024, MIN_RAM_SIZE/1024/1024);
+ hlt();
+ }
+
+ // handle_post();
+ serial_debug_preinit();
+ debug_banner();
+ // maininit();
+ qemu_preinit();
+ RamSize = ram_size;
+ // coreboot_preinit();
+
+ pci_setup();
+
+ serial_setup();
+ block_setup();
+
+ printf("\n");
+ printf("SeaBIOS PA-RISC Firmware Version %d\n"
+ "\n"
+ "Duplex Console IO Dependent Code (IODC) revision 1\n"
+ "\n"
+ "Memory Test/Initialization Completed\n\n", SEABIOS_HPPA_VERSION);
+ printf("------------------------------------------------------------------------------\n"
+ " (c) Copyright 2017-2021 Helge Deller <deller@gmx.de> and SeaBIOS developers.\n"
+ "------------------------------------------------------------------------------\n\n");
+ printf( " Processor Speed State Coprocessor State Cache Size\n"
+ " --------- -------- --------------------- ----------------- ----------\n");
+ for (i = 0; i < smp_cpus; i++)
+ printf(" %s%d " __stringify(CPU_CLOCK_MHZ)
+ " MHz %s Functional 0 KB\n",
+ i < 10 ? " ":"", i, i?"Idle ":"Active");
+ printf("\n\n");
+ printf(" Available memory: %llu MB\n"
+ " Good memory required: %d MB\n\n",
+ (unsigned long long)ram_size/1024/1024, MIN_RAM_SIZE/1024/1024);
+
+ // search boot devices
+ find_initial_parisc_boot_drives(&parisc_boot_harddisc, &parisc_boot_cdrom);
+
+ printf(" Primary boot path: FWSCSI.%d.%d\n"
+ " Alternate boot path: FWSCSI.%d.%d\n"
+ " Console path: %s\n"
+ " Keyboard path: PS2\n\n",
+ parisc_boot_harddisc->target, parisc_boot_harddisc->lun,
+ parisc_boot_cdrom->target, parisc_boot_cdrom->lun,
+ HPA_is_graphics_device(PAGE0->mem_cons.hpa) ? "GRAPHICS(1)" :
+ ((PARISC_SERIAL_CONSOLE == PORT_SERIAL1) ? "SERIAL_1.9600.8.none" : "SERIAL_2.9600.8.none"));
+
+ if (bootdrive == 'c')
+ boot_drive = parisc_boot_harddisc;
+ else
+ boot_drive = parisc_boot_cdrom;
+
+ // Find PCI bus id of LSI SCSI card
+ find_pci_slot_for_dev(PCI_VENDOR_ID_LSI_LOGIC,
+ &mod_path_emulated_drives.path.bc[5]);
+
+ // Store initial emulated drives path master data
+ if (parisc_boot_harddisc) {
+ mod_path_emulated_drives.layers[0] = parisc_boot_harddisc->target;
+ mod_path_emulated_drives.layers[1] = parisc_boot_harddisc->lun;
+ }
+
+ prepare_boot_path(&(PAGE0->mem_boot), &mem_boot_boot, 0x0);
+
+ // copy primary boot path to alt boot path
+ memcpy(&stable_storage[0x80], &stable_storage[0], 0x20);
+ if (parisc_boot_cdrom) {
+ stable_storage[0x80 + 11] = parisc_boot_cdrom->target;
+ stable_storage[0x80 + 12] = parisc_boot_cdrom->lun;
+ }
+ // currently booted path == CD in PAGE0->mem_boot
+ if (boot_drive) {
+ PAGE0->mem_boot.dp.layers[0] = boot_drive->target;
+ PAGE0->mem_boot.dp.layers[1] = boot_drive->lun;
+ }
+
+ /* directly start Linux kernel if it was given on qemu command line. */
+ if (linux_kernel_entry > 1) {
+ void (*start_kernel)(unsigned long mem_free, unsigned long cline,
+ unsigned long rdstart, unsigned long rdend);
+
+ printf("Autobooting Linux kernel which was loaded by qemu...\n\n");
+ start_kernel = (void *) linux_kernel_entry;
+ start_kernel(PAGE0->mem_free, cmdline, initrd_start, initrd_end);
+ hlt(); /* this ends the emulator */
+ }
+
+#if 0
+ printf("------- Main Menu -------------------------------------------------------------\n\n"
+ " Command Description\n"
+ " ------- -----------\n"
+ " BOot [PRI|ALT|<path>] Boot from specified path\n"
+ " PAth [PRI|ALT|CON|KEY] [<path>] Display or modify a path\n"
+ " SEArch [DIsplay|IPL] [<path>] Search for boot devices\n\n"
+ " COnfiguration [<command>] Access Configuration menu/commands\n"
+ " INformation [<command>] Access Information menu/commands\n"
+ " SERvice [<command>] Access Service menu/commands\n\n"
+ " DIsplay Redisplay the current menu\n"
+ " HElp [<menu>|<command>] Display help for menu or command\n"
+ " RESET Restart the system\n"
+ "-------\n"
+ "Main Menu: Enter command > ");
+#endif
+
+ /* check for bootable drives, and load and start IPL bootloader if possible */
+ if (parisc_boot_menu(&iplstart, &iplend, bootdrive)) {
+ void (*start_ipl)(long interactive, long iplend);
+
+ PAGE0->mem_boot.dp.layers[0] = boot_drive->target;
+ PAGE0->mem_boot.dp.layers[1] = boot_drive->lun;
+
+ printf("\nBooting...\n"
+ "Boot IO Dependent Code (IODC) revision 153\n\n"
+ "%s Booted.\n", PAGE0->imm_soft_boot ? "SOFT":"HARD");
+ start_ipl = (void *) iplstart;
+ start_ipl(interactive, iplend);
+ }
+
+ hlt(); /* this ends the emulator */
+}
diff --git a/roms/seabios-hppa/src/parisc/pdc.h b/roms/seabios-hppa/src/parisc/pdc.h
new file mode 100644
index 000000000..2d0318944
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/pdc.h
@@ -0,0 +1,694 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_PARISC_PDC_H
+#define _UAPI_PARISC_PDC_H
+
+/*
+ * PDC return values ...
+ * All PDC calls return a subset of these errors.
+ */
+
+#define PDC_WARN 3 /* Call completed with a warning */
+#define PDC_REQ_ERR_1 2 /* See above */
+#define PDC_REQ_ERR_0 1 /* Call would generate a requestor error */
+#define PDC_OK 0 /* Call completed successfully */
+#define PDC_BAD_PROC -1 /* Called non-existent procedure*/
+#define PDC_BAD_OPTION -2 /* Called with non-existent option */
+#define PDC_ERROR -3 /* Call could not complete without an error */
+#define PDC_NE_MOD -5 /* Module not found */
+#define PDC_NE_CELL_MOD -7 /* Cell module not found */
+#define PDC_NE_BOOTDEV -9 /* Cannot locate a console device or boot device */
+#define PDC_INVALID_ARG -10 /* Called with an invalid argument */
+#define PDC_BUS_POW_WARN -12 /* Call could not complete in allowed power budget */
+#define PDC_NOT_NARROW -17 /* Narrow mode not supported */
+
+/*
+ * PDC entry points...
+ */
+
+#define PDC_POW_FAIL 1 /* perform a power-fail */
+#define PDC_POW_FAIL_PREPARE 0 /* prepare for powerfail */
+
+#define PDC_CHASSIS 2 /* PDC-chassis functions */
+#define PDC_CHASSIS_DISP 0 /* update chassis display */
+#define PDC_CHASSIS_WARN 1 /* return chassis warnings */
+#define PDC_CHASSIS_DISPWARN 2 /* update&return chassis status */
+#define PDC_RETURN_CHASSIS_INFO 128 /* HVERSION dependent: return chassis LED/LCD info */
+
+#define PDC_PIM 3 /* Get PIM data */
+#define PDC_PIM_HPMC 0 /* Transfer HPMC data */
+#define PDC_PIM_RETURN_SIZE 1 /* Get Max buffer needed for PIM*/
+#define PDC_PIM_LPMC 2 /* Transfer HPMC data */
+#define PDC_PIM_SOFT_BOOT 3 /* Transfer Soft Boot data */
+#define PDC_PIM_TOC 4 /* Transfer TOC data */
+
+#define PDC_MODEL 4 /* PDC model information call */
+#define PDC_MODEL_INFO 0 /* returns information */
+#define PDC_MODEL_BOOTID 1 /* set the BOOT_ID */
+#define PDC_MODEL_VERSIONS 2 /* returns cpu-internal versions*/
+#define PDC_MODEL_SYSMODEL 3 /* return system model info */
+#define PDC_MODEL_ENSPEC 4 /* enable specific option */
+#define PDC_MODEL_DISPEC 5 /* disable specific option */
+#define PDC_MODEL_CPU_ID 6 /* returns cpu-id (only newer machines!) */
+#define PDC_MODEL_CAPABILITIES 7 /* returns OS32/OS64-flags */
+/* Values for PDC_MODEL_CAPABILITIES non-equivalent virtual aliasing support */
+#define PDC_MODEL_OS64 (1 << 0)
+#define PDC_MODEL_OS32 (1 << 1)
+#define PDC_MODEL_IOPDIR_FDC (1 << 2)
+#define PDC_MODEL_NVA_MASK (3 << 4)
+#define PDC_MODEL_NVA_SUPPORTED (0 << 4)
+#define PDC_MODEL_NVA_SLOW (1 << 4)
+#define PDC_MODEL_NVA_UNSUPPORTED (3 << 4)
+#define PDC_MODEL_GET_BOOT__OP 8 /* returns boot test options */
+#define PDC_MODEL_SET_BOOT__OP 9 /* set boot test options */
+#define PDC_MODEL_GET_PLATFORM_INFO 10 /* returns platform info */
+#define PDC_MODEL_GET_INSTALL_KERNEL 11 /* returns kernel for installation */
+
+#define PA89_INSTRUCTION_SET 0x4 /* capabilities returned */
+#define PA90_INSTRUCTION_SET 0x8
+
+#define PDC_CACHE 5 /* return/set cache (& TLB) info*/
+#define PDC_CACHE_INFO 0 /* returns information */
+#define PDC_CACHE_SET_COH 1 /* set coherence state */
+#define PDC_CACHE_RET_SPID 2 /* returns space-ID bits */
+
+#define PDC_HPA 6 /* return HPA of processor */
+#define PDC_HPA_PROCESSOR 0
+#define PDC_HPA_MODULES 1
+
+#define PDC_COPROC 7 /* Co-Processor (usually FP unit(s)) */
+#define PDC_COPROC_CFG 0 /* Co-Processor Cfg (FP unit(s) enabled?) */
+
+#define PDC_IODC 8 /* talk to IODC */
+#define PDC_IODC_READ 0 /* read IODC entry point */
+/* PDC_IODC_RI_ * INDEX parameter of PDC_IODC_READ */
+#define PDC_IODC_RI_DATA_BYTES 0 /* IODC Data Bytes */
+/* 1, 2 obsolete - HVERSION dependent*/
+#define PDC_IODC_RI_INIT 3 /* Initialize module */
+#define PDC_IODC_RI_IO 4 /* Module input/output */
+#define PDC_IODC_RI_SPA 5 /* Module input/output */
+#define PDC_IODC_RI_CONFIG 6 /* Module input/output */
+/* 7 obsolete - HVERSION dependent */
+#define PDC_IODC_RI_TEST 8 /* Module input/output */
+#define PDC_IODC_RI_TLB 9 /* Module input/output */
+#define PDC_IODC_NINIT 2 /* non-destructive init */
+#define PDC_IODC_DINIT 3 /* destructive init */
+#define PDC_IODC_MEMERR 4 /* check for memory errors */
+#define PDC_IODC_INDEX_DATA 0 /* get first 16 bytes from mod IODC */
+#define PDC_IODC_BUS_ERROR -4 /* bus error return value */
+#define PDC_IODC_INVALID_INDEX -5 /* invalid index return value */
+#define PDC_IODC_COUNT -6 /* count is too small */
+
+#define PDC_TOD 9 /* time-of-day clock (TOD) */
+#define PDC_TOD_READ 0 /* read TOD */
+#define PDC_TOD_WRITE 1 /* write TOD */
+#define PDC_TOD_CALIBRATE 2 /* calibrate timers */
+
+#define PDC_STABLE 10 /* stable storage (sprockets) */
+#define PDC_STABLE_READ 0
+#define PDC_STABLE_WRITE 1
+#define PDC_STABLE_RETURN_SIZE 2
+#define PDC_STABLE_VERIFY_CONTENTS 3
+#define PDC_STABLE_INITIALIZE 4
+
+#define PDC_NVOLATILE 11 /* often not implemented */
+#define PDC_NVOLATILE_READ 0
+#define PDC_NVOLATILE_WRITE 1
+#define PDC_NVOLATILE_RETURN_SIZE 2
+#define PDC_NVOLATILE_VERIFY_CONTENTS 3
+#define PDC_NVOLATILE_INITIALIZE 4
+
+#define PDC_ADD_VALID 12 /* Memory validation PDC call */
+#define PDC_ADD_VALID_VERIFY 0 /* Make PDC_ADD_VALID verify region */
+
+#define PDC_DEBUG 14 /* Obsolete */
+
+#define PDC_INSTR 15 /* get instr to invoke PDCE_CHECK() */
+
+#define PDC_PROC 16 /* (sprockets) */
+
+#define PDC_CONFIG 17 /* (sprockets) */
+#define PDC_CONFIG_DECONFIG 0
+#define PDC_CONFIG_DRECONFIG 1
+#define PDC_CONFIG_DRETURN_CONFIG 2
+
+#define PDC_BLOCK_TLB 18 /* manage hardware block-TLB */
+#define PDC_BTLB_INFO 0 /* returns parameter */
+#define PDC_BTLB_INSERT 1 /* insert BTLB entry */
+#define PDC_BTLB_PURGE 2 /* purge BTLB entries */
+#define PDC_BTLB_PURGE_ALL 3 /* purge all BTLB entries */
+
+#define PDC_TLB 19 /* manage hardware TLB miss handling */
+#define PDC_TLB_INFO 0 /* returns parameter */
+#define PDC_TLB_SETUP 1 /* set up miss handling */
+
+#define PDC_MEM 20 /* Manage memory */
+#define PDC_MEM_MEMINFO 0 /* Return PDT info */
+#define PDC_MEM_ADD_PAGE 1 /* Add page to PDT */
+#define PDC_MEM_CLEAR_PDT 2 /* Clear PDT */
+#define PDC_MEM_READ_PDT 3 /* Read PDT entry */
+#define PDC_MEM_RESET_CLEAR 4 /* Reset PDT clear flag */
+#define PDC_MEM_GOODMEM 5 /* Set good_mem value */
+#define PDC_MEM_TABLE 128 /* Non contig mem map (sprockets) */
+#define PDC_MEM_RETURN_ADDRESS_TABLE PDC_MEM_TABLE
+#define PDC_MEM_GET_MEMORY_SYSTEM_TABLES_SIZE 131
+#define PDC_MEM_GET_MEMORY_SYSTEM_TABLES 132
+#define PDC_MEM_GET_PHYSICAL_LOCATION_FROM_MEMORY_ADDRESS 133
+
+#define PDC_MEM_RET_SBE_REPLACED 5 /* PDC_MEM return values */
+#define PDC_MEM_RET_DUPLICATE_ENTRY 4
+#define PDC_MEM_RET_BUF_SIZE_SMALL 1
+#define PDC_MEM_RET_PDT_FULL -11
+#define PDC_MEM_RET_INVALID_PHYSICAL_LOCATION ~0ULL
+
+#define PDC_PSW 21 /* Get/Set default System Mask */
+#define PDC_PSW_MASK 0 /* Return mask */
+#define PDC_PSW_GET_DEFAULTS 1 /* Return defaults */
+#define PDC_PSW_SET_DEFAULTS 2 /* Set default */
+#define PDC_PSW_ENDIAN_BIT 1 /* set for big endian */
+#define PDC_PSW_WIDE_BIT 2 /* set for wide mode */
+
+#define PDC_SYSTEM_MAP 22 /* find system modules */
+#define PDC_FIND_MODULE 0
+#define PDC_FIND_ADDRESS 1
+#define PDC_TRANSLATE_PATH 2
+
+#define PDC_SOFT_POWER 23 /* soft power switch */
+#define PDC_SOFT_POWER_INFO 0 /* return info about the soft power switch */
+#define PDC_SOFT_POWER_ENABLE 1 /* enable/disable soft power switch */
+
+#define PDC_ALLOC 24 /* allocate static storage for PDC & IODC */
+
+#define PDC_CRASH_PREP 25 /* Prepare system for crash dump */
+#define PDC_CRASH_DUMP 0 /* Do platform specific preparations for dump */
+#define PDC_CRASH_LOG_CEC_ERROR 1 /* Dump hardware registers */
+
+#define PDC_SCSI_PARMS 26 /* Get and set SCSI parameters */
+#define PDC_SCSI_GET_PARMS 0 /* Get SCSI parameters for I/O device */
+#define PDC_SCSI_SET_PARMS 1 /* Set SCSI parameters for I/O device */
+
+/* HVERSION dependent */
+
+/* The PDC_MEM_MAP calls */
+#define PDC_MEM_MAP 128 /* on s700: return page info */
+#define PDC_MEM_MAP_HPA 0 /* returns hpa of a module */
+
+#define PDC_EEPROM 129 /* EEPROM access */
+#define PDC_EEPROM_READ_WORD 0
+#define PDC_EEPROM_WRITE_WORD 1
+#define PDC_EEPROM_READ_BYTE 2
+#define PDC_EEPROM_WRITE_BYTE 3
+#define PDC_EEPROM_EEPROM_PASSWORD -1000
+
+#define PDC_NVM 130 /* NVM (non-volatile memory) access */
+#define PDC_NVM_READ_WORD 0
+#define PDC_NVM_WRITE_WORD 1
+#define PDC_NVM_READ_BYTE 2
+#define PDC_NVM_WRITE_BYTE 3
+
+#define PDC_SEED_ERROR 132 /* (sprockets) */
+
+#define PDC_IO 135 /* log error info, reset IO system */
+#define PDC_IO_READ_AND_CLEAR_ERRORS 0
+#define PDC_IO_RESET 1
+#define PDC_IO_RESET_DEVICES 2
+/* sets bits 6&7 (little endian) of the HcControl Register */
+#define PDC_IO_USB_SUSPEND 0xC000000000000000
+#define PDC_IO_EEPROM_IO_ERR_TABLE_FULL -5 /* return value */
+#define PDC_IO_NO_SUSPEND -6 /* return value */
+
+#define PDC_BROADCAST_RESET 136 /* reset all processors */
+#define PDC_DO_RESET 0 /* option: perform a broadcast reset */
+#define PDC_DO_FIRM_TEST_RESET 1 /* Do broadcast reset with bitmap */
+#define PDC_BR_RECONFIGURATION 2 /* reset w/reconfiguration */
+#define PDC_FIRM_TEST_MAGIC 0xab9ec36fUL /* for this reboot only */
+
+#define PDC_LAN_STATION_ID 138 /* Hversion dependent mechanism for */
+#define PDC_LAN_STATION_ID_READ 0 /* getting the lan station address */
+
+#define PDC_LAN_STATION_ID_SIZE 6
+
+#define PDC_CHECK_RANGES 139 /* (sprockets) */
+
+#define PDC_NV_SECTIONS 141 /* (sprockets) */
+
+#define PDC_PERFORMANCE 142 /* performance monitoring */
+
+#define PDC_SYSTEM_INFO 143 /* system information */
+#define PDC_SYSINFO_RETURN_INFO_SIZE 0
+#define PDC_SYSINFO_RRETURN_SYS_INFO 1
+#define PDC_SYSINFO_RRETURN_ERRORS 2
+#define PDC_SYSINFO_RRETURN_WARNINGS 3
+#define PDC_SYSINFO_RETURN_REVISIONS 4
+#define PDC_SYSINFO_RRETURN_DIAGNOSE 5
+#define PDC_SYSINFO_RRETURN_HV_DIAGNOSE 1005
+
+#define PDC_RDR 144 /* (sprockets) */
+#define PDC_RDR_READ_BUFFER 0
+#define PDC_RDR_READ_SINGLE 1
+#define PDC_RDR_WRITE_SINGLE 2
+
+#define PDC_INTRIGUE 145 /* (sprockets) */
+#define PDC_INTRIGUE_WRITE_BUFFER 0
+#define PDC_INTRIGUE_GET_SCRATCH_BUFSIZE 1
+#define PDC_INTRIGUE_START_CPU_COUNTERS 2
+#define PDC_INTRIGUE_STOP_CPU_COUNTERS 3
+
+#define PDC_STI 146 /* STI access */
+/* same as PDC_PCI_XXX values (see below) */
+
+/* Legacy PDC definitions for same stuff */
+#define PDC_PCI_INDEX 147
+#define PDC_PCI_INTERFACE_INFO 0
+#define PDC_PCI_SLOT_INFO 1
+#define PDC_PCI_INFLIGHT_BYTES 2
+#define PDC_PCI_READ_CONFIG 3
+#define PDC_PCI_WRITE_CONFIG 4
+#define PDC_PCI_READ_PCI_IO 5
+#define PDC_PCI_WRITE_PCI_IO 6
+#define PDC_PCI_READ_CONFIG_DELAY 7
+#define PDC_PCI_UPDATE_CONFIG_DELAY 8
+#define PDC_PCI_PCI_PATH_TO_PCI_HPA 9
+#define PDC_PCI_PCI_HPA_TO_PCI_PATH 10
+#define PDC_PCI_PCI_PATH_TO_PCI_BUS 11
+#define PDC_PCI_PCI_RESERVED 12
+#define PDC_PCI_PCI_INT_ROUTE_SIZE 13
+#define PDC_PCI_GET_INT_TBL_SIZE PDC_PCI_PCI_INT_ROUTE_SIZE
+#define PDC_PCI_PCI_INT_ROUTE 14
+#define PDC_PCI_GET_INT_TBL PDC_PCI_PCI_INT_ROUTE
+#define PDC_PCI_READ_MON_TYPE 15
+#define PDC_PCI_WRITE_MON_TYPE 16
+
+#define PDC_RELOCATE 149 /* (sprockets) */
+#define PDC_RELOCATE_GET_RELOCINFO 0
+#define PDC_RELOCATE_CHECKSUM 1
+#define PDC_RELOCATE_RELOCATE 2
+
+/* Get SCSI Interface Card info: SDTR, SCSI ID, mode (SE vs LVD) */
+#define PDC_INITIATOR 163
+#define PDC_GET_INITIATOR 0
+#define PDC_SET_INITIATOR 1
+#define PDC_DELETE_INITIATOR 2
+#define PDC_RETURN_TABLE_SIZE 3
+#define PDC_RETURN_TABLE 4
+
+#define PDC_LINK 165 /* (sprockets) */
+#define PDC_LINK_PCI_ENTRY_POINTS 0 /* list (Arg1) = 0 */
+#define PDC_LINK_USB_ENTRY_POINTS 1 /* list (Arg1) = 1 */
+
+/* cl_class
+ * page 3-33 of IO-Firmware ARS
+ * IODC ENTRY_INIT(Search first) RET[1]
+ */
+#define CL_NULL 0 /* invalid */
+#define CL_RANDOM 1 /* random access (as disk) */
+#define CL_SEQU 2 /* sequential access (as tape) */
+#define CL_DUPLEX 7 /* full-duplex point-to-point (RS-232, Net) */
+#define CL_KEYBD 8 /* half-duplex console (HIL Keyboard) */
+#define CL_DISPL 9 /* half-duplex console (display) */
+#define CL_FC 10 /* FiberChannel access media */
+
+/* IODC ENTRY_INIT() */
+#define ENTRY_INIT_SRCH_FRST 2
+#define ENTRY_INIT_SRCH_NEXT 3
+#define ENTRY_INIT_MOD_DEV 4
+#define ENTRY_INIT_DEV 5
+#define ENTRY_INIT_MOD 6
+#define ENTRY_INIT_MSG 9
+
+/* IODC ENTRY_IO() */
+#define ENTRY_IO_BOOTIN 0
+#define ENTRY_IO_BOOTOUT 1
+#define ENTRY_IO_CIN 2
+#define ENTRY_IO_COUT 3
+#define ENTRY_IO_CLOSE 4
+#define ENTRY_IO_GETMSG 9
+#define ENTRY_IO_BBLOCK_IN 16
+#define ENTRY_IO_BBLOCK_OUT 17
+
+/* IODC ENTRY_SPA() */
+
+/* IODC ENTRY_CONFIG() */
+
+/* IODC ENTRY_TEST() */
+
+/* IODC ENTRY_TLB() */
+
+/* constants for OS (NVM...) */
+#define OS_ID_NONE 0 /* Undefined OS ID */
+#define OS_ID_HPUX 1 /* HP-UX OS */
+#define OS_ID_MPEXL 2 /* MPE XL OS */
+#define OS_ID_OSF 3 /* OSF OS */
+#define OS_ID_HPRT 4 /* HP-RT OS */
+#define OS_ID_NOVEL 5 /* NOVELL OS */
+#define OS_ID_LINUX 6 /* Linux */
+
+
+/* constants for PDC_CHASSIS */
+#define OSTAT_OFF 0
+#define OSTAT_FLT 1
+#define OSTAT_TEST 2
+#define OSTAT_INIT 3
+#define OSTAT_SHUT 4
+#define OSTAT_WARN 5
+#define OSTAT_RUN 6
+#define OSTAT_ON 7
+
+/* Page Zero constant offsets used by the HPMC handler */
+#define BOOT_CONSOLE_HPA_OFFSET 0x3c0
+#define BOOT_CONSOLE_SPA_OFFSET 0x3c4
+#define BOOT_CONSOLE_PATH_OFFSET 0x3a8
+
+/* size of the pdc_result buffer for firmware.c */
+#define NUM_PDC_RESULT 32
+
+#if !defined(__ASSEMBLY__)
+
+/* flags of the device_path */
+#define PF_AUTOBOOT 0x80
+#define PF_AUTOSEARCH 0x40
+#define PF_TIMER 0x0F
+
+struct device_path { /* page 1-69 */
+ unsigned char flags; /* flags see above! */
+ unsigned char bc[6]; /* bus converter routing info */
+ unsigned char mod;
+ unsigned int layers[6];/* device-specific layer-info */
+} __attribute__((aligned(8))) ;
+
+struct pz_device {
+ struct device_path dp; /* see above */
+ /* struct iomod *hpa; */
+ unsigned int hpa; /* HPA base address */
+ /* char *spa; */
+ unsigned int spa; /* SPA base address */
+ /* int (*iodc_io)(struct iomod*, ...); */
+ unsigned int iodc_io; /* device entry point */
+ short pad; /* reserved */
+ unsigned short cl_class;/* see below */
+} __attribute__((aligned(8))) ;
+
+struct zeropage {
+ /* [0x000] initialize vectors (VEC) */
+ unsigned int vec_special; /* must be zero */
+ /* int (*vec_pow_fail)(void);*/
+ unsigned int vec_pow_fail; /* power failure handler */
+ /* int (*vec_toc)(void); */
+ unsigned int vec_toc;
+ unsigned int vec_toclen;
+ /* int (*vec_rendz)(void); */
+ unsigned int vec_rendz;
+ int vec_pow_fail_flen;
+ int vec_pad[10];
+
+ /* [0x040] reserved processor dependent */
+ int pad0[112]; /* in QEMU pad0[0] holds "SeaBIOS\0" */
+
+ /* [0x200] reserved */
+ int pad1[84];
+
+ /* [0x350] memory configuration (MC) */
+ int memc_cont; /* contiguous mem size (bytes) */
+ int memc_phsize; /* physical memory size */
+ int memc_adsize; /* additional mem size, bytes of SPA space used by PDC */
+ unsigned int mem_pdc_hi; /* used for 64-bit */
+
+ /* [0x360] various parameters for the boot-CPU */
+ /* unsigned int *mem_booterr[8]; */
+ unsigned int mem_booterr[8]; /* ptr to boot errors */
+ unsigned int mem_free; /* first location, where OS can be loaded */
+ /* struct iomod *mem_hpa; */
+ unsigned int mem_hpa; /* HPA of the boot-CPU */
+ /* int (*mem_pdc)(int, ...); */
+ unsigned int mem_pdc; /* PDC entry point */
+ unsigned int mem_10msec; /* number of clock ticks in 10msec */
+
+ /* [0x390] initial memory module (IMM) */
+ /* struct iomod *imm_hpa; */
+ unsigned int imm_hpa; /* HPA of the IMM */
+ int imm_soft_boot; /* 0 = was hard boot, 1 = was soft boot */
+ unsigned int imm_spa_size; /* SPA size of the IMM in bytes */
+ unsigned int imm_max_mem; /* bytes of mem in IMM */
+
+ /* [0x3A0] boot console, display device and keyboard */
+ struct pz_device mem_cons; /* description of console device */
+ struct pz_device mem_boot; /* description of boot device */
+ struct pz_device mem_kbd; /* description of keyboard device */
+
+ /* [0x430] reserved */
+ int pad430[116];
+
+ /* [0x600] processor dependent */
+ unsigned int pad600[1];
+ unsigned int proc_sti; /* pointer to STI ROM */
+ unsigned int pad608[126];
+};
+
+struct pdc_chassis_info { /* for PDC_CHASSIS_INFO */
+ unsigned long actcnt; /* actual number of bytes returned */
+ unsigned long maxcnt; /* maximum number of bytes that could be returned */
+};
+
+struct pdc_coproc_cfg { /* for PDC_COPROC_CFG */
+ unsigned long ccr_functional;
+ unsigned long ccr_present;
+ unsigned long revision;
+ unsigned long model;
+};
+
+struct pdc_model { /* for PDC_MODEL */
+ unsigned long hversion;
+ unsigned long sversion;
+ unsigned long hw_id;
+ unsigned long boot_id;
+ unsigned long sw_id;
+ unsigned long sw_cap;
+ unsigned long arch_rev;
+ unsigned long pot_key;
+ unsigned long curr_key;
+};
+
+struct pdc_cache_cf { /* for PDC_CACHE (I/D-caches) */
+ unsigned long
+#ifdef __LP64__
+ cc_padW:32,
+#endif
+ cc_alias: 4, /* alias boundaries for virtual addresses */
+ cc_block: 4, /* to determine most efficient stride */
+ cc_line : 3, /* maximum amount written back as a result of store (multiple of 16 bytes) */
+ cc_shift: 2, /* how much to shift cc_block left */
+ cc_wt : 1, /* 0 = WT-Dcache, 1 = WB-Dcache */
+ cc_sh : 2, /* 0 = separate I/D-cache, else shared I/D-cache */
+ cc_cst : 3, /* 0 = incoherent D-cache, 1=coherent D-cache */
+ cc_pad1 : 10, /* reserved */
+ cc_hv : 3; /* hversion dependent */
+};
+
+struct pdc_tlb_cf { /* for PDC_CACHE (I/D-TLB's) */
+ unsigned long tc_pad0:12, /* reserved */
+#ifdef __LP64__
+ tc_padW:32,
+#endif
+ tc_sh : 2, /* 0 = separate I/D-TLB, else shared I/D-TLB */
+ tc_hv : 1, /* HV */
+ tc_page : 1, /* 0 = 2K page-size-machine, 1 = 4k page size */
+ tc_cst : 3, /* 0 = incoherent operations, else coherent operations */
+ tc_aid : 5, /* ITLB: width of access ids of processor (encoded!) */
+ tc_sr : 8; /* ITLB: width of space-registers (encoded) */
+};
+
+struct pdc_cache_info { /* main-PDC_CACHE-structure (caches & TLB's) */
+ /* I-cache */
+ unsigned long ic_size; /* size in bytes */
+ struct pdc_cache_cf ic_conf; /* configuration */
+ unsigned long ic_base; /* base-addr */
+ unsigned long ic_stride;
+ unsigned long ic_count;
+ unsigned long ic_loop;
+ /* D-cache */
+ unsigned long dc_size; /* size in bytes */
+ struct pdc_cache_cf dc_conf; /* configuration */
+ unsigned long dc_base; /* base-addr */
+ unsigned long dc_stride;
+ unsigned long dc_count;
+ unsigned long dc_loop;
+ /* Instruction-TLB */
+ unsigned long it_size; /* number of entries in I-TLB */
+ struct pdc_tlb_cf it_conf; /* I-TLB-configuration */
+ unsigned long it_sp_base;
+ unsigned long it_sp_stride;
+ unsigned long it_sp_count;
+ unsigned long it_off_base;
+ unsigned long it_off_stride;
+ unsigned long it_off_count;
+ unsigned long it_loop;
+ /* data-TLB */
+ unsigned long dt_size; /* number of entries in D-TLB */
+ struct pdc_tlb_cf dt_conf; /* D-TLB-configuration */
+ unsigned long dt_sp_base;
+ unsigned long dt_sp_stride;
+ unsigned long dt_sp_count;
+ unsigned long dt_off_base;
+ unsigned long dt_off_stride;
+ unsigned long dt_off_count;
+ unsigned long dt_loop;
+};
+
+/* Might need adjustment to work with 64-bit firmware */
+struct pdc_iodc { /* PDC_IODC */
+ unsigned char hversion_model;
+ unsigned char hversion;
+ unsigned char spa;
+ unsigned char type;
+ unsigned int sversion_rev:4;
+ unsigned int sversion_model:19;
+ unsigned int sversion_opt:8;
+ unsigned char rev;
+ unsigned char dep;
+ unsigned char features;
+ unsigned char pad1;
+ unsigned int checksum:16;
+ unsigned int length:16;
+ unsigned int pad[15];
+} __attribute__((aligned(8))) ;
+
+/* no BLTBs in pa2.0 processors */
+struct pdc_btlb_info_range {
+ unsigned char res00;
+ unsigned char num_i;
+ unsigned char num_d;
+ unsigned char num_comb;
+};
+
+struct pdc_btlb_info { /* PDC_BLOCK_TLB, return of PDC_BTLB_INFO */
+ unsigned int min_size; /* minimum size of BTLB in pages */
+ unsigned int max_size; /* maximum size of BTLB in pages */
+ struct pdc_btlb_info_range fixed_range_info;
+ struct pdc_btlb_info_range variable_range_info;
+};
+
+struct pdc_mem_retinfo { /* PDC_MEM/PDC_MEM_MEMINFO (return info) */
+ unsigned long pdt_size;
+ unsigned long pdt_entries;
+ unsigned long pdt_status;
+ unsigned long first_dbe_loc;
+ unsigned long good_mem;
+};
+
+struct pdc_mem_read_pdt { /* PDC_MEM/PDC_MEM_READ_PDT (return info) */
+ unsigned long pdt_entries;
+};
+
+#ifdef __LP64__
+struct pdc_memory_table_raddr { /* PDC_MEM/PDC_MEM_TABLE (return info) */
+ unsigned long entries_returned;
+ unsigned long entries_total;
+};
+
+struct pdc_memory_table { /* PDC_MEM/PDC_MEM_TABLE (arguments) */
+ unsigned long paddr;
+ unsigned int pages;
+ unsigned int reserved;
+};
+#endif /* __LP64__ */
+
+struct pdc_system_map_mod_info { /* PDC_SYSTEM_MAP/FIND_MODULE */
+ unsigned long mod_addr;
+ unsigned long mod_pgs;
+ unsigned long add_addrs;
+};
+
+struct pdc_system_map_addr_info { /* PDC_SYSTEM_MAP/FIND_ADDRESS */
+ unsigned long mod_addr;
+ unsigned long mod_pgs;
+};
+
+struct pdc_initiator { /* PDC_INITIATOR */
+ int host_id;
+ int factor;
+ int width;
+ int mode;
+};
+
+struct hardware_path {
+ char flags; /* see bit definitions below */
+ char bc[6]; /* Bus Converter routing info to a specific */
+ /* I/O adaptor (< 0 means none, > 63 resvd) */
+ char mod; /* fixed field of specified module */
+};
+
+/*
+ * Device path specifications used by PDC.
+ */
+struct pdc_module_path {
+ struct hardware_path path;
+ unsigned int layers[6]; /* device-specific info (ctlr #, unit # ...) */
+};
+
+/* Only used on some pre-PA2.0 boxes */
+struct pdc_memory_map { /* PDC_MEMORY_MAP */
+ unsigned long hpa; /* mod's register set address */
+ unsigned long more_pgs; /* number of additional I/O pgs */
+};
+
+struct pdc_tod {
+ unsigned long tod_sec;
+ unsigned long tod_usec;
+};
+
+/* architected results from PDC_PIM/transfer hpmc on a PA1.1 machine */
+
+struct pdc_hpmc_pim_11 { /* PDC_PIM */
+ unsigned int gr[32];
+ unsigned int cr[32];
+ unsigned int sr[8];
+ unsigned int iasq_back;
+ unsigned int iaoq_back;
+ unsigned int check_type;
+ unsigned int cpu_state;
+ unsigned int rsvd1;
+ unsigned int cache_check;
+ unsigned int tlb_check;
+ unsigned int bus_check;
+ unsigned int assists_check;
+ unsigned int rsvd2;
+ unsigned int assist_state;
+ unsigned int responder_addr;
+ unsigned int requestor_addr;
+ unsigned int path_info;
+ unsigned long long fr[32];
+};
+
+/*
+ * architected results from PDC_PIM/transfer hpmc on a PA2.0 machine
+ *
+ * Note that PDC_PIM doesn't care whether or not wide mode was enabled
+ * so the results are different on PA1.1 vs. PA2.0 when in narrow mode.
+ *
+ * Note also that there are unarchitected results available, which
+ * are hversion dependent. Do a "ser pim 0 hpmc" after rebooting, since
+ * the firmware is probably the best way of printing hversion dependent
+ * data.
+ */
+
+struct pdc_hpmc_pim_20 { /* PDC_PIM */
+ unsigned long long gr[32];
+ unsigned long long cr[32];
+ unsigned long long sr[8];
+ unsigned long long iasq_back;
+ unsigned long long iaoq_back;
+ unsigned int check_type;
+ unsigned int cpu_state;
+ unsigned int cache_check;
+ unsigned int tlb_check;
+ unsigned int bus_check;
+ unsigned int assists_check;
+ unsigned int assist_state;
+ unsigned int path_info;
+ unsigned long long responder_addr;
+ unsigned long long requestor_addr;
+ unsigned long long fr[32];
+};
+
+#endif /* !defined(__ASSEMBLY__) */
+
+#endif /* _UAPI_PARISC_PDC_H */
diff --git a/roms/seabios-hppa/src/parisc/sti.c b/roms/seabios-hppa/src/parisc/sti.c
new file mode 100644
index 000000000..7c7fb5412
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/sti.c
@@ -0,0 +1,179 @@
+/* STI console code
+ *
+ * Copyright (C) 2019 Sven Schnelle <svens@stackframe.org>
+ *
+ * This file may be distributed under the terms of the GNU LGPLv3 license.
+ */
+
+#include "autoconf.h"
+#include "types.h"
+#include "std/optionrom.h"
+#include "vgahw.h"
+#include "parisc/sticore.h"
+#include "parisc/hppa_hardware.h"
+#include "output.h"
+#include "pdc.h"
+
+#define PAGE0 ((volatile struct zeropage *) 0UL)
+
+static int sti_enabled;
+
+static struct sti_init_flags sti_init_flags = {
+ .wait = 1,
+ .reset = 1,
+ .text = 1,
+ .nontext = 1,
+ .cmap_blk = 1,
+ .no_chg_bet = 1,
+ .no_chg_bei = 1,
+ .init_cmap_tx = 1,
+ .clear = 1,
+};
+
+static struct sti_glob_cfg_ext sti_glob_ext_cfg = {
+};
+
+static struct sti_glob_cfg sti_glob_cfg = {
+ .region_ptrs = { 0, ARTIST_FB_ADDR, 0xf8100000, 0xf8380000, 0, 0, 0, 0 },
+ .ext_ptr = (u32)&sti_glob_ext_cfg,
+};
+
+static struct sti_init_inptr_ext sti_init_inptr_ext = {
+ .config_mon_type = 1,
+};
+
+static struct sti_init_inptr sti_init_inptr = {
+ .text_planes = 3,
+ .ext_ptr = (u32)&sti_init_inptr_ext,
+};
+
+static struct sti_init_outptr sti_init_outptr = {
+};
+
+static struct sti_font_flags sti_font_flags = {
+ .wait = 1,
+};
+
+static struct sti_font_inptr sti_font_inptr = {
+ .fg_color = 1,
+ .bg_color = 0,
+};
+
+static struct sti_font_outptr sti_font_outptr = {
+};
+
+static struct sti_blkmv_flags sti_blkmv_flags = {
+ .wait = 1,
+};
+
+static struct sti_blkmv_inptr sti_blkmv_inptr = {
+};
+
+static struct sti_blkmv_outptr sti_blkmv_outptr = {
+};
+
+static void sti_putchar(struct sti_rom *rom, int row, int column, const char c)
+{
+ int (*sti_unpmv)(struct sti_font_flags *,
+ struct sti_font_inptr *,
+ struct sti_font_outptr *,
+ struct sti_glob_cfg *);
+
+ struct sti_rom_font *font = (void *)rom + rom->font_start;
+ sti_unpmv = (void *)rom + rom->font_unpmv;
+
+ sti_font_inptr.dest_x = column * font->width;
+ sti_font_inptr.dest_y = row * font->height;
+ sti_font_inptr.index = c;
+ sti_font_inptr.font_start_addr = (u32)rom + rom->font_start;
+
+ sti_unpmv(&sti_font_flags, &sti_font_inptr,
+ &sti_font_outptr, &sti_glob_cfg);
+}
+
+static void sti_block_move(struct sti_rom *rom, int src_x, int src_y,
+ int dest_x, int dest_y,
+ int width, int height,
+ int clear)
+{
+ int (*sti_block_move)(struct sti_blkmv_flags *,
+ struct sti_blkmv_inptr *,
+ struct sti_blkmv_outptr *,
+ struct sti_glob_cfg *);
+ sti_block_move = (void *)rom + rom->block_move;
+
+ sti_blkmv_inptr.src_x = src_x;
+ sti_blkmv_inptr.src_y = src_y;
+ sti_blkmv_inptr.dest_x = dest_x;
+ sti_blkmv_inptr.dest_y = dest_y;
+ sti_blkmv_inptr.width = width;
+ sti_blkmv_inptr.height = height;
+ sti_blkmv_flags.clear = clear;
+
+ sti_block_move(&sti_blkmv_flags, &sti_blkmv_inptr,
+ &sti_blkmv_outptr, &sti_glob_cfg);
+}
+
+void sti_console_init(struct sti_rom *rom)
+{
+ int (*sti_init)(struct sti_init_flags *,
+ struct sti_init_inptr *,
+ struct sti_init_outptr *,
+ struct sti_glob_cfg *);
+
+ sti_init = (void *)rom + rom->init_graph;
+
+ sti_init(&sti_init_flags, &sti_init_inptr,
+ &sti_init_outptr, &sti_glob_cfg);
+
+ sti_enabled = 1;
+}
+
+void sti_putc(const char c)
+{
+ struct sti_rom *rom = (struct sti_rom *)PAGE0->proc_sti;
+ struct sti_rom_font *font = (void *)rom + rom->font_start;
+ static int row, col;
+
+ if (!sti_enabled)
+ return;
+
+ if (c == '\r') {
+ col = 0;
+ return;
+ }
+
+ if (c == 0x08) {
+ if (col > 0)
+ col--;
+ return;
+ }
+
+ if (c == '\n') {
+ col = 0;
+ row++;
+
+ if (row >= sti_glob_cfg.onscreen_y / font->height) {
+ sti_block_move(rom,
+ 0, font->height,
+ 0, 0,
+ sti_glob_cfg.total_x, sti_glob_cfg.onscreen_y - font->height, 0);
+
+ /* clear new line at bottom */
+ sti_block_move(rom,
+ 0, 0, /* source */
+ 0, sti_glob_cfg.onscreen_y - font->height, /* dest */
+ sti_glob_cfg.onscreen_x, font->height,
+ 1);
+
+ row = (sti_glob_cfg.onscreen_y / font->height)-1;
+ }
+ return;
+ }
+
+ /* wrap to next line or scroll screen if EOL reached */
+ if (col >= ((sti_glob_cfg.onscreen_x / font->width) - 1))
+ sti_putc('\n');
+
+ sti_putchar(rom, row, col++, c);
+}
diff --git a/roms/seabios-hppa/src/parisc/sticore.h b/roms/seabios-hppa/src/parisc/sticore.h
new file mode 100644
index 000000000..0c5556ba8
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/sticore.h
@@ -0,0 +1,326 @@
+/* SPDX-License-Identifier:GPL-2.0 */
+#ifndef STICORE_H
+#define STICORE_H
+
+#include "types.h"
+
+/* generic STI structures & functions */
+
+#define MAX_STI_ROMS 4 /* max no. of ROMs which this driver handles */
+
+#define STI_REGION_MAX 8 /* hardcoded STI constants */
+#define STI_DEV_NAME_LENGTH 32
+#define STI_MONITOR_MAX 256
+
+#define STI_FONT_HPROMAN8 1
+#define STI_FONT_KANA8 2
+
+#define ALT_CODE_TYPE_UNKNOWN 0x00 /* alt code type values */
+#define ALT_CODE_TYPE_PA_RISC_64 0x01
+
+#define STI_WAIT 1
+
+/* STI function configuration structs */
+
+typedef union region {
+ struct {
+ u32 offset:14; /* offset in 4kbyte page */
+ u32 sys_only:1; /* don't map to user space */
+ u32 cache:1; /* map to data cache */
+ u32 btlb:1; /* map to block tlb */
+ u32 last:1; /* last region in list */
+ u32 length:14; /* length in 4kbyte page */
+ } region_desc;
+
+ u32 region; /* complete region value */
+} region_t;
+
+struct sti_glob_cfg_ext {
+ u8 curr_mon; /* current monitor configured */
+ u8 friendly_boot; /* in friendly boot mode */
+ s16 power; /* power calculation (in Watts) */
+ s32 freq_ref; /* frequency reference */
+ u32 sti_mem_addr; /* pointer to global sti memory (size=sti_mem_request) */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_glob_cfg {
+ s32 text_planes; /* number of planes used for text */
+ s16 onscreen_x; /* screen width in pixels */
+ s16 onscreen_y; /* screen height in pixels */
+ s16 offscreen_x; /* offset width in pixels */
+ s16 offscreen_y; /* offset height in pixels */
+ s16 total_x; /* frame buffer width in pixels */
+ s16 total_y; /* frame buffer height in pixels */
+ u32 region_ptrs[STI_REGION_MAX]; /* region pointers */
+ s32 reent_lvl; /* storage for reentry level value */
+ u32 save_addr; /* where to save or restore reentrant state */
+ u32 ext_ptr; /* pointer to extended glob_cfg data structure */
+};
+
+
+/* STI init function structs */
+
+struct sti_init_flags {
+ u32 wait:1; /* should routine idle wait or not */
+ u32 reset:1; /* hard reset the device? */
+ u32 text:1; /* turn on text display planes? */
+ u32 nontext:1; /* turn on non-text display planes? */
+ u32 clear:1; /* clear text display planes? */
+ u32 cmap_blk:1; /* non-text planes cmap black? */
+ u32 enable_be_timer:1; /* enable bus error timer */
+ u32 enable_be_int:1; /* enable bus error timer interrupt */
+ u32 no_chg_tx:1; /* don't change text settings */
+ u32 no_chg_ntx:1; /* don't change non-text settings */
+ u32 no_chg_bet:1; /* don't change berr timer settings */
+ u32 no_chg_bei:1; /* don't change berr int settings */
+ u32 init_cmap_tx:1; /* initialize cmap for text planes */
+ u32 cmt_chg:1; /* change current monitor type */
+ u32 retain_ie:1; /* don't allow reset to clear int enables */
+ u32 caller_bootrom:1; /* set only by bootrom for each call */
+ u32 caller_kernel:1; /* set only by kernel for each call */
+ u32 caller_other:1; /* set only by non-[BR/K] caller */
+ u32 pad:14; /* pad to word boundary */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_init_inptr_ext {
+ u8 config_mon_type; /* configure to monitor type */
+ u8 pad[1]; /* pad to word boundary */
+ u16 inflight_data; /* inflight data possible on PCI */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_init_inptr {
+ s32 text_planes; /* number of planes to use for text */
+ u32 ext_ptr; /* pointer to extended init_graph inptr data structure*/
+};
+
+
+struct sti_init_outptr {
+ s32 errno; /* error number on failure */
+ s32 text_planes; /* number of planes used for text */
+ u32 future_ptr; /* pointer to future data */
+};
+
+/* STI configuration function structs */
+
+struct sti_conf_flags {
+ u32 wait:1; /* should routine idle wait or not */
+ u32 pad:31; /* pad to word boundary */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_conf_inptr {
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_conf_outptr_ext {
+ u32 crt_config[3]; /* hardware specific X11/OGL information */
+ u32 crt_hdw[3];
+ u32 future_ptr;
+};
+
+struct sti_conf_outptr {
+ s32 errno; /* error number on failure */
+ s16 onscreen_x; /* screen width in pixels */
+ s16 onscreen_y; /* screen height in pixels */
+ s16 offscreen_x; /* offscreen width in pixels */
+ s16 offscreen_y; /* offscreen height in pixels */
+ s16 total_x; /* frame buffer width in pixels */
+ s16 total_y; /* frame buffer height in pixels */
+ s32 bits_per_pixel; /* bits/pixel device has configured */
+ s32 bits_used; /* bits which can be accessed */
+ s32 planes; /* number of fb planes in system */
+ u8 dev_name[STI_DEV_NAME_LENGTH]; /* null terminated product name */
+ u32 attributes; /* flags denoting attributes */
+ u32 ext_ptr; /* pointer to future data */
+};
+
+typedef struct {
+ u32 x:12;
+ u32 y:12;
+ u32 hz:7;
+ u32 class_flat:1;
+ u32 class_vesa:1;
+ u32 class_grey:1;
+ u32 class_dbl:1;
+ u32 class_user:1;
+ u32 class_stereo:1;
+ u32 class_sam:1;
+ u32 pad:15;
+ u32 hz_upper:3;
+ u32 index:8;
+} mon_tbl_desc;
+
+struct sti_rom {
+ u8 type[4];
+ u8 res004;
+ u8 num_mons;
+ u8 revno[2];
+ u32 graphics_id[2];
+
+ u32 font_start;
+ u32 statesize;
+ u32 last_addr;
+ u32 region_list;
+
+ u16 reentsize;
+ u16 maxtime;
+ u32 mon_tbl_addr;
+ u32 user_data_addr;
+ u32 sti_mem_req;
+
+ u32 user_data_size;
+ u16 power;
+ u8 bus_support;
+ u8 ext_bus_support;
+ u8 alt_code_type;
+ u8 ext_dd_struct[3];
+ u32 cfb_addr;
+
+ u32 init_graph;
+ u32 state_mgmt;
+ u32 font_unpmv;
+ u32 block_move;
+ u32 self_test;
+ u32 excep_hdlr;
+ u32 inq_conf;
+ u32 set_cm_entry;
+ u32 dma_ctrl;
+ u32 flow_ctrl;
+ u32 user_timing;
+ u32 process_mgr;
+ u32 sti_util;
+ u32 end;
+
+ u32 res040[2];
+
+ u32 init_graph_addr;
+ u32 state_mgmt_addr;
+ u32 font_unp_addr;
+ u32 block_move_addr;
+ u32 self_test_addr;
+ u32 excep_hdlr_addr;
+ u32 inq_conf_addr;
+ u32 set_cm_entry_addr;
+ u32 image_unpack_addr;
+ u32 pa_risx_addrs[7];
+};
+
+
+struct sti_rom_font {
+ u16 first_char;
+ u16 last_char;
+ u8 width;
+ u8 height;
+ u8 font_type; /* language type */
+ u8 bytes_per_char;
+ u32 next_font;
+ u8 underline_height;
+ u8 underline_pos;
+ u8 res008[2];
+};
+
+struct font {
+ struct sti_rom_font hdr;
+ unsigned char font[16*256];
+};
+
+/* STI font printing function structs */
+
+struct sti_font_inptr {
+ u32 font_start_addr; /* address of font start */
+ s16 index; /* index into font table of character */
+ u8 fg_color; /* foreground color of character */
+ u8 bg_color; /* background color of character */
+ s16 dest_x; /* X location of character upper left */
+ s16 dest_y; /* Y location of character upper left */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_font_flags {
+ u32 wait:1; /* should routine idle wait or not */
+ u32 non_text:1; /* font unpack/move in non_text planes =1, text =0 */
+ u32 pad:30; /* pad to word boundary */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_font_outptr {
+ s32 errno; /* error number on failure */
+ u32 future_ptr; /* pointer to future data */
+};
+
+/* STI blockmove structs */
+
+struct sti_blkmv_flags {
+ u32 wait:1; /* should routine idle wait or not */
+ u32 color:1; /* change color during move? */
+ u32 clear:1; /* clear during move? */
+ u32 non_text:1; /* block move in non_text planes =1, text =0 */
+ u32 pad:28; /* pad to word boundary */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_blkmv_inptr {
+ u8 fg_color; /* foreground color after move */
+ u8 bg_color; /* background color after move */
+ s16 src_x; /* source upper left pixel x location */
+ s16 src_y; /* source upper left pixel y location */
+ s16 dest_x; /* dest upper left pixel x location */
+ s16 dest_y; /* dest upper left pixel y location */
+ s16 width; /* block width in pixels */
+ s16 height; /* block height in pixels */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_blkmv_outptr {
+ s32 errno; /* error number on failure */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_state_flags {
+ u32 wait:1; /* should routing idle wait or not */
+ u32 save:1; /* save (1) or restore (0) state */
+ u32 res_disp:1; /* restore all display planes */
+ u32 pad:29; /* pad to word boundary */
+ s32 *future_ptr; /* pointer to future data */
+};
+
+struct sti_state_inptr {
+ s32 *save_addr; /* where to save or restore state */
+ s32 *future_ptr; /* pointer to future data */
+};
+
+struct sti_state_outptr {
+ s32 errno; /* error number on failure */
+ s32 *future_ptr; /* pointer to future data */
+};
+
+struct setcm_flags {
+ u32 wait:1; /* should routine idle wait or not */
+ u32 pad:31; /* pad to word boundary */
+ s32 *future_ptr; /* pointer to future data */
+};
+
+struct setcm_inptr {
+ s32 entry; /* entry number */
+ u32 value; /* entry value */
+ s32 *future_ptr; /* pointer to future data */
+};
+
+struct setcm_outptr {
+ s32 errno; /* error number on failure */
+ s32 *future_ptr; /* pointer to future data */
+};
+
+void sti_rom_init(void);
+void sti_console_init(struct sti_rom *rom);
+void sti_putc(const char c);
+
+extern struct sti_rom sti_proc_rom;
+extern char _sti_rom_end[];
+extern char _sti_rom_start[];
+extern void parisc_screenc(char c);
+
+#endif /* STICORE_H */
diff --git a/roms/seabios-hppa/src/parisc/stirom.c b/roms/seabios-hppa/src/parisc/stirom.c
new file mode 100644
index 000000000..07e89c395
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/stirom.c
@@ -0,0 +1,652 @@
+#include "sticore.h"
+#include "hppa.h"
+
+#define ARTIST_VRAM_IDX 0x4a0
+#define ARTIST_VRAM_BITMASK 0x5a0
+#define ARTIST_VRAM_WRITE_INCR_X 0x600
+#define ARTIST_VRAM_BYTE_WRITE 0x620
+#define ARTIST_CMAP_ACCESS 0x18000
+#define ARTIST_DST_BM_ACCESS 0x18004
+#define ARTIST_SRC_BM_ACCESS 0x18008
+#define ARTIST_BGCOLOR 0x18014
+#define ARTIST_FGCOLOR 0x18010
+#define ARTIST_BITMAP_OP 0x1801c
+#define ARTIST_PLANE_BITMASK 0x18018
+#define ARTIST_VRAM_DEST 0x800
+#define ARTIST_VRAM_SIZE 0x804
+#define ARTIST_VRAM_SRC 0x808
+
+#define ARTIST_VRAM_SIZE_TRIGGER_WINFILL 0xa04
+#define ARTIST_VRAM_DEST_TRIGGER_BLOCKMOVE 0xb00
+
+#define __stiheader __attribute__((section(".sti.hdr")))
+#define __stidata __attribute__((section(".sti.data")))
+#define __stitext __attribute__((section(".sti.text")))
+
+/* Don't ask - HP-UX assumes a certain order of functions
+ * when it copies them to RAM. So we put the functions into
+ * different sections and order them in the linker script.
+ */
+
+#define __stifunc(_name) __attribute__((section(".sti.text." _name)))
+
+static const __stidata char user_data[256] __aligned(32);
+
+static const region_t sti_region_list[STI_REGION_MAX] __stidata __aligned(32) = {
+ { .region_desc = { .offset = 0, .btlb = 1, .length = 2 }, },
+ { .region_desc = { .offset = (ARTIST_FB_ADDR - LASI_GFX_HPA) / 4096, .btlb = 1, .length = (ARTIST_FB_ADDR - LASI_GFX_HPA) / 4096} },
+ { .region_desc = { .offset = (0xf8100000 - LASI_GFX_HPA)/ 4096, .btlb = 1, .length = ((0xf8380000-0xf8100000) / 4096), } },
+ { .region_desc = { .offset = (0xf8380000 - LASI_GFX_HPA)/ 4096, .sys_only = 1, .length = 1, .last = 1, } }
+};
+
+static const struct font __stidata __aligned(32) sti_rom_font = {
+ .hdr = {
+ .first_char = 0,
+ .last_char = 255,
+ .width = 8,
+ .height = 16,
+ .font_type = STI_FONT_HPROMAN8,
+ .bytes_per_char = 16,
+ .underline_height = 1,
+ .underline_pos = 15,
+ },
+ .font = {
+ 0x00, 0x48, 0x68, 0x58, 0x48, 0x48, 0x00, 0x12, 0x12, 0x12, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x30, 0x08, 0x70, 0x00, 0x12, 0x12, 0x1e, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x30, 0x08, 0x70, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x78, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x78, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x78, 0x00, 0x1c, 0x22, 0x22, 0x2a, 0x1c, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x78, 0x48, 0x48, 0x00, 0x12, 0x14, 0x18, 0x14, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x48, 0x70, 0x00, 0x0e, 0x10, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x48, 0x78, 0x48, 0x48, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x40, 0x40, 0x40, 0x40, 0x78, 0x00, 0x1e, 0x10, 0x1c, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x44, 0x44, 0x28, 0x28, 0x10, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x40, 0x00, 0x1e, 0x10, 0x1c, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x40, 0x40, 0x38, 0x00, 0x1c, 0x12, 0x1c, 0x14, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x30, 0x08, 0x70, 0x00, 0x0c, 0x12, 0x12, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x30, 0x08, 0x70, 0x00, 0x0e, 0x04, 0x04, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x48, 0x48, 0x70, 0x00, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x48, 0x48, 0x70, 0x00, 0x04, 0x0c, 0x04, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x48, 0x48, 0x70, 0x0c, 0x12, 0x02, 0x0c, 0x10, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x48, 0x48, 0x70, 0x00, 0x1c, 0x02, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x48, 0x48, 0x70, 0x00, 0x14, 0x14, 0x1e, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x68, 0x58, 0x48, 0x48, 0x00, 0x12, 0x14, 0x18, 0x14, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x30, 0x08, 0x70, 0x00, 0x22, 0x14, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x78, 0x00, 0x1c, 0x12, 0x1c, 0x12, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x40, 0x40, 0x38, 0x00, 0x12, 0x1a, 0x16, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x78, 0x00, 0x22, 0x36, 0x2a, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x30, 0x08, 0x70, 0x00, 0x1c, 0x12, 0x1c, 0x12, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x78, 0x00, 0x0e, 0x10, 0x10, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x40, 0x00, 0x0e, 0x10, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x58, 0x48, 0x38, 0x00, 0x0e, 0x10, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x50, 0x48, 0x00, 0x0e, 0x10, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x48, 0x48, 0x48, 0x30, 0x00, 0x0e, 0x10, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x24, 0x24, 0x7e, 0x24, 0x24, 0x24, 0x24, 0x7e, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x54, 0x50, 0x30, 0x18, 0x14, 0x54, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x24, 0x54, 0x28, 0x08, 0x10, 0x10, 0x20, 0x24, 0x4a, 0x44, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x48, 0x48, 0x50, 0x20, 0x50, 0x8a, 0x84, 0x8c, 0x72, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x7c, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x5a, 0x5a, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x0c, 0x10, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x1c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x0c, 0x14, 0x24, 0x44, 0x7e, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x02, 0x02, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x04, 0x08, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x4e, 0x52, 0x52, 0x52, 0x4c, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x4e, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x42, 0x44, 0x48, 0x50, 0x70, 0x48, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x42, 0x66, 0x5a, 0x5a, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x62, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x46, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x4a, 0x3c, 0x04, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x50, 0x48, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x3c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x82, 0x82, 0x44, 0x44, 0x44, 0x28, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x5a, 0x5a, 0x66, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x82, 0x82, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x22, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x18, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x44, 0x48, 0x50, 0x68, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x92, 0x92, 0x92, 0x92, 0x92, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x32, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x40, 0x3c, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x44, 0x44, 0x28, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x92, 0x92, 0x92, 0x92, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08, 0x10, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x00, 0x00, 0x30, 0x08, 0x08, 0x08, 0x08, 0x04, 0x08, 0x08, 0x08, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x2a, 0x54, 0x2a, 0x54, 0x2a, 0x54, 0x2a, 0x54, 0x2a, 0x54, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x40, 0x40, 0x38, 0x00, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x20, 0x20, 0x20, 0x70, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x48, 0x70, 0x00, 0x0c, 0x10, 0x16, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x20, 0x20, 0x20, 0x70, 0x00, 0x1c, 0x12, 0x1c, 0x12, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x48, 0x48, 0x48, 0x30, 0x00, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x70, 0x20, 0x20, 0x20, 0x70, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x48, 0x70, 0x00, 0x0c, 0x10, 0x16, 0x12, 0x0c, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x70, 0x20, 0x20, 0x20, 0x70, 0x00, 0x1c, 0x12, 0x1c, 0x12, 0x1c, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0xa8, 0xa8, 0xa8, 0xa8, 0x50, 0x00, 0x12, 0x12, 0x1e, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x50, 0x48, 0x00, 0x1c, 0x12, 0x12, 0x12, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x48, 0x30, 0x10, 0x10, 0x00, 0x1e, 0x10, 0x1c, 0x10, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x40, 0x58, 0x48, 0x30, 0x00, 0x1c, 0x12, 0x1c, 0x14, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x40, 0x40, 0x38, 0x00, 0x12, 0x12, 0x0c, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x48, 0x70, 0x00, 0x12, 0x12, 0x12, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x88, 0xd8, 0xa8, 0x88, 0x88, 0x00, 0x0c, 0x10, 0x16, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x48, 0x70, 0x00, 0x12, 0x14, 0x18, 0x14, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x0c, 0x12, 0x12, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x04, 0x0c, 0x04, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x0c, 0x12, 0x04, 0x08, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1c, 0x02, 0x1c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x14, 0x14, 0x1e, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1e, 0x10, 0x1c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x0c, 0x10, 0x1c, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1e, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x0c, 0x12, 0x0c, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x0c, 0x12, 0x0e, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x78, 0x08, 0x30, 0x00, 0x0c, 0x12, 0x1e, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1c, 0x12, 0x1c, 0x12, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x0e, 0x10, 0x10, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1c, 0x12, 0x12, 0x12, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1e, 0x10, 0x1c, 0x10, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1e, 0x10, 0x1c, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x08, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x14, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x08, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x24, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x28, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x32, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x08, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x12, 0x10, 0x3c, 0x10, 0x3c, 0x10, 0x70, 0x91, 0x6e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x48, 0x70, 0x00, 0x04, 0x0c, 0x04, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x3c, 0x10, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x42, 0x3c, 0x10, 0x08, 0x10, 0x00,
+ 0x32, 0x4c, 0x00, 0x42, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x20, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x41, 0x22, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x22, 0x41, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x12, 0x10, 0x10, 0x3c, 0x10, 0x10, 0x70, 0x91, 0x6e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x82, 0x44, 0x28, 0x10, 0x7c, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1c, 0x20, 0x20, 0x10, 0x18, 0x24, 0x24, 0x18, 0x08, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x07, 0x08, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x20, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x3e, 0x49, 0x48, 0x48, 0x49, 0x3e, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x14, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x14, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x28, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x28, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x24, 0x18, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x28, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3d, 0x42, 0x46, 0x4a, 0x4a, 0x52, 0x52, 0x62, 0x42, 0xbc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x48, 0x48, 0x48, 0x7e, 0x48, 0x48, 0x48, 0x48, 0x4f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x14, 0x08, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x4e, 0x72, 0x42, 0xbc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x09, 0x3f, 0x48, 0x49, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x10, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x24, 0x44, 0x48, 0x70, 0x48, 0x44, 0x44, 0x64, 0x58, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x10, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x32, 0x4c, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0xe2, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x07, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x10, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x10, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x10, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x08, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x32, 0x4c, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x10, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x3c, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x28, 0x10, 0x00, 0x3c, 0x40, 0x3c, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x10, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00,
+ 0x00, 0x00, 0x38, 0x10, 0x10, 0x1c, 0x12, 0x12, 0x1c, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x1c, 0x12, 0x12, 0x1c, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x40, 0x00, 0x0c, 0x12, 0x04, 0x08, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x40, 0x00, 0x1c, 0x02, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x40, 0x00, 0x14, 0x14, 0x1e, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x20, 0x20, 0x20, 0x70, 0x00, 0x0c, 0x12, 0x12, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x60, 0x22, 0x24, 0x28, 0x14, 0x2c, 0x54, 0x1e, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x60, 0x22, 0x24, 0x28, 0x10, 0x2c, 0x52, 0x04, 0x08, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x09, 0x12, 0x24, 0x48, 0x24, 0x12, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x48, 0x24, 0x12, 0x09, 0x12, 0x24, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x5a, 0x5a, 0x56, 0x4e, 0x56, 0x5a, 0x5a, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }
+};
+
+static const mon_tbl_desc __stidata sti_mon_table[] = {
+ { .x = 1280, .y = 1024, .hz = 72, .class_vesa = 1, .index = 0 },
+ { .x = 1024, .y = 768, .hz = 72, .class_vesa = 1, .index = 0 },
+ { .x = 768, .y = 600, .hz = 72, .class_vesa = 1, .index = 0 },
+ { .x = 640, .y = 480, .hz = 72, .class_vesa = 1, .index = 0 },
+};
+
+struct sti_rom __stiheader sti_proc_rom = {
+ .type = { 0x03, 0x03, 0x03, 0x03 },
+ .num_mons = ARRAY_SIZE(sti_mon_table),
+ .revno = { 0x84, 0x07 },
+ .graphics_id = { 0x2b4ded6d, 0x40a00499 },
+};
+
+static void __stitext write_artist(struct sti_glob_cfg *cfg,
+ int reg, u32 val)
+{
+ writel((void *)cfg->region_ptrs[2] + reg, val);
+}
+
+static int __stifunc("state_mgmt") sti_state_mgmt(struct sti_state_flags *flags,
+ struct sti_state_inptr *in,
+ struct sti_state_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ (void)flags;
+ (void)in;
+ (void)cfg;
+ out->errno = 0;
+ return 0;
+}
+
+static u32 __stifunc("block_move") sti_bmove(struct sti_blkmv_flags *flags,
+ struct sti_blkmv_inptr *in,
+ struct sti_blkmv_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ write_artist(cfg, ARTIST_PLANE_BITMASK, 0xffffffff);
+ write_artist(cfg, ARTIST_BITMAP_OP, 0x03000300);
+ write_artist(cfg, ARTIST_SRC_BM_ACCESS, 0x2ea01000);
+ write_artist(cfg, ARTIST_DST_BM_ACCESS, 0x2ea01000);
+ write_artist(cfg, ARTIST_FGCOLOR, in->fg_color);
+ write_artist(cfg, ARTIST_BGCOLOR, in->bg_color);
+
+ if (flags->clear) {
+ write_artist(cfg, ARTIST_VRAM_DEST, (in->dest_x << 16) | (in->dest_y));
+ barrier();
+ write_artist(cfg, ARTIST_VRAM_SIZE_TRIGGER_WINFILL,
+ (in->width << 16) | (in->height));
+ } else {
+ write_artist(cfg, ARTIST_VRAM_SIZE, (in->width << 16) | (in->height));
+ write_artist(cfg, ARTIST_VRAM_SRC, (in->src_x << 16) | (in->src_y));
+ barrier();
+ write_artist(cfg, ARTIST_VRAM_DEST_TRIGGER_BLOCKMOVE,
+ (in->dest_x << 16) | (in->dest_y));
+ }
+ out->errno = 0;
+ return 0;
+}
+
+/* can not call millicode routines in STI ROM code */
+static inline int inline_mul(int val, int mul)
+{
+ switch (mul) {
+ case 7: return (val << 3) - val;
+ case 6: return (val << 2) + (val << 1);
+ case 5: return (val << 2) + val;
+ case 4: return (val << 2);
+ case 3: return (val << 1) + val;
+ case 2: return (val << 1);
+ case 1: return val;
+ case 0: return 0;
+ default: return 0;
+ }
+}
+
+static int __stifunc("font_unpmv") sti_font_unpmv(struct sti_font_flags *flags,
+ struct sti_font_inptr *in,
+ struct sti_font_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ struct font *font = (struct font *) in->font_start_addr;
+ int bpc = font->hdr.bytes_per_char;
+ int width = font->hdr.width;
+ unsigned char *src;
+ int c, y, pitch;
+ (void)flags;
+
+ /* same as: src = &font->font[in->index * bpc]; */
+ c = in->index;
+ y = inline_mul(c, bpc & 7);
+ if (bpc & 8) y += c << 3;
+ if (bpc & 16) y += c << 4;
+ if (bpc & 32) y += c << 5;
+ if (bpc & 64) y += c << 6;
+ if (bpc & 128) y += c << 7;
+ src = &font->font[y];
+
+ write_artist(cfg, ARTIST_VRAM_IDX,
+ (in->dest_y << 13) | (in->dest_x << 2));
+
+ write_artist(cfg, ARTIST_FGCOLOR, in->fg_color);
+ write_artist(cfg, ARTIST_BGCOLOR, in->bg_color);
+ write_artist(cfg, ARTIST_BITMAP_OP, 0x23000300);
+ write_artist(cfg, ARTIST_VRAM_BITMASK, 0xffffffff << (32 - width));
+ write_artist(cfg, ARTIST_DST_BM_ACCESS, 0x2ea01000);
+ write_artist(cfg, ARTIST_PLANE_BITMASK, 7);
+ barrier();
+
+ pitch = (width + 7) / 8;
+ for (y = 0; y < bpc; y += pitch) {
+ u32 val = 0;
+ switch (pitch) {
+ case 4: val |= src[y+3] << 0; /* fall through */
+ case 3: val |= src[y+2] << 8; /* fall through */
+ case 2: val |= src[y+1] << 16; /* fall through */
+ default: val |= src[y+0] << 24; /* fall through */
+ }
+ write_artist(cfg, ARTIST_VRAM_BYTE_WRITE, val);
+ barrier();
+ }
+ out->errno = 0;
+ return 0;
+}
+
+static int __stifunc("init_graph") sti_init_graph(struct sti_init_flags *flags,
+ struct sti_init_inptr *in,
+ struct sti_init_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ u32 *cmap = (u32 *)cfg->region_ptrs[1];
+ u32 resolution = *(u32 *)(cfg->region_ptrs[2] + 0x111110);
+
+ out->errno = 0;
+ if (resolution & (1 << 31)) {
+ cfg->text_planes = 1;
+ } else {
+ cfg->text_planes = in->text_planes;
+ if (cfg->text_planes < 0 || cfg->text_planes > 3)
+ cfg->text_planes = 3;
+ }
+ out->text_planes = cfg->text_planes;
+
+ cfg->onscreen_x = (resolution >> 16) & 0xfff;
+ cfg->onscreen_y = resolution & 0xfff;
+ cfg->offscreen_x = 0;
+ cfg->offscreen_y = 0;
+ cfg->total_x = 2048; /* hardcoded width */
+ cfg->total_y = cfg->onscreen_y;
+ if (cfg->total_y < 1024)
+ cfg->total_y = 1024;
+
+ if (flags->clear) {
+ /* clear screen */
+ write_artist(cfg, ARTIST_VRAM_BITMASK, 0xffffffff);
+ write_artist(cfg, ARTIST_FGCOLOR, 1);
+ write_artist(cfg, ARTIST_BGCOLOR, 0);
+ write_artist(cfg, ARTIST_VRAM_DEST, 0);
+ barrier();
+ write_artist(cfg, ARTIST_VRAM_SIZE_TRIGGER_WINFILL,
+ (cfg->total_x << 16) | cfg->total_y);
+ }
+
+ if (flags->init_cmap_tx) {
+ /* STI color map */
+ write_artist(cfg, ARTIST_CMAP_ACCESS, 0x3ba0f000);
+ cmap[0x100] = 0x000000; /* black */
+ cmap[0x101] = 0xffffff; /* white */
+ cmap[0x102] = 0xff0000; /* red */
+ cmap[0x103] = 0xffff00; /* yellow */
+ cmap[0x104] = 0x00ff00; /* green */
+ cmap[0x105] = 0x00ffff; /* cyan */
+ cmap[0x106] = 0x0000ff; /* blue */
+ cmap[0x107] = 0xff00ff; /* magenta */
+ write_artist(cfg, ARTIST_DST_BM_ACCESS, 0x2ea0f000);
+ }
+ return 0;
+}
+
+static __stifunc("self_test") int sti_self_test(struct sti_init_flags *flags,
+ struct sti_init_inptr *in,
+ struct sti_init_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ (void)flags;
+ (void)in;
+ (void)cfg;
+
+ out->errno = 0;
+ return 0;
+}
+
+static __stifunc("inq_conf") int sti_inq_conf(struct sti_conf_flags *flags,
+ struct sti_conf_inptr *in,
+ struct sti_conf_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ (void)in;
+ (void)flags;
+
+ out->errno = 0;
+ out->onscreen_x = cfg->onscreen_x;
+ out->onscreen_y = cfg->onscreen_y;
+ out->total_x = cfg->total_x;
+ out->total_y = cfg->total_y;
+ out->bits_per_pixel = 8;
+ out->bits_used = 8;
+ out->planes = cfg->text_planes;
+ /* attributes for GCDESCRIBE. See graphics.h and framebuf.h include files. */
+ out->attributes = 0x1836;
+ out->dev_name[0] = 'H';
+ out->dev_name[1] = 'P';
+ out->dev_name[2] = 'A';
+ out->dev_name[3] = '2';
+ out->dev_name[4] = '0';
+ out->dev_name[5] = '8';
+ out->dev_name[6] = 'L';
+ out->dev_name[7] = 'C';
+
+ switch(cfg->total_x) {
+ default:
+ /* default to 1280 if user gave some odd resolution */
+ out->dev_name[8] = '1';
+ out->dev_name[9] = '2';
+ out->dev_name[10] = '8';
+ out->dev_name[11] = '0';
+ out->dev_name[12] = '\0';
+ break;
+
+ case 1024:
+ out->dev_name[8] = '1';
+ out->dev_name[9] = '0';
+ out->dev_name[10] = '2';
+ out->dev_name[11] = '4';
+ out->dev_name[12] = '\0';
+ break;
+
+ case 800:
+ out->dev_name[8] = '8';
+ out->dev_name[9] = '0';
+ out->dev_name[10] = '0';
+ out->dev_name[11] = '\0';
+ break;
+
+ case 640:
+ out->dev_name[8] = '6';
+ out->dev_name[9] = '4';
+ out->dev_name[10] = '0';
+ out->dev_name[11] = '\0';
+ break;
+
+ }
+ return 0;
+}
+
+int __stifunc("excep_hdlr") sti_excep_hdlr(void)
+{
+ return 0;
+}
+
+int __stifunc("set_cm_entry") sti_set_cm_entry(struct setcm_flags *flags,
+ struct setcm_inptr *in,
+ struct setcm_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ u32 *cmap = (u32 *)cfg->region_ptrs[1];
+ (void)flags;
+ (void)cfg;
+
+ cmap[in->entry & 0xffff] = in->value;
+ out->errno = 0;
+ return 0;
+}
+
+int __stifunc("dma_ctrl") sti_dma_ctrl(void)
+{
+ return 0;
+}
+
+void __stifunc("end") sti_end(void)
+{
+}
+
+static void update_crc(struct sti_rom *rom)
+{
+ u8 *c, *romend = (u8 *)rom + rom->last_addr - 2;
+ u16 code = 0, poly = 0x8408, accum = 0;
+ int i, j;
+
+ for (c = (u8 *)rom, j = 0; c <= romend; c++, j++) {
+ accum = (accum << 8) | (*c & 0xff);
+ if (j & 1) {
+ accum ^= code;
+ for (i = 0; i < 16; i++) {
+ /* do a left rotate */
+ if (accum & 0x8000) {
+ accum = (accum << 1) | 0x0001;
+ accum ^= poly;
+ } else {
+ accum <<= 1;
+ }
+ }
+ code = accum;
+ }
+ }
+ *(u16 *)(romend+1) = code;
+}
+
+#define STI_OFFSET(_x) ((u32)&(_x) - (u32)&_sti_rom_start)
+
+void sti_rom_init(void)
+{
+ unsigned int sti_rom_size;
+
+ sti_rom_size = (_sti_rom_end - _sti_rom_start) / 4096;
+ if (sti_region_list[0].region_desc.length != sti_rom_size) {
+ /* The STI ROM size is wrong. Try to fix it.
+ * If it's not writeable, we have to patch the source code. */
+ region_t *rp = (region_t *) &sti_region_list[0];
+ rp->region_desc.length = sti_rom_size;
+ }
+
+ sti_proc_rom.last_addr = _sti_rom_end - _sti_rom_start - 1;
+
+ sti_proc_rom.font_start = STI_OFFSET(sti_rom_font);
+ sti_proc_rom.state_mgmt = STI_OFFSET(sti_state_mgmt);
+ sti_proc_rom.inq_conf = STI_OFFSET(sti_inq_conf);
+ sti_proc_rom.init_graph = STI_OFFSET(sti_init_graph);
+ sti_proc_rom.block_move = STI_OFFSET(sti_bmove);
+ sti_proc_rom.region_list = STI_OFFSET(sti_region_list);
+ sti_proc_rom.font_unpmv = STI_OFFSET(sti_font_unpmv);
+ sti_proc_rom.self_test = STI_OFFSET(sti_self_test);
+ sti_proc_rom.mon_tbl_addr = STI_OFFSET(sti_mon_table);
+ sti_proc_rom.user_data_addr = STI_OFFSET(user_data);
+ sti_proc_rom.excep_hdlr = STI_OFFSET(sti_excep_hdlr);
+ sti_proc_rom.set_cm_entry = STI_OFFSET(sti_set_cm_entry);
+ sti_proc_rom.dma_ctrl = STI_OFFSET(sti_dma_ctrl);
+ sti_proc_rom.end = STI_OFFSET(sti_end);
+ update_crc(&sti_proc_rom);
+}
diff --git a/roms/seabios-hppa/src/parisc/timer.c b/roms/seabios-hppa/src/parisc/timer.c
new file mode 100644
index 000000000..ea8214f1b
--- /dev/null
+++ b/roms/seabios-hppa/src/parisc/timer.c
@@ -0,0 +1,103 @@
+// Internal timer
+//
+// Copyright (C) 2008-2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "x86.h" // rdtscll()
+#include "util.h" // timer_setup
+#include "parisc/pdc.h"
+
+#define PAGE0 ((volatile struct zeropage *) 0UL)
+
+// Setup internal timers.
+void
+timer_setup(void)
+{
+}
+
+void
+pmtimer_setup(u16 ioport)
+{
+}
+
+// Return the number of milliseconds in 'ticks' number of timer irqs.
+u32 ticks_to_ms(u32 ticks)
+{
+ return (10 * ticks / PAGE0->mem_10msec);
+}
+
+
+u32 ticks_from_ms(u32 ms)
+{
+ return (ms * PAGE0->mem_10msec / 10);
+}
+
+
+/****************************************************************
+ * Internal timer reading
+ ****************************************************************/
+
+u32 TimerLast VARLOW;
+
+// Sample the current timer value.
+static u32
+timer_read(void)
+{
+ return rdtscll();
+}
+
+// Check if the current time is past a previously calculated end time.
+int
+timer_check(u32 end)
+{
+ return (s32)(timer_read() - end) > 0;
+}
+
+static void
+timer_sleep(u32 diff)
+{
+ u32 start = timer_read();
+ u32 end = start + diff;
+ while (!timer_check(end))
+ /* idle wait */;
+}
+
+void ndelay(u32 count) {
+ timer_sleep((count * PAGE0->mem_10msec / 10) / 1000 / 1000);
+}
+void udelay(u32 count) {
+ timer_sleep((count * PAGE0->mem_10msec / 10) / 1000);
+}
+void mdelay(u32 count) {
+ timer_sleep((count * PAGE0->mem_10msec / 10));
+}
+
+void nsleep(u32 count) {
+ ndelay(count);
+}
+void usleep(u32 count) {
+ udelay(count);
+}
+void msleep(u32 count) {
+ mdelay(count);
+}
+
+// Return the TSC value that is 'msecs' time in the future.
+u32
+timer_calc(u32 msecs)
+{
+ return (msecs * PAGE0->mem_10msec / 10) + timer_read();
+}
+u32
+timer_calc_usec(u32 usecs)
+{
+ return ((usecs * PAGE0->mem_10msec / 10) / 1000) + timer_read();
+}
+
+
+void
+pit_setup(void)
+{
+}
diff --git a/roms/seabios-hppa/src/pcibios.c b/roms/seabios-hppa/src/pcibios.c
new file mode 100644
index 000000000..81735e3dd
--- /dev/null
+++ b/roms/seabios-hppa/src/pcibios.c
@@ -0,0 +1,241 @@
+// PCI BIOS (int 1a/b1) calls
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "bregs.h" // struct bregs
+#include "hw/pci.h" // pci_config_readl
+#include "hw/pcidevice.h" // MaxPCIBus
+#include "hw/pci_regs.h" // PCI_VENDOR_ID
+#include "output.h" // dprintf
+#include "std/pirtable.h" // struct pir_header
+#include "string.h" // checksum
+#include "util.h" // handle_1ab1
+
+// romlayout.S
+extern void entry_bios32(void);
+extern void entry_pcibios32(void);
+
+#define RET_FUNC_NOT_SUPPORTED 0x81
+#define RET_BAD_VENDOR_ID 0x83
+#define RET_DEVICE_NOT_FOUND 0x86
+#define RET_BUFFER_TOO_SMALL 0x89
+
+// installation check
+static void
+handle_1ab101(struct bregs *regs)
+{
+ regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
+ regs->bx = 0x0210; // PCI version 2.10
+ regs->cl = GET_GLOBAL(MaxPCIBus);
+ regs->edx = 0x20494350; // "PCI "
+ regs->edi = (u32)entry_pcibios32 + BUILD_BIOS_ADDR;
+ set_code_success(regs);
+}
+
+// find pci device
+static void
+handle_1ab102(struct bregs *regs)
+{
+ u32 id = (regs->cx << 16) | regs->dx;
+ int count = regs->si;
+ int bus = -1;
+ while (bus < GET_GLOBAL(MaxPCIBus)) {
+ bus++;
+ int bdf;
+ foreachbdf(bdf, bus) {
+ u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
+ if (v != id)
+ continue;
+ if (count--)
+ continue;
+ regs->bx = bdf;
+ set_code_success(regs);
+ return;
+ }
+ }
+ set_code_invalid(regs, RET_DEVICE_NOT_FOUND);
+}
+
+// find class code
+static void
+handle_1ab103(struct bregs *regs)
+{
+ int count = regs->si;
+ u32 classprog = regs->ecx;
+ int bus = -1;
+ while (bus < GET_GLOBAL(MaxPCIBus)) {
+ bus++;
+ int bdf;
+ foreachbdf(bdf, bus) {
+ u32 v = pci_config_readl(bdf, PCI_CLASS_REVISION);
+ if ((v>>8) != classprog)
+ continue;
+ if (count--)
+ continue;
+ regs->bx = bdf;
+ set_code_success(regs);
+ return;
+ }
+ }
+ set_code_invalid(regs, RET_DEVICE_NOT_FOUND);
+}
+
+// read configuration byte
+static void
+handle_1ab108(struct bregs *regs)
+{
+ regs->cl = pci_config_readb(regs->bx, regs->di);
+ set_code_success(regs);
+}
+
+// read configuration word
+static void
+handle_1ab109(struct bregs *regs)
+{
+ regs->cx = pci_config_readw(regs->bx, regs->di);
+ set_code_success(regs);
+}
+
+// read configuration dword
+static void
+handle_1ab10a(struct bregs *regs)
+{
+ regs->ecx = pci_config_readl(regs->bx, regs->di);
+ set_code_success(regs);
+}
+
+// write configuration byte
+static void
+handle_1ab10b(struct bregs *regs)
+{
+ pci_config_writeb(regs->bx, regs->di, regs->cl);
+ set_code_success(regs);
+}
+
+// write configuration word
+static void
+handle_1ab10c(struct bregs *regs)
+{
+ pci_config_writew(regs->bx, regs->di, regs->cx);
+ set_code_success(regs);
+}
+
+// write configuration dword
+static void
+handle_1ab10d(struct bregs *regs)
+{
+ pci_config_writel(regs->bx, regs->di, regs->ecx);
+ set_code_success(regs);
+}
+
+// get irq routing options
+static void
+handle_1ab10e(struct bregs *regs)
+{
+ struct pir_header *pirtable_gf = GET_GLOBAL(PirAddr);
+ if (! pirtable_gf) {
+ set_code_invalid(regs, RET_FUNC_NOT_SUPPORTED);
+ return;
+ }
+ struct pir_header *pirtable_g = GLOBALFLAT2GLOBAL(pirtable_gf);
+
+ struct param_s {
+ u16 size;
+ u16 buf_off;
+ u16 buf_seg;
+ } *param_far = (void*)(regs->di+0);
+
+ // Validate and update size.
+ u16 bufsize = GET_FARVAR(regs->es, param_far->size);
+ u16 pirsize = GET_GLOBAL(pirtable_g->size) - sizeof(struct pir_header);
+ SET_FARVAR(regs->es, param_far->size, pirsize);
+ if (bufsize < pirsize) {
+ set_code_invalid(regs, RET_BUFFER_TOO_SMALL);
+ return;
+ }
+
+ // Get dest buffer.
+ void *buf_far = (void*)(GET_FARVAR(regs->es, param_far->buf_off)+0);
+ u16 buf_seg = GET_FARVAR(regs->es, param_far->buf_seg);
+
+ // Memcpy pir table slots to dest buffer.
+ memcpy_far(buf_seg, buf_far
+ , get_global_seg()
+ , (void*)(pirtable_g->slots) + get_global_offset()
+ , pirsize);
+
+ // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
+ regs->bx = GET_GLOBAL(pirtable_g->exclusive_irqs);
+ set_code_success(regs);
+}
+
+static void
+handle_1ab1XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_FUNC_NOT_SUPPORTED);
+}
+
+void
+handle_1ab1(struct bregs *regs)
+{
+ //debug_stub(regs);
+
+ if (! CONFIG_PCIBIOS) {
+ set_invalid(regs);
+ return;
+ }
+
+ switch (regs->al) {
+ case 0x01: handle_1ab101(regs); break;
+ case 0x02: handle_1ab102(regs); break;
+ case 0x03: handle_1ab103(regs); break;
+ case 0x08: handle_1ab108(regs); break;
+ case 0x09: handle_1ab109(regs); break;
+ case 0x0a: handle_1ab10a(regs); break;
+ case 0x0b: handle_1ab10b(regs); break;
+ case 0x0c: handle_1ab10c(regs); break;
+ case 0x0d: handle_1ab10d(regs); break;
+ case 0x0e: handle_1ab10e(regs); break;
+ default: handle_1ab1XX(regs); break;
+ }
+}
+
+// Entry point for pci bios functions.
+void VISIBLE16 VISIBLE32SEG
+handle_pcibios(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_pcibios);
+ handle_1ab1(regs);
+}
+
+
+/****************************************************************
+ * 32bit interface
+ ****************************************************************/
+
+struct bios32_s {
+ u32 signature;
+ u32 entry;
+ u8 version;
+ u8 length;
+ u8 checksum;
+ u8 reserved[5];
+} PACKED;
+
+struct bios32_s BIOS32HEADER __aligned(16) VARFSEG = {
+ .signature = 0x5f32335f, // _32_
+ .length = sizeof(BIOS32HEADER) / 16,
+};
+
+void
+bios32_init(void)
+{
+ dprintf(3, "init bios32\n");
+
+ BIOS32HEADER.entry = (u32)entry_bios32;
+ BIOS32HEADER.checksum -= checksum(&BIOS32HEADER, sizeof(BIOS32HEADER));
+}
diff --git a/roms/seabios-hppa/src/pmm.c b/roms/seabios-hppa/src/pmm.c
new file mode 100644
index 000000000..28b253b2d
--- /dev/null
+++ b/roms/seabios-hppa/src/pmm.c
@@ -0,0 +1,176 @@
+// Post memory manager (PMM) calls
+//
+// Copyright (C) 2009-2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // FUNC16
+#include "config.h" // CONFIG_*
+#include "malloc.h" // _malloc
+#include "output.h" // dprintf
+#include "e820map.h" // struct e820entry
+#include "std/pmm.h" // PMM_SIGNATURE
+#include "string.h" // checksum
+#include "util.h" // pmm_init
+#include "x86.h" // __ffs
+
+extern struct pmmheader PMMHEADER;
+
+#if CONFIG_PMM
+struct pmmheader PMMHEADER __aligned(16) VARFSEG = {
+ .signature = PMM_SIGNATURE,
+ .version = 0x01,
+ .length = sizeof(PMMHEADER),
+};
+#endif
+
+// PMM - allocate
+static u32
+handle_pmm00(u16 *args)
+{
+ u32 length = *(u32*)&args[1], handle = *(u32*)&args[3];
+ u16 flags = args[5];
+ dprintf(3, "pmm00: length=%x handle=%x flags=%x\n"
+ , length, handle, flags);
+ struct zone_s *lowzone = &ZoneTmpLow, *highzone = &ZoneTmpHigh;
+ if (flags & 8) {
+ // Permanent memory request.
+ lowzone = &ZoneLow;
+ highzone = &ZoneHigh;
+ }
+ if (!length) {
+ // Memory size request
+ switch (flags & 3) {
+ default:
+ case 0:
+ return 0;
+ case 1:
+ return malloc_getspace(lowzone);
+ case 2:
+ return malloc_getspace(highzone);
+ case 3: {
+ u32 spacelow = malloc_getspace(lowzone);
+ u32 spacehigh = malloc_getspace(highzone);
+ if (spacelow > spacehigh)
+ return spacelow;
+ return spacehigh;
+ }
+ }
+ }
+ u32 size = length * 16;
+ if ((s32)size <= 0)
+ return 0;
+ u32 align = MALLOC_MIN_ALIGN;
+ if (flags & 4) {
+ align = 1<<__ffs(size);
+ if (align < MALLOC_MIN_ALIGN)
+ align = MALLOC_MIN_ALIGN;
+ }
+ u32 data;
+ switch (flags & 3) {
+ default:
+ case 0:
+ return 0;
+ case 1:
+ data = malloc_palloc(lowzone, size, align);
+ break;
+ case 2:
+ data = malloc_palloc(highzone, size, align);
+ if (!data && (flags & 8)) {
+ /*
+ * We are out of meory. So go allocate from the (big)
+ * ZoneTmpHigh instead and reserve the block in the e820
+ * map so the OS will not override it. That way we can
+ * handle big permanent allocations without needing a big
+ * ZoneHigh.
+ */
+ data = malloc_palloc(&ZoneTmpHigh, size, align);
+ if (data)
+ e820_add(data, size, E820_RESERVED);
+ }
+ break;
+ case 3: {
+ data = malloc_palloc(lowzone, size, align);
+ if (!data)
+ data = malloc_palloc(highzone, size, align);
+ }
+ }
+ if (data && handle != MALLOC_DEFAULT_HANDLE)
+ malloc_sethandle(data, handle);
+ return data;
+}
+
+// PMM - find
+static u32
+handle_pmm01(u16 *args)
+{
+ u32 handle = *(u32*)&args[1];
+ dprintf(3, "pmm01: handle=%x\n", handle);
+ if (handle == MALLOC_DEFAULT_HANDLE)
+ return 0;
+ return malloc_findhandle(handle);
+}
+
+// PMM - deallocate
+static u32
+handle_pmm02(u16 *args)
+{
+ u32 buffer = *(u32*)&args[1];
+ dprintf(3, "pmm02: buffer=%x\n", buffer);
+ int ret = malloc_pfree(buffer);
+ if (ret)
+ // Error
+ return 1;
+ return 0;
+}
+
+static u32
+handle_pmmXX(u16 *args)
+{
+ return PMM_FUNCTION_NOT_SUPPORTED;
+}
+
+u32 VISIBLE32INIT
+handle_pmm(u16 *args)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_PMM)
+ return PMM_FUNCTION_NOT_SUPPORTED;
+
+ u16 arg1 = args[0];
+ dprintf(DEBUG_HDL_pmm, "pmm call arg1=%x\n", arg1);
+
+ u32 ret;
+ switch (arg1) {
+ case 0x00: ret = handle_pmm00(args); break;
+ case 0x01: ret = handle_pmm01(args); break;
+ case 0x02: ret = handle_pmm02(args); break;
+ default: ret = handle_pmmXX(args); break;
+ }
+
+ return ret;
+}
+
+void
+pmm_init(void)
+{
+ if (! CONFIG_PMM)
+ return;
+
+ dprintf(3, "init PMM\n");
+
+ PMMHEADER.entry = FUNC16(entry_pmm);
+ PMMHEADER.checksum -= checksum(&PMMHEADER, sizeof(PMMHEADER));
+}
+
+void
+pmm_prepboot(void)
+{
+ if (! CONFIG_PMM)
+ return;
+
+ dprintf(3, "finalize PMM\n");
+
+ PMMHEADER.signature = 0;
+ PMMHEADER.entry.segoff = 0;
+}
diff --git a/roms/seabios-hppa/src/pnpbios.c b/roms/seabios-hppa/src/pnpbios.c
new file mode 100644
index 000000000..95ce21f8f
--- /dev/null
+++ b/roms/seabios-hppa/src/pnpbios.c
@@ -0,0 +1,88 @@
+// PNP BIOS calls
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // BUILD_BIOS_ADDR
+#include "farptr.h" // SET_FARVAR
+#include "output.h" // dprintf
+#include "std/pnpbios.h" // PNP_SIGNATURE
+#include "string.h" // checksum
+#include "util.h" // pnp_init
+
+extern struct pnpheader PNPHEADER;
+extern char pnp_string[];
+
+#if CONFIG_PNPBIOS
+struct pnpheader PNPHEADER __aligned(16) VARFSEG = {
+ .signature = PNP_SIGNATURE,
+ .version = 0x10,
+ .length = sizeof(PNPHEADER),
+ .real_cs = SEG_BIOS,
+ .prot_base = BUILD_BIOS_ADDR,
+ .real_ds = SEG_BIOS,
+ .prot_database = BUILD_BIOS_ADDR,
+};
+#else
+// We need a copy of this string in the 0xf000 segment, but we are not
+// actually a PnP BIOS, so make sure it is *not* aligned, so OSes will
+// not see it if they scan.
+char pnp_string[] __aligned(2) VARFSEG = " $PnP";
+#endif
+
+// BBS - Get Version and Installation Check
+static u16
+handle_pnp60(u16 *args)
+{
+ u16 version_ptr = args[1];
+ u16 version_seg = args[2];
+ SET_FARVAR(version_seg, *(u16*)(version_ptr+0), 0x0101);
+ return 0;
+}
+
+static u16
+handle_pnpXX(u16 *args)
+{
+ return FUNCTION_NOT_SUPPORTED;
+}
+
+u16 VISIBLE16
+handle_pnp(u16 *args)
+{
+ if (! CONFIG_PNPBIOS)
+ return FUNCTION_NOT_SUPPORTED;
+
+ u16 arg1 = args[0];
+ dprintf(DEBUG_HDL_pnp, "pnp call arg1=%x\n", arg1);
+
+ switch (arg1) {
+ case 0x60: return handle_pnp60(args);
+ default: return handle_pnpXX(args);
+ }
+}
+
+u16
+get_pnp_offset(void)
+{
+ if (! CONFIG_PNPBIOS)
+ return (u32)pnp_string + 1 - BUILD_BIOS_ADDR;
+ return (u32)&PNPHEADER - BUILD_BIOS_ADDR;
+}
+
+// romlayout.S
+extern void entry_pnp_real(void);
+extern void entry_pnp_prot(void);
+
+void
+pnp_init(void)
+{
+ if (! CONFIG_PNPBIOS)
+ return;
+
+ dprintf(3, "init PNPBIOS table\n");
+
+ PNPHEADER.real_ip = (u32)entry_pnp_real - BUILD_BIOS_ADDR;
+ PNPHEADER.prot_ip = (u32)entry_pnp_prot - BUILD_BIOS_ADDR;
+ PNPHEADER.checksum -= checksum(&PNPHEADER, sizeof(PNPHEADER));
+}
diff --git a/roms/seabios-hppa/src/post.c b/roms/seabios-hppa/src/post.c
new file mode 100644
index 000000000..a504aefd8
--- /dev/null
+++ b/roms/seabios-hppa/src/post.c
@@ -0,0 +1,337 @@
+// 32bit code to Power On Self Test (POST) a machine.
+//
+// Copyright (C) 2008-2013 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // SET_BDA
+#include "block.h" // block_setup
+#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/pic.h" // pic_setup
+#include "hw/ps2port.h" // ps2port_setup
+#include "hw/rtc.h" // rtc_write
+#include "hw/serialio.h" // serial_debug_preinit
+#include "hw/usb.h" // usb_setup
+#include "malloc.h" // malloc_init
+#include "memmap.h" // SYMBOL
+#include "output.h" // dprintf
+#include "string.h" // memset
+#include "util.h" // kbd_init
+#include "tcgbios.h" // tpm_*
+
+
+/****************************************************************
+ * BIOS initialization and hardware setup
+ ****************************************************************/
+
+static void
+ivt_init(void)
+{
+ dprintf(3, "init ivt\n");
+
+ // Initialize all vectors to the default handler.
+ int i;
+ for (i=0; i<256; i++)
+ SET_IVT(i, FUNC16(entry_iret_official));
+
+ // Initialize all hw vectors to a default hw handler.
+ for (i=BIOS_HWIRQ0_VECTOR; i<BIOS_HWIRQ0_VECTOR+8; i++)
+ SET_IVT(i, FUNC16(entry_hwpic1));
+ for (i=BIOS_HWIRQ8_VECTOR; i<BIOS_HWIRQ8_VECTOR+8; i++)
+ SET_IVT(i, FUNC16(entry_hwpic2));
+
+ // Initialize software handlers.
+ SET_IVT(0x02, FUNC16(entry_02));
+ SET_IVT(0x05, FUNC16(entry_05));
+ SET_IVT(0x10, FUNC16(entry_10));
+ SET_IVT(0x11, FUNC16(entry_11));
+ SET_IVT(0x12, FUNC16(entry_12));
+ SET_IVT(0x13, FUNC16(entry_13_official));
+ SET_IVT(0x14, FUNC16(entry_14));
+ SET_IVT(0x15, FUNC16(entry_15_official));
+ SET_IVT(0x16, FUNC16(entry_16));
+ SET_IVT(0x17, FUNC16(entry_17));
+ SET_IVT(0x18, FUNC16(entry_18));
+ SET_IVT(0x19, FUNC16(entry_19_official));
+ SET_IVT(0x1a, FUNC16(entry_1a_official));
+ SET_IVT(0x40, FUNC16(entry_40));
+
+ // INT 60h-66h reserved for user interrupt
+ for (i=0x60; i<=0x66; i++)
+ SET_IVT(i, SEGOFF(0, 0));
+
+ // set vector 0x79 to zero
+ // this is used by 'gardian angel' protection system
+ SET_IVT(0x79, SEGOFF(0, 0));
+}
+
+static void
+bda_init(void)
+{
+ dprintf(3, "init bda\n");
+
+ struct bios_data_area_s *bda = get_bda_ptr();
+ memset(bda, 0, sizeof(*bda));
+
+ int esize = EBDA_SIZE_START;
+ u16 ebda_seg = EBDA_SEGMENT_START;
+ if (!CONFIG_MALLOC_UPPERMEMORY)
+ ebda_seg = FLATPTR_TO_SEG(ALIGN_DOWN(SYMBOL(final_varlow_start), 1024)
+ - EBDA_SIZE_START*1024);
+ SET_BDA(ebda_seg, ebda_seg);
+
+ SET_BDA(mem_size_kb, ebda_seg / (1024/16));
+
+ // Init ebda
+ struct extended_bios_data_area_s *ebda = get_ebda_ptr();
+ memset(ebda, 0, sizeof(*ebda));
+ ebda->size = esize;
+
+ e820_add((u32)ebda, BUILD_LOWRAM_END-(u32)ebda, E820_RESERVED);
+
+ // Init extra stack
+ StackPos = &ExtraStack[BUILD_EXTRA_STACK_SIZE] - SYMBOL(zonelow_base);
+}
+
+void
+interface_init(void)
+{
+ // Running at new code address - do code relocation fixups
+ malloc_init();
+
+ // Setup romfile items.
+ qemu_cfg_init();
+ coreboot_cbfs_init();
+ multiboot_init();
+
+ // Setup ivt/bda/ebda
+ ivt_init();
+ bda_init();
+
+ // Other interfaces
+ boot_init();
+ bios32_init();
+ pmm_init();
+ pnp_init();
+ kbd_init();
+ mouse_init();
+}
+
+// Initialize hardware devices
+void
+device_hardware_setup(void)
+{
+ usb_setup();
+ ps2port_setup();
+ block_setup();
+ lpt_setup();
+ serial_setup();
+ cbfs_payload_setup();
+}
+
+static void
+platform_hardware_setup(void)
+{
+ // Make sure legacy DMA isn't running.
+ dma_setup();
+
+ // Init base pc hardware.
+ pic_setup();
+ thread_setup();
+ mathcp_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();
+
+ // Finalize data structures before boot
+ cdrom_prepboot();
+ pmm_prepboot();
+ malloc_prepboot();
+ e820_prepboot();
+
+ HaveRunPost = 2;
+
+ // Setup bios checksum.
+ BiosChecksum -= checksum((u8*)BUILD_BIOS_ADDR, BUILD_BIOS_SIZE);
+}
+
+// Begin the boot process by invoking an int0x19 in 16bit mode.
+void VISIBLE32FLAT
+startBoot(void)
+{
+ // Clear low-memory allocations (required by PMM spec).
+ memset((void*)BUILD_STACK_ADDR, 0, BUILD_EBDA_MINIMUM - BUILD_STACK_ADDR);
+
+ dprintf(3, "Jump to int19\n");
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ call16_int(0x19, &br);
+}
+
+// Main setup code.
+static void
+maininit(void)
+{
+ // Initialize internal interfaces.
+ interface_init();
+
+ // Setup platform devices.
+ platform_hardware_setup();
+
+ // Start hardware initialization (if threads allowed during optionroms)
+ if (threads_during_optionroms())
+ device_hardware_setup();
+
+ // Run vga option rom
+ vgarom_setup();
+ sercon_setup();
+ enable_vga_console();
+
+ // Do hardware initialization (if running synchronously)
+ if (!threads_during_optionroms()) {
+ device_hardware_setup();
+ wait_threads();
+ }
+
+ // Run option roms
+ optionrom_setup();
+
+ // Allow user to modify overall boot order.
+ interactive_bootmenu();
+ wait_threads();
+
+ // Prepare for boot.
+ prepareboot();
+
+ // Write protect bios memory.
+ make_bios_readonly();
+
+ // Invoke int 19 to start boot process.
+ startBoot();
+}
+
+
+/****************************************************************
+ * POST entry and code relocation
+ ****************************************************************/
+
+// Update given relocs for the code at 'dest' with a given 'delta'
+static void
+updateRelocs(void *dest, u32 *rstart, u32 *rend, u32 delta)
+{
+ u32 *reloc;
+ for (reloc = rstart; reloc < rend; reloc++)
+ *((u32*)(dest + *reloc)) += delta;
+}
+
+// Relocate init code and then call a function at its new address.
+// The passed function should be in the "init" section and must not
+// return.
+void __noreturn
+reloc_preinit(void *f, void *arg)
+{
+ void (*func)(void *) __noreturn = f;
+ if (!CONFIG_RELOCATE_INIT)
+ func(arg);
+
+ // Allocate space for init code.
+ 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"
+ , 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.
+ barrier();
+ func(arg);
+}
+
+// Runs after all code is present and prior to any modifications
+void
+code_mutable_preinit(void)
+{
+ if (HaveRunPost)
+ // Already run
+ return;
+ // Setup reset-vector entry point (controls legacy reboots).
+ rtc_write(CMOS_RESET_CODE, 0);
+ barrier();
+ HaveRunPost = 1;
+ barrier();
+}
+
+// Setup for code relocation and then relocate.
+void VISIBLE32INIT
+dopost(void)
+{
+ code_mutable_preinit();
+
+ // Detect ram and setup internal malloc.
+ qemu_preinit();
+ coreboot_preinit();
+ malloc_preinit();
+
+ // Relocate initialization code and call maininit().
+ reloc_preinit(maininit, NULL);
+}
+
+// Entry point for Power On Self Test (POST) - the BIOS initilization
+// phase. This function makes the memory at 0xc0000-0xfffff
+// read/writable and then calls dopost().
+void VISIBLE32FLAT
+handle_post(void)
+{
+ if (!CONFIG_QEMU && !CONFIG_COREBOOT)
+ return;
+
+ serial_debug_preinit();
+ debug_banner();
+
+ // Check if we are running under Xen.
+ xen_preinit();
+
+ // Allow writes to modify bios area (0xf0000)
+ make_bios_writable();
+
+ // Now that memory is read/writable - start post process.
+ dopost();
+}
diff --git a/roms/seabios-hppa/src/resume.c b/roms/seabios-hppa/src/resume.c
new file mode 100644
index 000000000..fb0b8a89e
--- /dev/null
+++ b/roms/seabios-hppa/src/resume.c
@@ -0,0 +1,157 @@
+// Code for handling calls to "post" that are resume related.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "bregs.h" // struct bregs
+#include "config.h" // CONFIG_*
+#include "farptr.h" // FLATPTR_TO_SEGOFF
+#include "hw/pci.h" // pci_reboot
+#include "hw/pic.h" // pic_eoi2
+#include "hw/ps2port.h" // i8042_reboot
+#include "hw/rtc.h" // rtc_read
+#include "output.h" // dprintf
+#include "stacks.h" // farcall16big
+#include "std/bda.h" // struct bios_data_area_s
+#include "string.h" // memset
+#include "util.h" // dma_setup
+#include "tcgbios.h" // tpm_s3_resume
+#include "fw/romfile_loader.h" // romfile_fw_cfg_resume
+
+// Handler for post calls that look like a resume.
+void VISIBLE16
+handle_resume(void)
+{
+ ASSERT16();
+ int status = rtc_read(CMOS_RESET_CODE);
+ rtc_write(CMOS_RESET_CODE, 0);
+ dprintf(1, "In resume (status=%d)\n", status);
+
+ dma_setup();
+
+ switch (status) {
+ case 0x01 ... 0x04:
+ case 0x06 ... 0x09:
+ panic("Unimplemented shutdown status: %02x\n", status);
+
+ case 0x05:
+ // flush keyboard (issue EOI) and jump via 40h:0067h
+ pic_eoi2();
+ // NO BREAK
+ case 0x0a:
+#define BDA_JUMP (((struct bios_data_area_s *)0)->jump)
+ // resume execution by jump via 40h:0067h
+ asm volatile(
+ "movw %w1, %%ds\n"
+ "ljmpw *%0\n"
+ : : "m"(BDA_JUMP), "r"(SEG_BDA)
+ );
+ break;
+
+ case 0x0b:
+ // resume execution via IRET via 40h:0067h
+ asm volatile(
+ "movw %w1, %%ds\n"
+ "lssw %0, %%sp\n"
+ "iretw\n"
+ : : "m"(BDA_JUMP), "r"(SEG_BDA)
+ );
+ break;
+
+ case 0x0c:
+ // resume execution via RETF via 40h:0067h
+ asm volatile(
+ "movw %w1, %%ds\n"
+ "lssw %0, %%sp\n"
+ "lretw\n"
+ : : "m"(BDA_JUMP), "r"(SEG_BDA)
+ );
+ break;
+
+ default:
+ break;
+ }
+
+ // Not a 16bit resume - do remaining checks in 32bit mode
+ asm volatile(
+ "movw %w1, %%ss\n"
+ "movl %0, %%esp\n"
+ "movl $_cfunc32flat_handle_resume32, %%edx\n"
+ "jmp transition32\n"
+ : : "i"(BUILD_S3RESUME_STACK_ADDR), "r"(0), "a"(status)
+ );
+}
+
+// Handle an S3 resume event
+static void
+s3_resume(void)
+{
+ if (!CONFIG_S3_RESUME)
+ return;
+
+ u32 s3_resume_vector = find_resume_vector();
+ if (!s3_resume_vector) {
+ dprintf(1, "No resume vector set!\n");
+ return;
+ }
+
+ pic_setup();
+ smm_setup();
+ smp_resume();
+
+ pci_resume();
+
+ /* resume TPM before we may measure option roms */
+ tpm_s3_resume();
+ s3_resume_vga();
+
+ /* Replay any fw_cfg entries that go back to the host */
+ romfile_fw_cfg_resume();
+
+ make_bios_readonly();
+
+ // Invoke the resume vector.
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector);
+ br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector);
+ farcall16big(&br);
+}
+
+// Attempt to invoke a hard-reboot.
+static void
+tryReboot(void)
+{
+ dprintf(1, "Attempting a hard reboot\n");
+
+ // Use a QEMU specific reboot on QEMU
+ qemu_reboot();
+
+ // Reboot using ACPI RESET_REG
+ acpi_reboot();
+
+ // Try keyboard controller reboot.
+ i8042_reboot();
+
+ // Try PCI 0xcf9 reboot
+ pci_reboot();
+
+ // Try triple fault
+ asm volatile("int3");
+
+ panic("Could not reboot");
+}
+
+void VISIBLE32FLAT
+handle_resume32(int status)
+{
+ ASSERT32FLAT();
+ dprintf(1, "In 32bit resume\n");
+
+ if (status == 0xfe)
+ s3_resume();
+
+ // Must be a soft reboot - invoke a hard reboot.
+ tryReboot();
+}
diff --git a/roms/seabios-hppa/src/romfile.c b/roms/seabios-hppa/src/romfile.c
new file mode 100644
index 000000000..64abe685e
--- /dev/null
+++ b/roms/seabios-hppa/src/romfile.c
@@ -0,0 +1,148 @@
+// Access to pseudo "file" interface for configuration information.
+//
+// Copyright (C) 2012 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "byteorder.h" // cpu_to_le16
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "romfile.h" // struct romfile_s
+#include "string.h" // memcmp
+
+static struct romfile_s *RomfileRoot VARVERIFY32INIT;
+
+void
+romfile_add(struct romfile_s *file)
+{
+ dprintf(3, "Add romfile: %s (size=%d)\n", file->name, file->size);
+ file->next = RomfileRoot;
+ RomfileRoot = file;
+}
+
+// Search for the specified file.
+static struct romfile_s *
+__romfile_findprefix(const char *prefix, int prefixlen, struct romfile_s *prev)
+{
+ struct romfile_s *cur = RomfileRoot;
+ if (prev)
+ cur = prev->next;
+ while (cur) {
+ if (memcmp(prefix, cur->name, prefixlen) == 0)
+ return cur;
+ cur = cur->next;
+ }
+ return NULL;
+}
+
+struct romfile_s *
+romfile_findprefix(const char *prefix, struct romfile_s *prev)
+{
+ return __romfile_findprefix(prefix, strlen(prefix), prev);
+}
+
+struct romfile_s *
+romfile_find(const char *name)
+{
+ return __romfile_findprefix(name, strlen(name) + 1, NULL);
+}
+
+// Helper function to find, malloc_tmphigh, and copy a romfile. This
+// function adds a trailing zero to the malloc'd copy.
+void *
+romfile_loadfile(const char *name, int *psize)
+{
+ struct romfile_s *file = romfile_find(name);
+ if (!file)
+ return NULL;
+
+ int filesize = file->size;
+ if (!filesize)
+ return NULL;
+
+ char *data = malloc_tmphigh(filesize+1);
+ if (!data) {
+ warn_noalloc();
+ return NULL;
+ }
+
+ dprintf(5, "Copying romfile '%s' (len %d)\n", name, filesize);
+ int ret = file->copy(file, data, filesize);
+ if (ret < 0) {
+ free(data);
+ return NULL;
+ }
+ if (psize)
+ *psize = filesize;
+ data[filesize] = '\0';
+ return data;
+}
+
+// Attempt to load an integer from the given file - return 'defval'
+// if unsuccessful.
+u64
+romfile_loadint(const char *name, u64 defval)
+{
+ struct romfile_s *file = romfile_find(name);
+ if (!file)
+ return defval;
+
+ int filesize = file->size;
+ if (!filesize || filesize > sizeof(u64) || (filesize & (filesize-1)))
+ // Doesn't look like a valid integer.
+ return defval;
+
+ u64 val = 0;
+ int ret = file->copy(file, &val, sizeof(val));
+ if (ret < 0)
+ return defval;
+ /* romfile interface stores values in little endian */
+ return le64_to_cpu(val);
+}
+
+struct const_romfile_s {
+ struct romfile_s file;
+ void *data;
+};
+
+static int
+const_read_file(struct romfile_s *file, void *dst, u32 maxlen)
+{
+ if (file->size > maxlen)
+ return -1;
+ struct const_romfile_s *cfile;
+ cfile = container_of(file, struct const_romfile_s, file);
+ if (maxlen > file->size)
+ maxlen = file->size;
+ memcpy(dst, cfile->data, maxlen);
+ return file->size;
+}
+
+static void
+const_romfile_add(char *name, void *data, int size)
+{
+ struct const_romfile_s *cfile = malloc_tmp(sizeof(*cfile));
+ if (!cfile) {
+ warn_noalloc();
+ return;
+ }
+ memset(cfile, 0, sizeof(*cfile));
+ strtcpy(cfile->file.name, name, sizeof(cfile->file.name));
+ cfile->file.size = size;
+ cfile->file.copy = const_read_file;
+ cfile->data = data;
+ romfile_add(&cfile->file);
+}
+
+void
+const_romfile_add_int(char *name, u32 value)
+{
+ u32 *data = malloc_tmp(sizeof(*data));
+ if (!data) {
+ warn_noalloc();
+ return;
+ }
+ *data = value;
+ const_romfile_add(name, data, sizeof(*data));
+}
diff --git a/roms/seabios-hppa/src/romfile.h b/roms/seabios-hppa/src/romfile.h
new file mode 100644
index 000000000..3e0f82004
--- /dev/null
+++ b/roms/seabios-hppa/src/romfile.h
@@ -0,0 +1,21 @@
+#ifndef __ROMFILE_H
+#define __ROMFILE_H
+
+#include "types.h" // u32
+
+// romfile.c
+struct romfile_s {
+ struct romfile_s *next;
+ char name[128];
+ u32 size;
+ int (*copy)(struct romfile_s *file, void *dest, u32 maxlen);
+};
+void romfile_add(struct romfile_s *file);
+struct romfile_s *romfile_findprefix(const char *prefix, struct romfile_s *prev);
+struct romfile_s *romfile_find(const char *name);
+void *romfile_loadfile(const char *name, int *psize);
+u64 romfile_loadint(const char *name, u64 defval);
+
+void const_romfile_add_int(char *name, u32 value);
+
+#endif // romfile.h
diff --git a/roms/seabios-hppa/src/romlayout.S b/roms/seabios-hppa/src/romlayout.S
new file mode 100644
index 000000000..c4a4635e8
--- /dev/null
+++ b/roms/seabios-hppa/src/romlayout.S
@@ -0,0 +1,698 @@
+// Rom layout and bios assembler to C interface.
+//
+// Copyright (C) 2008-2012 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "asm-offsets.h" // BREGS_*
+#include "config.h" // CONFIG_*
+#include "entryfuncs.S" // ENTRY_*
+#include "hw/rtc.h" // CMOS_RESET_CODE
+#include "x86.h" // CR0_*
+
+ .code16
+
+
+/****************************************************************
+ * 16bit / 32bit call trampolines
+ ****************************************************************/
+
+// Place CPU into 32bit mode from 16bit mode.
+// %edx = return location (in 32bit mode)
+// Clobbers: ecx, flags, segment registers, cr0, idt/gdt
+ DECLFUNC transition32
+ .global transition32_nmi_off
+transition32:
+ // 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
+
+ // enable a20
+ inb $PORT_A20, %al
+ orb $A20_ENABLE_BIT, %al
+ outb %al, $PORT_A20
+ movl %ecx, %eax
+
+transition32_nmi_off:
+ // Set segment descriptors
+ lidtw %cs:pmode_IDT_info
+ lgdtw %cs:rombios32_gdt_48
+
+ // Enable protected mode
+ 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 + 1f)
+
+ .code32
+ // init data segments
+1: movl $SEG32_MODE32_DS, %ecx
+ movw %cx, %ds
+ movw %cx, %es
+ movw %cx, %ss
+ movw %cx, %fs
+ movw %cx, %gs
+
+ jmpl *%edx
+ .code16
+
+// Place CPU into 16bit mode from 32bit mode.
+// %edx = return location (in 16bit mode)
+// Clobbers: ecx, flags, segment registers, cr0, idt/gdt
+ DECLFUNC transition16
+ .global transition16big
+ .code32
+transition16:
+ // 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 $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
+ // Disable protected mode
+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
+
+ // restore IDT to normal real-mode defaults
+2: lidtw %cs:rmode_IDT_info
+
+ // Clear segment registers
+ xorw %cx, %cx
+ movw %cx, %fs
+ movw %cx, %gs
+ movw %cx, %es
+ movw %cx, %ds
+ movw %cx, %ss // Assume stack is in segment 0
+
+ jmpl *%edx
+
+
+/****************************************************************
+ * External calling trampolines
+ ****************************************************************/
+
+// Far call a 16bit function from 16bit mode with a specified cpu register state
+// %eax = address of struct bregs, %edx = segment of struct bregs
+// Clobbers: %e[bc]x, %e[ds]i, flags
+ DECLFUNC __farcall16
+__farcall16:
+ // Save %edx/%eax, %ebp
+ pushl %ebp
+ pushl %eax
+ pushl %edx
+
+ // Setup for iretw call
+ movl %edx, %ds
+ pushw %cs
+ pushw $1f // return point
+ pushw BREGS_flags(%eax) // flags
+ pushl BREGS_code(%eax) // CS:IP
+
+ // Load calling registers and invoke call
+ RESTOREBREGS_DSEAX
+ iretw // XXX - just do a lcalll
+1:
+ // Store flags, es, eax
+ pushfw
+ cli
+ cld
+ pushw %ds
+ pushl %eax
+ movw 0x08(%esp), %ds
+ movl 0x0c(%esp), %eax
+ SAVEBREGS_POP_DSEAX
+ popw BREGS_flags(%eax)
+ movw %ss, %cx
+ movw %cx, %ds // Restore %ds == %ss
+
+ // Remove %edx/%eax, restore %ebp
+ popl %edx
+ popl %eax
+ popl %ebp
+
+ retl
+
+// IRQ trampolines
+ .macro IRQ_TRAMPOLINE num
+ DECLFUNC irq_trampoline_0x\num
+ irq_trampoline_0x\num :
+ int $0x\num
+ lretw
+ .endm
+
+ IRQ_TRAMPOLINE 02
+ IRQ_TRAMPOLINE 05
+ IRQ_TRAMPOLINE 10
+ IRQ_TRAMPOLINE 13
+ IRQ_TRAMPOLINE 15
+ IRQ_TRAMPOLINE 16
+ IRQ_TRAMPOLINE 18
+ IRQ_TRAMPOLINE 19
+ IRQ_TRAMPOLINE 1b
+ IRQ_TRAMPOLINE 1c
+ IRQ_TRAMPOLINE 4a
+
+
+/****************************************************************
+ * Misc. entry points.
+ ****************************************************************/
+
+// Entry point for QEMU smi interrupts.
+ DECLFUNC entry_smi
+entry_smi:
+ // Transition to 32bit mode.
+ movl $1f + BUILD_BIOS_ADDR, %edx
+ jmp transition32_nmi_off
+ .code32
+1: movl $BUILD_SMM_ADDR + 0x8000, %esp
+ calll _cfunc32flat_handle_smi - BUILD_BIOS_ADDR
+ rsm
+ .code16
+
+// Entry point for QEMU smp sipi interrupts.
+ DECLFUNC entry_smp
+entry_smp:
+ // Transition to 32bit mode.
+ cli
+ cld
+ movl $2f + BUILD_BIOS_ADDR, %edx
+ jmp transition32_nmi_off
+ .code32
+ // Acquire lock and take ownership of shared stack
+1: rep ; nop
+2: lock btsl $0, SMPLock
+ jc 1b
+ movl SMPStack, %esp
+ // Call handle_smp
+ calll _cfunc32flat_handle_smp - BUILD_BIOS_ADDR
+ // Release lock and halt processor.
+ movl $0, SMPLock
+3: hlt
+ jmp 3b
+ .code16
+
+// Resume (and reboot) entry point - called from entry_post
+ DECLFUNC entry_resume
+entry_resume:
+ // Disable interrupts
+ cli
+ cld
+ // Use the ExtraStack in low mem.
+ movl $_zonelow_seg, %eax
+ movw %ax, %ds
+ movw %ax, %ss
+ movl $ExtraStack + BUILD_EXTRA_STACK_SIZE, %esp
+ // Call handler.
+ jmp handle_resume
+
+// PMM entry point
+ DECLFUNC entry_pmm
+entry_pmm:
+ pushl %esp // Backup %esp, then clear high bits
+ movzwl %sp, %esp
+ pushfl // Save registers clobbered by C code
+ cli
+ cld
+ PUSHBREGS
+ movl %ss, %ecx // Move %ss to %ds
+ movw %cx, %ds
+ shll $4, %ecx
+ 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
+ movw %ax, BREGS_eax(%esp) // Modify %ax:%dx to return %eax
+ shrl $16, %eax
+ movw %ax, BREGS_edx(%esp)
+ POPBREGS
+ popfl
+ popl %esp
+ lretw
+
+// PnP entry points
+ DECLFUNC entry_pnp_real
+ .global entry_pnp_prot
+entry_pnp_prot:
+ pushl %esp
+ jmp 1f
+entry_pnp_real:
+ pushl %esp // Backup %esp, then clear high bits
+ movzwl %sp, %esp
+1:
+ pushfl // Save registers clobbered by C code
+ cli
+ cld
+ PUSHBREGS
+ movw %ss, %cx // Move %ss to %ds
+ movw %cx, %ds
+ leal PUSHBREGS_size+12(%esp), %eax // %eax points to start of u16 args
+ calll handle_pnp
+ movw %ax, BREGS_eax(%esp) // Modify %eax to return %ax
+ POPBREGS
+ popfl
+ popl %esp
+ lretw
+
+// APM entry points
+ DECLFUNC entry_apm16
+entry_apm16:
+ pushfw // save flags
+ pushl %eax // dummy
+ ENTRY_ARG handle_apm
+ addw $4, %sp // pop dummy
+ popfw // restore flags
+ lretw
+
+ DECLFUNC entry_apm32
+ .code32
+entry_apm32:
+ pushfl
+ pushl %gs
+ pushl %cs // Move second descriptor after %cs to %gs
+ addl $16, (%esp)
+ popl %gs
+ ENTRY_ARG_ESP _cfunc32seg_handle_apm
+ popl %gs
+ popfl
+ lretl
+ .code16
+
+// PCI-BIOS entry points
+ DECLFUNC entry_pcibios32
+ .code32
+entry_pcibios32:
+ pushfl
+ pushl %gs // Backup %gs and set %gs=%ds
+ pushl %ds
+ popl %gs
+ ENTRY_ARG_ESP _cfunc32seg_handle_pcibios
+ popl %gs
+ popfl
+ lretl
+ .code16
+
+ DECLFUNC entry_pcibios16
+entry_pcibios16:
+ ENTRY_ARG handle_pcibios
+ iretw
+
+// int 1589 entry point
+ DECLFUNC entry_1589
+entry_1589:
+ ENTRY_ARG handle_1589
+ iretw
+
+// BIOS32 support
+ DECLFUNC entry_bios32
+ .code32
+entry_bios32:
+ pushfl
+#if CONFIG_PCIBIOS
+ // Check for PCI-BIOS request
+ cmpl $0x49435024, %eax // $PCI
+ jne 1f
+ movl $BUILD_BIOS_ADDR, %ebx
+ movl $BUILD_BIOS_SIZE, %ecx
+ movl $entry_pcibios32, %edx
+ xorb %al, %al
+ jmp 2f
+#endif
+ // Unknown request
+1: movb $0x80, %al
+ // Return to caller
+2: popfl
+ lretl
+ .code16
+
+// 32bit elf entry point
+ DECLFUNC entry_elf
+ .code32
+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
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+ movl $BUILD_STACK_ADDR, %esp
+ ljmpl $SEG32_MODE32_CS, $_cfunc32flat_handle_post
+ .code16
+
+// UEFI Compatibility Support Module (CSM) entry point
+ DECLFUNC entry_csm
+entry_csm:
+ // Backup register state
+ pushfw
+ cli
+ cld
+ pushl %eax // dummy
+ PUSHBREGS
+
+ // Backup stack location and convert to a "flat pointer"
+ movl %ss, %eax
+ movw %ax, BREGS_code+2(%esp) // Store %ss in bregs->code.seg
+ shll $4, %eax
+ addl %esp, %eax
+
+ // Change to BUILD_STACK_ADDR stack and call handle_csm(bregs)
+ ENTRY_INTO32 _cfunc32flat_handle_csm
+
+ DECLFUNC __csm_return
+ .code32
+__csm_return:
+ movl $1f, %edx
+ jmp transition16big
+ .code16
+
+ // Switch back to original stack
+1: movzwl BREGS_code+2(%eax), %edx
+ movl %edx, %ecx
+ shll $4, %ecx
+ subl %ecx, %eax
+ movl %edx, %ss
+ movl %eax, %esp
+
+ // Restore register state and return.
+ POPBREGS
+ addw $4, %sp // pop dummy
+ popfw
+ lretw
+
+// Serial console "hooked vga" entry point
+ DECLFUNC entry_sercon
+entry_sercon:
+ // Setup for chain loading to real vga handler
+ pushfw
+ pushl %cs:sercon_real_vga_handler
+
+ // Set %ds to varlow segment
+ cli
+ cld
+ pushw %ds
+ pushl %eax
+ movl $_zonelow_seg, %eax
+ movl %eax, %ds
+
+ // Test if the sercon handler can be called
+ movl %esp, %eax // Test for broken x86emu
+ pushl $1f
+ retl
+1: cmpl %esp, %eax
+ jne 4f
+ cmpb $0, sercon_enable // Test that sercon is enabled
+ je 3f
+
+ // call handle_sercon
+ popl %eax
+ popw %ds
+2: pushl $handle_sercon
+#if CONFIG_ENTRY_EXTRASTACK
+ jmp irqentry_arg_extrastack
+#else
+ jmp irqentry_arg
+#endif
+
+ // sercon disabled - check for legacy text modeset and otherwise exit
+3: popl %eax
+ popw %ds
+ cmpw $0x0007, %ax
+ jle 2b
+ iretw
+
+ // Running on broken x86emu - restore stack and exit
+4: movl %eax, %esp
+ popl %eax
+ popw %ds
+ iretw
+
+
+/****************************************************************
+ * Interrupt entry points
+ ****************************************************************/
+
+ // Main entry point for hardware interrupts handled on extra stack
+ DECLFUNC irqentry_extrastack
+irqentry_extrastack:
+ cli
+ cld
+ pushw %ds // Set %ds:%eax to space on ExtraStack
+ pushl %eax
+ movl $_zonelow_seg, %eax
+ movl %eax, %ds
+ movl StackPos, %eax
+ subl $PUSHBREGS_size+8, %eax
+ SAVEBREGS_POP_DSEAX
+ popl %ecx
+ movl %esp, PUSHBREGS_size(%eax)
+ movw %ss, PUSHBREGS_size+4(%eax)
+
+ movw %ds, %dx // Setup %ss/%esp and call function
+ movw %dx, %ss
+ movl %eax, %esp
+ calll *%ecx
+
+ movl %esp, %eax // Restore registers and return
+ movw PUSHBREGS_size+4(%eax), %ss
+ movl PUSHBREGS_size(%eax), %esp
+ RESTOREBREGS_DSEAX
+ iretw
+
+ // Main entry point for software interrupts handled on extra stack
+ DECLFUNC irqentry_arg_extrastack
+irqentry_arg_extrastack:
+ cli
+ cld
+ pushw %ds // Set %ds:%eax to space on ExtraStack
+ pushl %eax
+ movl $_zonelow_seg, %eax
+ movl %eax, %ds
+ movl StackPos, %eax
+ subl $PUSHBREGS_size+16, %eax
+ SAVEBREGS_POP_DSEAX // Save registers on extra stack
+ popl %ecx
+ movl %esp, PUSHBREGS_size+8(%eax)
+ movw %ss, PUSHBREGS_size+12(%eax)
+ popl BREGS_code(%eax)
+ popw BREGS_flags(%eax)
+
+ movw %ds, %dx // Setup %ss/%esp and call function
+ movw %dx, %ss
+ movl %eax, %esp
+ calll *%ecx
+
+ movl %esp, %eax // Restore registers and return
+ movw PUSHBREGS_size+12(%eax), %ss
+ movl PUSHBREGS_size+8(%eax), %esp
+ popl %edx
+ popw %dx
+ pushw BREGS_flags(%eax)
+ pushl BREGS_code(%eax)
+ RESTOREBREGS_DSEAX
+ iretw
+
+ // Main entry point for software interrupts (using caller's stack)
+ DECLFUNC irqentry_arg
+irqentry_arg:
+ ENTRY_ARG_ST
+ iretw
+
+ // Helper macros for hardware interrupt declaration
+ .macro IRQ_ENTRY num
+ .global entry_\num
+ entry_\num :
+ pushl $ handle_\num
+ jmp irqentry_extrastack
+ .endm
+
+ .macro DECL_IRQ_ENTRY num
+ DECLFUNC entry_\num
+ IRQ_ENTRY \num
+ .endm
+
+ // Helper macros for software interrupt declaration
+ .macro IRQ_ENTRY_ARG num
+ .global entry_\num
+ entry_\num :
+ pushl $ handle_\num
+#if CONFIG_ENTRY_EXTRASTACK
+ jmp irqentry_arg_extrastack
+#else
+ jmp irqentry_arg
+#endif
+ .endm
+
+ .macro DECL_IRQ_ENTRY_ARG num
+ DECLFUNC entry_\num
+ IRQ_ENTRY_ARG \num
+ .endm
+
+ // Various entry points (that don't require a fixed location).
+ DECL_IRQ_ENTRY_ARG 13
+ DECL_IRQ_ENTRY 76
+ DECL_IRQ_ENTRY 70
+ DECL_IRQ_ENTRY 74
+ DECL_IRQ_ENTRY 75
+ DECL_IRQ_ENTRY hwpic1
+ DECL_IRQ_ENTRY hwpic2
+
+ // int 18/19 are special - they reset stack and call into 32bit mode.
+ DECLFUNC entry_19
+entry_19:
+ ENTRY_INTO32 _cfunc32flat_handle_19
+
+ DECLFUNC entry_18
+entry_18:
+ ENTRY_INTO32 _cfunc32flat_handle_18
+
+
+/****************************************************************
+ * Fixed position entry points
+ ****************************************************************/
+
+ // Specify a location in the fixed part of bios area.
+ .macro ORG addr
+ .section .fixedaddr.\addr
+ .endm
+
+ ORG 0xe05b
+entry_post:
+ cmpl $0, %cs:HaveRunPost // Check for resume/reboot
+ jnz entry_resume
+ ENTRY_INTO32 _cfunc32flat_handle_post // Normal entry point
+
+ ORG 0xe2c3
+ .global entry_02
+entry_02:
+ ENTRY handle_02 // NMI handler does not switch onto extra stack
+ iretw
+
+ ORG 0xe3fe
+ .global entry_13_official
+entry_13_official:
+ jmp entry_13
+
+ // 0xe401 - OldFDPT in misc.c
+
+ ORG 0xe6f2
+ .global entry_19_official
+entry_19_official:
+ jmp entry_19
+
+ // 0xe6f5 - BIOS_CONFIG_TABLE in misc.c
+
+ // 0xe729 - BaudTable in misc.c
+
+ ORG 0xe739
+ IRQ_ENTRY_ARG 14
+
+ ORG 0xe82e
+ IRQ_ENTRY_ARG 16
+
+ ORG 0xe987
+ IRQ_ENTRY 09
+
+ ORG 0xec59
+ IRQ_ENTRY_ARG 40
+
+ ORG 0xef57
+ IRQ_ENTRY 0e
+
+ // 0xefc7 - diskette_param_table in misc.c
+
+ ORG 0xefd2
+ IRQ_ENTRY_ARG 17
+
+ ORG 0xf045
+entry_10_0x0f:
+ // XXX - INT 10 Functions 0-Fh Entry Point
+ iretw
+
+ ORG 0xf065
+entry_10:
+ iretw
+
+ // 0xf0a4 - VideoParams in misc.c
+
+ ORG 0xf841
+ IRQ_ENTRY_ARG 12
+
+ ORG 0xf84d
+ IRQ_ENTRY_ARG 11
+
+ ORG 0xf859
+ .global entry_15_official
+entry_15_official:
+ cmpb $0x89, %ah
+ je entry_1589 // 1589 calls return in protected mode
+ IRQ_ENTRY_ARG 15
+
+ // 0xfa6e - vgafont8 in font.c
+
+ ORG 0xfe6e
+ .global entry_1a_official
+entry_1a_official:
+ cmpb $0xb1, %ah
+ je entry_pcibios16 // PCIBIOS calls can be in protected mode
+ IRQ_ENTRY_ARG 1a
+
+ ORG 0xfea5
+ IRQ_ENTRY 08
+
+ // 0xfef3 - InitVectors in misc.c
+
+ ORG 0xff53
+ .global entry_iret_official
+entry_iret_official:
+ iretw
+
+ ORG 0xff54
+ IRQ_ENTRY_ARG 05
+
+ ORG 0xfff0 // Power-up Entry Point
+ .global reset_vector
+reset_vector:
+ ljmpw $SEG_BIOS, $entry_post
+
+ // 0xfff5 - BiosDate in misc.c
+
+ // 0xfffe - BiosModelId in misc.c
+
+ // 0xffff - BiosChecksum in misc.c
+
+ .end
diff --git a/roms/seabios-hppa/src/sercon.c b/roms/seabios-hppa/src/sercon.c
new file mode 100644
index 000000000..8ae1f9cf4
--- /dev/null
+++ b/roms/seabios-hppa/src/sercon.c
@@ -0,0 +1,677 @@
+// serial console support
+//
+// Copyright (C) 2016 Gerd Hoffmann <kraxel@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // SET_BDA
+#include "bregs.h" // struct bregs
+#include "stacks.h" // yield
+#include "output.h" // dprintf
+#include "util.h" // irqtimer_calc_ticks
+#include "string.h" // memcpy
+#include "romfile.h" // romfile_loadint
+#include "hw/serialio.h" // SEROFF_IER
+#include "cp437.h"
+
+static u8 video_rows(void)
+{
+ return GET_BDA(video_rows)+1;
+}
+
+static u8 video_cols(void)
+{
+ return GET_BDA(video_cols);
+}
+
+static u8 cursor_pos_col(void)
+{
+ u16 pos = GET_BDA(cursor_pos[0]);
+ return pos & 0xff;
+}
+
+static u8 cursor_pos_row(void)
+{
+ u16 pos = GET_BDA(cursor_pos[0]);
+ return (pos >> 8) & 0xff;
+}
+
+static void cursor_pos_set(u8 row, u8 col)
+{
+ u16 pos = ((u16)row << 8) | col;
+ SET_BDA(cursor_pos[0], pos);
+}
+
+/****************************************************************
+ * serial console output
+ ****************************************************************/
+
+VARLOW u16 sercon_port;
+VARLOW u8 sercon_split;
+VARLOW u8 sercon_enable;
+VARFSEG struct segoff_s sercon_real_vga_handler;
+
+/*
+ * We have a small output buffer here, for lazy output. That allows
+ * to avoid a whole bunch of control sequences for pointless cursor
+ * moves, so when logging the output it'll be *alot* less cluttered.
+ *
+ * sercon_char/attr is the actual output buffer.
+ * sercon_attr_last is the most recent attribute sent to the terminal.
+ * sercon_col_last is the most recent column sent to the terminal.
+ * sercon_row_last is the most recent row sent to the terminal.
+ */
+VARLOW u8 sercon_attr_last;
+VARLOW u8 sercon_col_last;
+VARLOW u8 sercon_row_last;
+VARLOW u8 sercon_char;
+VARLOW u8 sercon_attr = 0x07;
+
+static VAR16 u8 sercon_cmap[8] = { '0', '4', '2', '6', '1', '5', '3', '7' };
+
+static int sercon_splitmode(void)
+{
+ return GET_LOW(sercon_split);
+}
+
+static void sercon_putchar(u8 chr)
+{
+ u16 addr = GET_LOW(sercon_port);
+ u32 end = irqtimer_calc_ticks(0x0a);
+
+#if 0
+ /* for visual control sequence debugging */
+ if (chr == '\x1b')
+ chr = '*';
+#endif
+
+ for (;;) {
+ u8 lsr = inb(addr+SEROFF_LSR);
+ if ((lsr & 0x60) == 0x60) {
+ // Success - can write data
+ outb(chr, addr+SEROFF_DATA);
+ break;
+ }
+ if (irqtimer_check(end)) {
+ break;
+ }
+ yield();
+ }
+}
+
+static void sercon_term_reset(void)
+{
+ sercon_putchar('\x1b');
+ sercon_putchar('c');
+}
+
+static void sercon_term_clear_screen(void)
+{
+ sercon_putchar('\x1b');
+ sercon_putchar('[');
+ sercon_putchar('2');
+ sercon_putchar('J');
+}
+
+static void sercon_term_no_linewrap(void)
+{
+ sercon_putchar('\x1b');
+ sercon_putchar('[');
+ sercon_putchar('?');
+ sercon_putchar('7');
+ sercon_putchar('l');
+}
+
+static void sercon_term_cursor_goto(u8 row, u8 col)
+{
+ row++; col++;
+ sercon_putchar('\x1b');
+ sercon_putchar('[');
+ sercon_putchar('0' + row / 10);
+ sercon_putchar('0' + row % 10);
+ sercon_putchar(';');
+ sercon_putchar('0' + col / 10);
+ sercon_putchar('0' + col % 10);
+ sercon_putchar('H');
+}
+
+static void sercon_term_set_color(u8 fg, u8 bg, u8 bold)
+{
+ sercon_putchar('\x1b');
+ sercon_putchar('[');
+ sercon_putchar('0');
+ if (fg != 7) {
+ sercon_putchar(';');
+ sercon_putchar('3');
+ sercon_putchar(GET_GLOBAL(sercon_cmap[fg & 7]));
+ }
+ if (bg != 0) {
+ sercon_putchar(';');
+ sercon_putchar('4');
+ sercon_putchar(GET_GLOBAL(sercon_cmap[bg & 7]));
+ }
+ if (bold) {
+ sercon_putchar(';');
+ sercon_putchar('1');
+ }
+ sercon_putchar('m');
+}
+
+static void sercon_set_attr(u8 attr)
+{
+ if (attr == GET_LOW(sercon_attr_last))
+ return;
+
+ SET_LOW(sercon_attr_last, attr);
+ sercon_term_set_color((attr >> 0) & 7,
+ (attr >> 4) & 7,
+ attr & 0x08);
+}
+
+static void sercon_print_utf8(u8 chr)
+{
+ u16 unicode = cp437_to_unicode(chr);
+
+ if (unicode < 0x7f) {
+ sercon_putchar(unicode);
+ } else if (unicode < 0x7ff) {
+ sercon_putchar(0xc0 | ((unicode >> 6) & 0x1f));
+ sercon_putchar(0x80 | ((unicode >> 0) & 0x3f));
+ } else {
+ sercon_putchar(0xe0 | ((unicode >> 12) & 0x0f));
+ sercon_putchar(0x80 | ((unicode >> 6) & 0x3f));
+ sercon_putchar(0x80 | ((unicode >> 0) & 0x3f));
+ }
+}
+
+static void sercon_cursor_pos_set(u8 row, u8 col)
+{
+ if (!sercon_splitmode()) {
+ cursor_pos_set(row, col);
+ } else {
+ /* let vgabios update cursor */
+ }
+}
+
+static void sercon_lazy_cursor_sync(void)
+{
+ u8 row = cursor_pos_row();
+ u8 col = cursor_pos_col();
+
+ if (GET_LOW(sercon_row_last) == row &&
+ GET_LOW(sercon_col_last) == col)
+ return;
+
+ if (col == 0 && GET_LOW(sercon_row_last) <= row) {
+ if (GET_LOW(sercon_col_last) != 0) {
+ sercon_putchar('\r');
+ SET_LOW(sercon_col_last, 0);
+ }
+ while (GET_LOW(sercon_row_last) < row) {
+ sercon_putchar('\n');
+ SET_LOW(sercon_row_last, GET_LOW(sercon_row_last)+1);
+ }
+ if (GET_LOW(sercon_row_last) == row &&
+ GET_LOW(sercon_col_last) == col)
+ return;
+ }
+
+ sercon_term_cursor_goto(row, col);
+ SET_LOW(sercon_row_last, row);
+ SET_LOW(sercon_col_last, col);
+}
+
+static void sercon_lazy_flush(void)
+{
+ u8 chr, attr;
+
+ chr = GET_LOW(sercon_char);
+ attr = GET_LOW(sercon_attr);
+ if (chr) {
+ sercon_set_attr(attr);
+ sercon_print_utf8(chr);
+ SET_LOW(sercon_col_last, GET_LOW(sercon_col_last) + 1);
+ }
+
+ sercon_lazy_cursor_sync();
+
+ SET_LOW(sercon_attr, 0x07);
+ SET_LOW(sercon_char, 0x00);
+}
+
+static void sercon_lazy_cursor_update(u8 row, u8 col)
+{
+ sercon_cursor_pos_set(row, col);
+ SET_LOW(sercon_row_last, row);
+ SET_LOW(sercon_col_last, col);
+}
+
+static void sercon_lazy_backspace(void)
+{
+ u8 col;
+
+ sercon_lazy_flush();
+ col = cursor_pos_col();
+ if (col > 0) {
+ sercon_putchar(8);
+ sercon_lazy_cursor_update(cursor_pos_row(), col-1);
+ }
+}
+
+static void sercon_lazy_cr(void)
+{
+ sercon_cursor_pos_set(cursor_pos_row(), 0);
+}
+
+static void sercon_lazy_lf(void)
+{
+ u8 row;
+
+ row = cursor_pos_row() + 1;
+ if (row >= video_rows()) {
+ /* scrolling up */
+ row = video_rows()-1;
+ if (GET_LOW(sercon_row_last) > 0) {
+ SET_LOW(sercon_row_last, GET_LOW(sercon_row_last) - 1);
+ }
+ }
+ sercon_cursor_pos_set(row, cursor_pos_col());
+}
+
+static void sercon_lazy_move_cursor(void)
+{
+ u8 col;
+
+ col = cursor_pos_col() + 1;
+ if (col >= video_cols()) {
+ sercon_lazy_cr();
+ sercon_lazy_lf();
+ } else {
+ sercon_cursor_pos_set(cursor_pos_row(), col);
+ }
+}
+
+static void sercon_lazy_putchar(u8 chr, u8 attr, u8 teletype)
+{
+ if (cursor_pos_row() != GET_LOW(sercon_row_last) ||
+ cursor_pos_col() != GET_LOW(sercon_col_last)) {
+ sercon_lazy_flush();
+ }
+
+ SET_LOW(sercon_char, chr);
+ if (teletype)
+ sercon_lazy_move_cursor();
+ else
+ SET_LOW(sercon_attr, attr);
+}
+
+/* Set video mode */
+static void sercon_1000(struct bregs *regs)
+{
+ u8 clearscreen = !(regs->al & 0x80);
+ u8 mode = regs->al & 0x7f;
+ u8 rows, cols;
+
+ if (!sercon_splitmode()) {
+ switch (mode) {
+ case 0x00:
+ case 0x01:
+ case 0x04: /* 320x200 */
+ case 0x05: /* 320x200 */
+ cols = 40;
+ rows = 25;
+ regs->al = 0x30;
+ break;
+ case 0x02:
+ case 0x03:
+ case 0x06: /* 640x200 */
+ case 0x07:
+ default:
+ cols = 80;
+ rows = 25;
+ regs->al = 0x30;
+ break;
+ }
+ cursor_pos_set(0, 0);
+ SET_BDA(video_mode, mode);
+ SET_BDA(video_cols, cols);
+ SET_BDA(video_rows, rows-1);
+ SET_BDA(cursor_type, 0x0007);
+ } else {
+ /* let vgabios handle mode init */
+ }
+
+ SET_LOW(sercon_enable, mode <= 0x07);
+ SET_LOW(sercon_col_last, 0);
+ SET_LOW(sercon_row_last, 0);
+ SET_LOW(sercon_attr_last, 0);
+
+ sercon_term_reset();
+ sercon_term_no_linewrap();
+ if (clearscreen)
+ sercon_term_clear_screen();
+}
+
+/* Set text-mode cursor shape */
+static void sercon_1001(struct bregs *regs)
+{
+ /* show/hide cursor? */
+ SET_BDA(cursor_type, regs->cx);
+}
+
+/* Set cursor position */
+static void sercon_1002(struct bregs *regs)
+{
+ sercon_cursor_pos_set(regs->dh, regs->dl);
+}
+
+/* Get cursor position */
+static void sercon_1003(struct bregs *regs)
+{
+ regs->cx = GET_BDA(cursor_type);
+ regs->dh = cursor_pos_row();
+ regs->dl = cursor_pos_col();
+}
+
+/* Scroll up window */
+static void sercon_1006(struct bregs *regs)
+{
+ sercon_lazy_flush();
+ if (regs->al == 0) {
+ /* clear rect, do only in case this looks like a fullscreen clear */
+ if (regs->ch == 0 &&
+ regs->cl == 0 &&
+ regs->dh == video_rows()-1 &&
+ regs->dl == video_cols()-1) {
+ sercon_set_attr(regs->bh);
+ sercon_term_clear_screen();
+ }
+ } else {
+ sercon_putchar('\r');
+ sercon_putchar('\n');
+ }
+}
+
+/* Read character and attribute at cursor position */
+static void sercon_1008(struct bregs *regs)
+{
+ regs->ah = 0x07;
+ regs->bh = ' ';
+}
+
+/* Write character and attribute at cursor position */
+static void sercon_1009(struct bregs *regs)
+{
+ u16 count = regs->cx;
+
+ if (count == 1) {
+ sercon_lazy_putchar(regs->al, regs->bl, 0);
+
+ } else if (regs->al == 0x20 &&
+ video_rows() * video_cols() == count &&
+ cursor_pos_row() == 0 &&
+ cursor_pos_col() == 0) {
+ /* override everything with spaces -> this is clear screen */
+ sercon_lazy_flush();
+ sercon_set_attr(regs->bl);
+ sercon_term_clear_screen();
+
+ } else {
+ sercon_lazy_flush();
+ sercon_set_attr(regs->bl);
+ while (count) {
+ sercon_print_utf8(regs->al);
+ count--;
+ }
+ sercon_term_cursor_goto(cursor_pos_row(),
+ cursor_pos_col());
+ }
+}
+
+/* Teletype output */
+static void sercon_100e(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 7:
+ sercon_putchar(0x07);
+ break;
+ case 8:
+ sercon_lazy_backspace();
+ break;
+ case '\r':
+ sercon_lazy_cr();
+ break;
+ case '\n':
+ sercon_lazy_lf();
+ break;
+ default:
+ sercon_lazy_putchar(regs->al, 0, 1);
+ break;
+ }
+}
+
+/* Get current video mode */
+static void sercon_100f(struct bregs *regs)
+{
+ regs->al = GET_BDA(video_mode);
+ regs->ah = GET_BDA(video_cols);
+}
+
+/* VBE 2.0 */
+static void sercon_104f(struct bregs *regs)
+{
+ if (!sercon_splitmode()) {
+ regs->ax = 0x0100;
+ } else {
+ // Disable sercon entry point on any vesa modeset
+ if (regs->al == 0x02)
+ SET_LOW(sercon_enable, 0);
+ }
+}
+
+static void sercon_10XX(struct bregs *regs)
+{
+ warn_unimplemented(regs);
+}
+
+void VISIBLE16
+handle_sercon(struct bregs *regs)
+{
+ if (!CONFIG_SERCON)
+ return;
+ if (!GET_LOW(sercon_port))
+ return;
+
+ switch (regs->ah) {
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x08:
+ case 0x0f:
+ if (sercon_splitmode())
+ /* nothing, vgabios handles it */
+ return;
+ }
+
+ switch (regs->ah) {
+ case 0x00: sercon_1000(regs); break;
+ case 0x01: sercon_1001(regs); break;
+ case 0x02: sercon_1002(regs); break;
+ case 0x03: sercon_1003(regs); break;
+ case 0x06: sercon_1006(regs); break;
+ case 0x08: sercon_1008(regs); break;
+ case 0x09: sercon_1009(regs); break;
+ case 0x0e: sercon_100e(regs); break;
+ case 0x0f: sercon_100f(regs); break;
+ case 0x4f: sercon_104f(regs); break;
+ default: sercon_10XX(regs); break;
+ }
+}
+
+void sercon_setup(void)
+{
+ if (!CONFIG_SERCON)
+ return;
+
+ struct segoff_s seabios, vgabios;
+ u16 addr;
+
+ addr = romfile_loadint("etc/sercon-port", 0);
+ if (!addr)
+ return;
+ dprintf(1, "sercon: using ioport 0x%x\n", addr);
+
+ if (CONFIG_DEBUG_SERIAL)
+ if (addr == CONFIG_DEBUG_SERIAL_PORT)
+ ScreenAndDebug = 0;
+
+ vgabios = GET_IVT(0x10);
+ seabios = FUNC16(entry_10);
+ if (vgabios.seg != seabios.seg ||
+ vgabios.offset != seabios.offset) {
+ dprintf(1, "sercon: configuring in splitmode (vgabios %04x:%04x)\n",
+ vgabios.seg, vgabios.offset);
+ sercon_real_vga_handler = vgabios;
+ SET_LOW(sercon_split, 1);
+ } else {
+ dprintf(1, "sercon: configuring as primary display\n");
+ sercon_real_vga_handler = seabios;
+ }
+
+ SET_IVT(0x10, FUNC16(entry_sercon));
+ SET_LOW(sercon_port, addr);
+ outb(0x03, addr + SEROFF_LCR); // 8N1
+ outb(0x01, addr + SEROFF_IIR); // enable fifo
+}
+
+/****************************************************************
+ * serial input
+ ****************************************************************/
+
+VARLOW u8 rx_buf[16];
+VARLOW u8 rx_bytes;
+
+static VAR16 struct {
+ char seq[4];
+ u8 len;
+ u16 keycode;
+} termseq[] = {
+ { .seq = "OP", .len = 2, .keycode = 0x3b00 }, // F1
+ { .seq = "OQ", .len = 2, .keycode = 0x3c00 }, // F2
+ { .seq = "OR", .len = 2, .keycode = 0x3d00 }, // F3
+ { .seq = "OS", .len = 2, .keycode = 0x3e00 }, // F4
+
+ { .seq = "[15~", .len = 4, .keycode = 0x3f00 }, // F5
+ { .seq = "[17~", .len = 4, .keycode = 0x4000 }, // F6
+ { .seq = "[18~", .len = 4, .keycode = 0x4100 }, // F7
+ { .seq = "[19~", .len = 4, .keycode = 0x4200 }, // F8
+ { .seq = "[20~", .len = 4, .keycode = 0x4300 }, // F9
+ { .seq = "[21~", .len = 4, .keycode = 0x4400 }, // F10
+ { .seq = "[23~", .len = 4, .keycode = 0x5700 }, // F11
+ { .seq = "[24~", .len = 4, .keycode = 0x5800 }, // F12
+
+ { .seq = "[2~", .len = 3, .keycode = 0x52e0 }, // insert
+ { .seq = "[3~", .len = 3, .keycode = 0x53e0 }, // delete
+ { .seq = "[5~", .len = 3, .keycode = 0x49e0 }, // page up
+ { .seq = "[6~", .len = 3, .keycode = 0x51e0 }, // page down
+
+ { .seq = "[A", .len = 2, .keycode = 0x48e0 }, // up
+ { .seq = "[B", .len = 2, .keycode = 0x50e0 }, // down
+ { .seq = "[C", .len = 2, .keycode = 0x4de0 }, // right
+ { .seq = "[D", .len = 2, .keycode = 0x4be0 }, // left
+
+ { .seq = "[H", .len = 2, .keycode = 0x47e0 }, // home
+ { .seq = "[F", .len = 2, .keycode = 0x4fe0 }, // end
+};
+
+static void shiftbuf(int remove)
+{
+ int i, remaining;
+
+ remaining = GET_LOW(rx_bytes) - remove;
+ SET_LOW(rx_bytes, remaining);
+ for (i = 0; i < remaining; i++)
+ SET_LOW(rx_buf[i], GET_LOW(rx_buf[i + remove]));
+}
+
+static int cmpbuf(int seq)
+{
+ int chr, len;
+
+ len = GET_GLOBAL(termseq[seq].len);
+ if (GET_LOW(rx_bytes) < len + 1)
+ return 0;
+ for (chr = 0; chr < len; chr++)
+ if (GET_GLOBAL(termseq[seq].seq[chr]) != GET_LOW(rx_buf[chr + 1]))
+ return 0;
+ return 1;
+}
+
+static int findseq(void)
+{
+ int seq;
+
+ for (seq = 0; seq < ARRAY_SIZE(termseq); seq++)
+ if (cmpbuf(seq))
+ return seq;
+ return -1;
+}
+
+void
+sercon_check_event(void)
+{
+ if (!CONFIG_SERCON)
+ return;
+
+ u16 addr = GET_LOW(sercon_port);
+ u16 keycode;
+ u8 byte, count = 0;
+ int seq, chr;
+
+ // check to see if there is a active serial port
+ if (!addr)
+ return;
+ if (inb(addr + SEROFF_LSR) == 0xFF)
+ return;
+
+ // flush pending output
+ sercon_lazy_flush();
+
+ // read all available data
+ while (inb(addr + SEROFF_LSR) & 0x01) {
+ byte = inb(addr + SEROFF_DATA);
+ if (GET_LOW(rx_bytes) < sizeof(rx_buf)) {
+ SET_LOW(rx_buf[rx_bytes], byte);
+ SET_LOW(rx_bytes, GET_LOW(rx_bytes) + 1);
+ count++;
+ }
+ }
+
+ for (;;) {
+ // no (more) input data
+ if (!GET_LOW(rx_bytes))
+ return;
+
+ // lookup escape sequences
+ if (GET_LOW(rx_bytes) > 1 && GET_LOW(rx_buf[0]) == 0x1b) {
+ seq = findseq();
+ if (seq >= 0) {
+ enqueue_key(GET_GLOBAL(termseq[seq].keycode));
+ shiftbuf(GET_GLOBAL(termseq[seq].len) + 1);
+ continue;
+ }
+ }
+
+ // Seems we got a escape sequence we didn't recognise.
+ // -> If we received data wait for more, maybe it is just incomplete.
+ if (GET_LOW(rx_buf[0]) == 0x1b && count)
+ return;
+
+ // Handle input as individual char.
+ chr = GET_LOW(rx_buf[0]);
+ keycode = ascii_to_keycode(chr);
+ if (keycode)
+ enqueue_key(keycode);
+ shiftbuf(1);
+ }
+}
diff --git a/roms/seabios-hppa/src/serial.c b/roms/seabios-hppa/src/serial.c
new file mode 100644
index 000000000..8813831bf
--- /dev/null
+++ b/roms/seabios-hppa/src/serial.c
@@ -0,0 +1,319 @@
+// 16bit code to handle serial and printer services.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // SET_BDA
+#include "bregs.h" // struct bregs
+#include "hw/serialio.h" // SEROFF_IER
+#include "output.h" // debug_enter
+#include "romfile.h" // romfile_loadint
+#include "stacks.h" // yield
+#include "util.h" // serial_setup
+
+
+/****************************************************************
+ * COM ports
+ ****************************************************************/
+
+static u16
+detect_serial(portaddr_t port, u8 timeout, u8 count)
+{
+ if (CONFIG_DEBUG_SERIAL && port == CONFIG_DEBUG_SERIAL_PORT
+ && !romfile_loadint("etc/advertise-serial-debug-port", 1))
+ return 0;
+ if (!port)
+ return 0;
+ outb(0x02, port+SEROFF_IER);
+ u8 ier = inb(port+SEROFF_IER);
+ if (ier != 0x02)
+ return 0;
+ u8 iir = inb(port+SEROFF_IIR);
+ if ((iir & 0x3f) != 0x02)
+ return 0;
+
+ outb(0x00, port+SEROFF_IER);
+ SET_BDA(port_com[count], port);
+ SET_BDA(com_timeout[count], timeout);
+ return 1;
+}
+
+void
+serial_setup(void)
+{
+ if (! CONFIG_SERIAL)
+ return;
+ dprintf(3, "init serial\n");
+
+ u16 count = 0;
+ count += detect_serial(PORT_SERIAL1, 0x0a, count);
+ count += detect_serial(PORT_SERIAL2, 0x0a, count);
+ count += detect_serial(PORT_SERIAL3, 0x0a, count);
+ count += detect_serial(PORT_SERIAL4, 0x0a, count);
+ dprintf(1, "Found %d serial ports\n", count);
+
+ // Equipment word bits 9..11 determing # serial ports
+ set_equipment_flags(0xe00, count << 9);
+}
+
+static u16
+getComAddr(struct bregs *regs)
+{
+ if (regs->dx >= 4) {
+ set_invalid(regs);
+ return 0;
+ }
+ u16 addr = GET_BDA(port_com[regs->dx]);
+ if (! addr)
+ set_invalid(regs);
+ return addr;
+}
+
+// SERIAL - INITIALIZE PORT
+static void
+handle_1400(struct bregs *regs)
+{
+ u16 addr = getComAddr(regs);
+ if (!addr)
+ return;
+ outb(inb(addr+SEROFF_LCR) | 0x80, addr+SEROFF_LCR);
+ if ((regs->al & 0xE0) == 0) {
+ outb(0x17, addr+SEROFF_DLL);
+ outb(0x04, addr+SEROFF_DLH);
+ } else {
+ u16 val16 = 0x600 >> ((regs->al & 0xE0) >> 5);
+ outb(val16 & 0xFF, addr+SEROFF_DLL);
+ outb(val16 >> 8, addr+SEROFF_DLH);
+ }
+ outb(regs->al & 0x1F, addr+SEROFF_LCR);
+ regs->ah = inb(addr+SEROFF_LSR);
+ regs->al = inb(addr+SEROFF_MSR);
+ set_success(regs);
+}
+
+// SERIAL - WRITE CHARACTER TO PORT
+static void
+handle_1401(struct bregs *regs)
+{
+ u16 addr = getComAddr(regs);
+ if (!addr)
+ return;
+ u32 end = irqtimer_calc_ticks(GET_BDA(com_timeout[regs->dx]));
+ for (;;) {
+ u8 lsr = inb(addr+SEROFF_LSR);
+ if ((lsr & 0x60) == 0x60) {
+ // Success - can write data
+ outb(regs->al, addr+SEROFF_DATA);
+ // XXX - reread lsr?
+ regs->ah = lsr;
+ break;
+ }
+ if (irqtimer_check(end)) {
+ // Timed out - can't write data.
+ regs->ah = lsr | 0x80;
+ break;
+ }
+ yield();
+ }
+ set_success(regs);
+}
+
+// SERIAL - READ CHARACTER FROM PORT
+static void
+handle_1402(struct bregs *regs)
+{
+ u16 addr = getComAddr(regs);
+ if (!addr)
+ return;
+ u32 end = irqtimer_calc_ticks(GET_BDA(com_timeout[regs->dx]));
+ for (;;) {
+ u8 lsr = inb(addr+SEROFF_LSR);
+ if (lsr & 0x01) {
+ // Success - can read data
+ regs->al = inb(addr+SEROFF_DATA);
+ regs->ah = lsr;
+ break;
+ }
+ if (irqtimer_check(end)) {
+ // Timed out - can't read data.
+ regs->ah = lsr | 0x80;
+ break;
+ }
+ yield();
+ }
+ set_success(regs);
+}
+
+// SERIAL - GET PORT STATUS
+static void
+handle_1403(struct bregs *regs)
+{
+ u16 addr = getComAddr(regs);
+ if (!addr)
+ return;
+ regs->ah = inb(addr+SEROFF_LSR);
+ regs->al = inb(addr+SEROFF_MSR);
+ set_success(regs);
+}
+
+static void
+handle_14XX(struct bregs *regs)
+{
+ set_unimplemented(regs);
+}
+
+// INT 14h Serial Communications Service Entry Point
+void VISIBLE16
+handle_14(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_14);
+ if (! CONFIG_SERIAL) {
+ handle_14XX(regs);
+ return;
+ }
+
+ switch (regs->ah) {
+ case 0x00: handle_1400(regs); break;
+ case 0x01: handle_1401(regs); break;
+ case 0x02: handle_1402(regs); break;
+ case 0x03: handle_1403(regs); break;
+ default: handle_14XX(regs); break;
+ }
+}
+
+
+/****************************************************************
+ * LPT ports
+ ****************************************************************/
+
+static u16
+detect_parport(u16 port, u8 timeout, u8 count)
+{
+ // clear input mode
+ outb(inb(port+2) & 0xdf, port+2);
+
+ outb(0xaa, port);
+ if (inb(port) != 0xaa)
+ // Not present
+ return 0;
+ SET_BDA(port_lpt[count], port);
+ SET_BDA(lpt_timeout[count], timeout);
+ return 1;
+}
+
+void
+lpt_setup(void)
+{
+ if (! CONFIG_LPT)
+ return;
+ dprintf(3, "init lpt\n");
+
+ u16 count = 0;
+ count += detect_parport(PORT_LPT1, 0x14, count);
+ count += detect_parport(PORT_LPT2, 0x14, count);
+ dprintf(1, "Found %d lpt ports\n", count);
+
+ // Equipment word bits 14..15 determing # parallel ports
+ set_equipment_flags(0xc000, count << 14);
+}
+
+static u16
+getLptAddr(struct bregs *regs)
+{
+ if (regs->dx >= 3) {
+ set_invalid(regs);
+ return 0;
+ }
+ u16 addr = GET_BDA(port_lpt[regs->dx]);
+ if (! addr)
+ set_invalid(regs);
+ return addr;
+}
+
+// INT 17 - PRINTER - WRITE CHARACTER
+static void
+handle_1700(struct bregs *regs)
+{
+ u16 addr = getLptAddr(regs);
+ if (!addr)
+ return;
+
+ u32 end = irqtimer_calc_ticks(GET_BDA(lpt_timeout[regs->dx]));
+
+ outb(regs->al, addr);
+ u8 val8 = inb(addr+2);
+ outb(val8 | 0x01, addr+2); // send strobe
+ udelay(5);
+ outb(val8 & ~0x01, addr+2);
+
+ for (;;) {
+ u8 v = inb(addr+1);
+ if (!(v & 0x40)) {
+ // Success
+ regs->ah = v ^ 0x48;
+ break;
+ }
+ if (irqtimer_check(end)) {
+ // Timeout
+ regs->ah = (v ^ 0x48) | 0x01;
+ break;
+ }
+ yield();
+ }
+
+ set_success(regs);
+}
+
+// INT 17 - PRINTER - INITIALIZE PORT
+static void
+handle_1701(struct bregs *regs)
+{
+ u16 addr = getLptAddr(regs);
+ if (!addr)
+ return;
+
+ u8 val8 = inb(addr+2);
+ outb(val8 & ~0x04, addr+2); // send init
+ udelay(5);
+ outb(val8 | 0x04, addr+2);
+
+ regs->ah = inb(addr+1) ^ 0x48;
+ set_success(regs);
+}
+
+// INT 17 - PRINTER - GET STATUS
+static void
+handle_1702(struct bregs *regs)
+{
+ u16 addr = getLptAddr(regs);
+ if (!addr)
+ return;
+ regs->ah = inb(addr+1) ^ 0x48;
+ set_success(regs);
+}
+
+static void
+handle_17XX(struct bregs *regs)
+{
+ set_unimplemented(regs);
+}
+
+// INT17h : Printer Service Entry Point
+void VISIBLE16
+handle_17(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_17);
+ if (! CONFIG_LPT) {
+ handle_17XX(regs);
+ return;
+ }
+
+ switch (regs->ah) {
+ case 0x00: handle_1700(regs); break;
+ case 0x01: handle_1701(regs); break;
+ case 0x02: handle_1702(regs); break;
+ default: handle_17XX(regs); break;
+ }
+}
diff --git a/roms/seabios-hppa/src/sha.h b/roms/seabios-hppa/src/sha.h
new file mode 100644
index 000000000..edc9437e4
--- /dev/null
+++ b/roms/seabios-hppa/src/sha.h
@@ -0,0 +1,11 @@
+#ifndef __SHA_H
+#define __SHA_H
+
+#include "types.h" // u32
+
+void sha1(const u8 *data, u32 length, u8 *hash);
+void sha256(const u8 *data, u32 length, u8 *hash);
+void sha384(const u8 *data, u32 length, u8 *hash);
+void sha512(const u8 *data, u32 length, u8 *hash);
+
+#endif // sha.h
diff --git a/roms/seabios-hppa/src/sha1.c b/roms/seabios-hppa/src/sha1.c
new file mode 100644
index 000000000..e6d80c80c
--- /dev/null
+++ b/roms/seabios-hppa/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 "sha.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]);
+}
+
+
+void
+sha1(const u8 *data, u32 length, u8 *hash)
+{
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ 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;
+}
diff --git a/roms/seabios-hppa/src/sha256.c b/roms/seabios-hppa/src/sha256.c
new file mode 100644
index 000000000..72c3df837
--- /dev/null
+++ b/roms/seabios-hppa/src/sha256.c
@@ -0,0 +1,211 @@
+/*****************************************************************************
+ * Copyright (c) 2015-2020 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
+ *****************************************************************************/
+
+/*
+ * See: NIST standard for SHA-256 in FIPS PUB 180-4
+ */
+
+#include "config.h"
+#include "byteorder.h"
+#include "sha.h"
+#include "string.h"
+#include "x86.h"
+
+typedef struct _sha256_ctx {
+ u32 h[8];
+} sha256_ctx;
+
+static inline u32 Ch(u32 x, u32 y, u32 z)
+{
+ return (x & y) | ((x ^ 0xffffffff) & z);
+}
+
+static inline u32 Maj(u32 x, u32 y, u32 z)
+{
+ return (x & y) | (x & z) | (y & z);
+}
+
+static inline u32 sum0(u32 x)
+{
+ return ror(x, 2) ^ ror(x, 13) ^ ror(x, 22);
+}
+
+static inline u32 sum1(u32 x)
+{
+ return ror(x, 6) ^ ror(x, 11) ^ ror(x, 25);
+}
+
+static inline u32 sigma0(u32 x)
+{
+ return ror(x, 7) ^ ror(x, 18) ^ (x >> 3);
+}
+
+static inline u32 sigma1(u32 x)
+{
+ return ror(x, 17) ^ ror(x, 19) ^ (x >> 10);
+}
+
+static void sha256_block(u32 *w, sha256_ctx *ctx)
+{
+ u32 t;
+ u32 a, b, c, d, e, f, g, h;
+ u32 T1, T2;
+
+ /*
+ * FIPS 180-4 4.2.2: SHA256 Constants
+ */
+ static const u32 sha_ko[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+ };
+
+ /*
+ * FIPS 180-4 6.2.2: step 1
+ *
+ * 0 <= i <= 15:
+ * W(t) = M(t)
+ * 16 <= i <= 63:
+ * W(t) = sigma1(W(t-2)) + W(t-7) + sigma0(W(t-15)) + W(t-16)
+ */
+
+ /* w(0)..w(15) are in big endian format */
+ for (t = 0; t <= 15; t++)
+ w[t] = be32_to_cpu(w[t]);
+
+ for (t = 16; t <= 63; t++)
+ w[t] = sigma1(w[t-2]) + w[t-7] + sigma0(w[t-15]) + w[t-16];
+
+ /*
+ * step 2: a = H0, b = H1, c = H2, d = H3, e = H4, f = H5, g = H6, h = H7
+ */
+ a = ctx->h[0];
+ b = ctx->h[1];
+ c = ctx->h[2];
+ d = ctx->h[3];
+ e = ctx->h[4];
+ f = ctx->h[5];
+ g = ctx->h[6];
+ h = ctx->h[7];
+
+ /*
+ * step 3: For i = 0 to 63:
+ * T1 = h + sum1(e) + Ch(e,f,g) + K(t) + W(t);
+ * T2 = sum0(a) + Maj(a,b,c)
+ * h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a + T1 + T2
+ */
+ for (t = 0; t <= 63; t++) {
+ T1 = h + sum1(e) + Ch(e, f, g) + sha_ko[t] + w[t];
+ T2 = sum0(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+ }
+
+ /*
+ * step 4:
+ * H0 = a + H0, H1 = b + H1, H2 = c + H2, H3 = d + H3, H4 = e + H4
+ */
+ ctx->h[0] += a;
+ ctx->h[1] += b;
+ ctx->h[2] += c;
+ ctx->h[3] += d;
+ ctx->h[4] += e;
+ ctx->h[5] += f;
+ ctx->h[6] += g;
+ ctx->h[7] += h;
+}
+
+static void sha256_do(sha256_ctx *ctx, const u8 *data32, u32 length)
+{
+ u32 offset;
+ u16 num;
+ u32 bits = 0;
+ u32 w[64];
+ u64 tmp;
+
+ /* treat data in 64-byte chunks */
+ for (offset = 0; length - offset >= 64; offset += 64) {
+ memcpy(w, data32 + offset, 64);
+ sha256_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);
+ /*
+ * FIPS 180-4 5.1: Padding the Message
+ */
+ ((u8 *)w)[num] = 0x80;
+ if (64 - (num + 1) > 0)
+ memset( &((u8 *)w)[num + 1], 0, 64 - (num + 1));
+
+ if (num >= 56) {
+ /* cannot append number of bits here */
+ sha256_block((u32 *)w, ctx);
+ memset(w, 0, 60);
+ }
+
+ /* write number of bits to end of block */
+ tmp = cpu_to_be64(bits);
+ memcpy(&w[14], &tmp, 8);
+
+ sha256_block(w, ctx);
+
+ /* need to switch result's endianness */
+ for (num = 0; num < 8; num++)
+ ctx->h[num] = cpu_to_be32(ctx->h[num]);
+}
+
+void sha256(const u8 *data, u32 length, u8 *hash)
+{
+ sha256_ctx ctx = {
+ .h = {
+ /*
+ * FIPS 180-4: 6.2.1
+ * -> 5.3.3: initial hash value
+ */
+ 0x6a09e667,
+ 0xbb67ae85,
+ 0x3c6ef372,
+ 0xa54ff53a,
+ 0x510e527f,
+ 0x9b05688c,
+ 0x1f83d9ab,
+ 0x5be0cd19
+ }
+ };
+
+ sha256_do(&ctx, data, length);
+ memcpy(hash, ctx.h, sizeof(ctx.h));
+}
diff --git a/roms/seabios-hppa/src/sha512.c b/roms/seabios-hppa/src/sha512.c
new file mode 100644
index 000000000..fddd9fa7e
--- /dev/null
+++ b/roms/seabios-hppa/src/sha512.c
@@ -0,0 +1,244 @@
+/*****************************************************************************
+ * Copyright (c) 2021 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
+ *****************************************************************************/
+
+/*
+ * See: NIST standard for SHA-512 and SHA-384 in FIPS PUB 180-4 & RFC 6234
+ */
+
+#include "config.h"
+#include "byteorder.h"
+#include "sha.h"
+#include "string.h"
+
+typedef struct _sha512_ctx {
+ u64 h[8];
+} sha512_ctx;
+
+static inline u64 ror64(u64 x, u8 n)
+{
+ return (x >> n) | (x << (64 - n));
+}
+
+static inline u64 Ch64(u64 x, u64 y, u64 z)
+{
+ return (x & y) ^ ((x ^ 0xffffffffffffffffULL) & z);
+}
+
+static inline u64 Maj64(u64 x, u64 y, u64 z)
+{
+ return (x & y) ^ (x & z) ^ (y & z);
+}
+
+static inline u64 sum0_64(u64 x)
+{
+ return ror64(x, 28) ^ ror64(x, 34) ^ ror64(x, 39);
+}
+
+static inline u64 sum1_64(u64 x)
+{
+ return ror64(x, 14) ^ ror64(x, 18) ^ ror64(x, 41);
+}
+
+static inline u64 sigma0_64(u64 x)
+{
+ return ror64(x, 1) ^ ror64(x, 8) ^ (x >> 7);
+}
+
+static inline u64 sigma1_64(u64 x)
+{
+ return ror64(x, 19) ^ ror64(x, 61) ^ (x >> 6);
+}
+
+static void sha512_block(u64 *w, sha512_ctx *ctx)
+{
+ u32 t;
+ u64 a, b, c, d, e, f, g, h;
+ u64 T1, T2;
+
+ /*
+ * FIPS 180-4 4.2.2: SHA512 Constants
+ */
+ static const u64 sha_ko[80] = {
+ 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
+ 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
+ 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
+ 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
+ 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
+ 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
+ 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
+ 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
+ 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
+ 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
+ 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
+ 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
+ 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
+ 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
+ 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
+ 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
+ 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
+ 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
+ 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
+ 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
+ };
+
+ /*
+ * FIPS 180-4 6.4.2: step 1
+ *
+ * 0 <= i <= 15:
+ * W(t) = M(t)
+ * 16 <= i <= 79:
+ * W(t) = sigma1(W(t-2)) + W(t-7) + sigma0(W(t-15)) + W(t-16)
+ */
+
+ /* w(0)..w(15) are in big endian format */
+ for (t = 0; t <= 15; t++)
+ w[t] = be64_to_cpu(w[t]);
+
+ for (t = 16; t <= 79; t++)
+ w[t] = sigma1_64(w[t-2]) + w[t-7] + sigma0_64(w[t-15]) + w[t-16];
+
+ /*
+ * step 2: a = H0, b = H1, c = H2, d = H3, e = H4, f = H5, g = H6, h = H7
+ */
+ a = ctx->h[0];
+ b = ctx->h[1];
+ c = ctx->h[2];
+ d = ctx->h[3];
+ e = ctx->h[4];
+ f = ctx->h[5];
+ g = ctx->h[6];
+ h = ctx->h[7];
+
+ /*
+ * step 3: For i = 0 to 79:
+ * T1 = h + sum1(e) + Ch(e,f,g) + K(t) + W(t);
+ * T2 = sum0(a) + Maj(a,b,c)
+ * h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a + T1 + T2
+ */
+ for (t = 0; t <= 79; t++) {
+ T1 = h + sum1_64(e) + Ch64(e, f, g) + sha_ko[t] + w[t];
+ T2 = sum0_64(a) + Maj64(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+ }
+
+ /*
+ * step 4:
+ * H0 = a + H0, H1 = b + H1, H2 = c + H2, H3 = d + H3, H4 = e + H4
+ */
+ ctx->h[0] += a;
+ ctx->h[1] += b;
+ ctx->h[2] += c;
+ ctx->h[3] += d;
+ ctx->h[4] += e;
+ ctx->h[5] += f;
+ ctx->h[6] += g;
+ ctx->h[7] += h;
+}
+
+static void sha512_do(sha512_ctx *ctx, const u8 *data32, u32 length)
+{
+ u32 offset;
+ u16 num;
+ u64 bits = 0;
+ u64 w[80];
+ u64 tmp;
+
+ /* treat data in 128-byte/1024 bit chunks */
+ for (offset = 0; length - offset >= 128; offset += 128) {
+ memcpy(w, data32 + offset, 128);
+ sha512_block(w, ctx);
+ bits += (128 * 8);
+ }
+
+ /* last block with less than 128 bytes */
+ num = length - offset;
+ bits += (num << 3);
+
+ memcpy(w, data32 + offset, num);
+ /*
+ * FIPS 180-4 5.1: Padding the Message
+ */
+ ((u8 *)w)[num] = 0x80;
+ if (128 - (num + 1) > 0)
+ memset( &((u8 *)w)[num + 1], 0, 128 - (num + 1));
+
+ if (num >= 112) {
+ /* cannot append number of bits here;
+ * need space for 128 bits (16 bytes)
+ */
+ sha512_block((u64 *)w, ctx);
+ memset(w, 0, 128);
+ }
+
+ /* write number of bits to end of the block; we write 64 bits */
+ tmp = cpu_to_be64(bits);
+ memcpy(&w[15], &tmp, 8);
+
+ sha512_block(w, ctx);
+
+ /* need to switch result's endianness */
+ for (num = 0; num < 8; num++)
+ ctx->h[num] = cpu_to_be64(ctx->h[num]);
+}
+
+void sha384(const u8 *data, u32 length, u8 *hash)
+{
+ sha512_ctx ctx = {
+ .h = {
+ /*
+ * FIPS 180-4: 6.2.1
+ * -> 5.3.4: initial hash value
+ */
+ 0xcbbb9d5dc1059ed8,
+ 0x629a292a367cd507,
+ 0x9159015a3070dd17,
+ 0x152fecd8f70e5939,
+ 0x67332667ffc00b31,
+ 0x8eb44a8768581511,
+ 0xdb0c2e0d64f98fa7,
+ 0x47b5481dbefa4fa4
+ }
+ };
+
+ sha512_do(&ctx, data, length);
+ memcpy(hash, ctx.h, 384/8);
+}
+
+void sha512(const u8 *data, u32 length, u8 *hash)
+{
+ sha512_ctx ctx = {
+ .h = {
+ /*
+ * FIPS 180-4: 6.2.1
+ * -> 5.3.5: initial hash value
+ */
+ 0x6a09e667f3bcc908,
+ 0xbb67ae8584caa73b,
+ 0x3c6ef372fe94f82b,
+ 0xa54ff53a5f1d36f1,
+ 0x510e527fade682d1,
+ 0x9b05688c2b3e6c1f,
+ 0x1f83d9abfb41bd6b,
+ 0x5be0cd19137e2179
+ }
+ };
+
+ sha512_do(&ctx, data, length);
+ memcpy(hash, ctx.h, sizeof(ctx.h));
+}
diff --git a/roms/seabios-hppa/src/stacks.c b/roms/seabios-hppa/src/stacks.c
new file mode 100644
index 000000000..4c8e5df68
--- /dev/null
+++ b/roms/seabios-hppa/src/stacks.c
@@ -0,0 +1,776 @@
+// Code for manipulating stack locations.
+//
+// Copyright (C) 2009-2015 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "bregs.h" // CR0_PE
+#include "fw/paravirt.h" // PORT_SMI_CMD
+#include "hw/rtc.h" // rtc_use
+#include "list.h" // hlist_node
+#include "malloc.h" // free
+#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)
+
+
+/****************************************************************
+ * 16bit / 32bit calling
+ ****************************************************************/
+
+struct {
+ u8 method;
+ u8 cmosindex;
+ u8 a20;
+ u16 ss, fs, gs;
+ u32 cr0;
+ struct descloc_s gdt;
+} Call16Data VARLOW;
+
+#define C16_BIG 1
+#define C16_SMM 2
+
+int HaveSmmCall32 VARFSEG;
+
+// 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);
+ if (!(cmosindex & NMI_DISABLE_BIT)) {
+ outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX);
+ inb(PORT_CMOS_DATA);
+ }
+ SET_LOW(Call16Data.cmosindex, cmosindex);
+
+ SET_LOW(Call16Data.method, method);
+ return 0;
+}
+
+// Restore state backed up during call32
+static u8
+call32_post(void)
+{
+ 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
+ u8 a20 = GET_LOW(Call16Data.a20);
+ if (!a20)
+ set_a20(0);
+
+ // 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
+ u8 cmosindex = GET_LOW(Call16Data.cmosindex);
+ if (!(cmosindex & NMI_DISABLE_BIT)) {
+ outb(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"
+#define ASM32_BACK32 " .popsection\n .code32\n"
+#define ASM16_SWITCH32 " .code32\n"
+#define ASM16_BACK16 " .code16gcc\n"
+
+// Call a SeaBIOS C function in 32bit mode using smm trampoline
+static u32
+call32_smm(void *func, u32 eax)
+{
+ ASSERT16();
+ dprintf(9, "call32_smm %p %x\n", func, eax);
+ call32_prep(C16_SMM);
+ u32 bkup_esp;
+ asm volatile(
+ // Backup esp / set esp to flat stack location
+ " movl %%esp, %0\n"
+ " movl %%ss, %%eax\n"
+ " shll $4, %%eax\n"
+ " addl %%eax, %%esp\n"
+
+ // Transition to 32bit mode, call func, return to 16bit
+ " movl $" __stringify(CALL32SMM_CMDID) ", %%eax\n"
+ " movl $" __stringify(CALL32SMM_ENTERID) ", %%ecx\n"
+ " movl $(" __stringify(BUILD_BIOS_ADDR) " + 1f), %%ebx\n"
+ " outb %%al, $" __stringify(PORT_SMI_CMD) "\n"
+ " rep; nop\n"
+ " hlt\n"
+
+ ASM16_SWITCH32
+ "1:movl %1, %%eax\n"
+ " calll *%2\n"
+ " movl %%eax, %1\n"
+
+ " movl $" __stringify(CALL32SMM_CMDID) ", %%eax\n"
+ " movl $" __stringify(CALL32SMM_RETURNID) ", %%ecx\n"
+ " movl $2f, %%ebx\n"
+ " outb %%al, $" __stringify(PORT_SMI_CMD) "\n"
+ " rep; nop\n"
+ " hlt\n"
+
+ // Restore esp
+ ASM16_BACK16
+ "2:movl %0, %%esp\n"
+ : "=&r" (bkup_esp), "+r" (eax)
+ : "r" (func)
+ : "eax", "ecx", "edx", "ebx", "cc", "memory");
+ call32_post();
+
+ dprintf(9, "call32_smm done %p %x\n", func, eax);
+ return eax;
+}
+
+static u32
+call16_smm(u32 eax, u32 edx, void *func)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_CALL32_SMM)
+ return eax;
+ func -= BUILD_BIOS_ADDR;
+ dprintf(9, "call16_smm %p %x %x\n", func, eax, edx);
+ u32 stackoffset = Call16Data.ss << 4;
+ asm volatile(
+ // Restore esp
+ " subl %0, %%esp\n"
+
+ // Transition to 16bit mode, call func, return to 32bit
+ " movl $" __stringify(CALL32SMM_CMDID) ", %%eax\n"
+ " movl $" __stringify(CALL32SMM_RETURNID) ", %%ecx\n"
+ " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%ebx\n"
+ " outb %%al, $" __stringify(PORT_SMI_CMD) "\n"
+ " rep; nop\n"
+ " hlt\n"
+
+ ASM32_SWITCH16
+ "1:movl %1, %%eax\n"
+ " movl %3, %%ecx\n"
+ " calll _cfunc16_call16_helper\n"
+ " movl %%eax, %1\n"
+
+ " movl $" __stringify(CALL32SMM_CMDID) ", %%eax\n"
+ " movl $" __stringify(CALL32SMM_ENTERID) ", %%ecx\n"
+ " movl $2f, %%ebx\n"
+ " outb %%al, $" __stringify(PORT_SMI_CMD) "\n"
+ " rep; nop\n"
+ " hlt\n"
+
+ // Set esp to flat stack location
+ ASM32_BACK32
+ "2:addl %0, %%esp\n"
+ : "+r" (stackoffset), "+r" (eax), "+d" (edx)
+ : "r" (func)
+ : "eax", "ecx", "ebx", "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);
+ // 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
+ " movl %%ss, %0\n"
+ " movl %%esp, %1\n"
+ " shll $4, %0\n"
+ " addl %0, %%esp\n"
+ " shrl $4, %0\n"
+
+ // Transition to 32bit mode, call func, return to 16bit
+ " movl $(" __stringify(BUILD_BIOS_ADDR) " + 1f), %%edx\n"
+ " jmp transition32_nmi_off\n"
+ ASM16_SWITCH32
+ "1:calll *%3\n"
+ " movl $2f, %%edx\n"
+ " jmp transition16big\n"
+
+ // Restore ds/ss/esp
+ ASM16_BACK16
+ "2:movl %0, %%ds\n"
+ " movl %0, %%ss\n"
+ " movl %1, %%esp\n"
+ : "=&r" (bkup_ss), "=&r" (bkup_esp), "+a" (eax)
+ : "r" (func)
+ : "ecx", "edx", "cc", "memory");
+ call32_post();
+ return eax;
+}
+
+// Call a 16bit SeaBIOS function, restoring the mode from last call32().
+static u32
+call16(u32 eax, u32 edx, void *func)
+{
+ ASSERT32FLAT();
+ if (getesp() > MAIN_STACK_MAX)
+ 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 = Call16Data.ss;
+ asm volatile(
+ // Transition to 16bit mode
+ " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n"
+ " jmp *%%ecx\n"
+ // Setup ss/esp and call func
+ ASM32_SWITCH16
+ "1:movl %2, %%ecx\n"
+ " shll $4, %2\n"
+ " movw %%cx, %%ss\n"
+ " subl %2, %%esp\n"
+ " movw %%cx, %%ds\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_nmi_off\n"
+ ASM32_BACK32
+ "2:addl %2, %%esp\n"
+ : "+a" (eax), "+c"(thunk), "+r"(stackseg)
+ : "r" (func), "r" (edx)
+ : "edx", "cc", "memory");
+ return eax;
+}
+
+
+/****************************************************************
+ * Extra 16bit stack
+ ****************************************************************/
+
+// Space for a stack for 16bit code.
+u8 ExtraStack[BUILD_EXTRA_STACK_SIZE+1] VARLOW __aligned(8);
+u8 *StackPos VARLOW;
+
+// Test if currently on the extra stack
+int
+on_extra_stack(void)
+{
+ return MODE16 && GET_SEG(SS) == SEG_LOW && getesp() > (u32)ExtraStack;
+}
+
+// Switch to the extra stack and call a function.
+u32
+__stack_hop(u32 eax, u32 edx, void *func)
+{
+ if (on_extra_stack())
+ return ((u32 (*)(u32, u32))func)(eax, edx);
+ ASSERT16();
+ u16 stack_seg = SEG_LOW;
+ u32 bkup_ss, bkup_esp;
+ asm volatile(
+ // Backup current %ss/%esp values.
+ "movw %%ss, %w3\n"
+ "movl %%esp, %4\n"
+ // Copy stack seg to %ds/%ss and set %esp
+ "movw %w6, %%ds\n"
+ "movw %w6, %%ss\n"
+ "movl %5, %%esp\n"
+ "pushl %3\n"
+ "pushl %4\n"
+ // Call func
+ "calll *%2\n"
+ "popl %4\n"
+ "popl %3\n"
+ // Restore segments and stack
+ "movw %w3, %%ds\n"
+ "movw %w3, %%ss\n"
+ "movl %4, %%esp"
+ : "+a" (eax), "+d" (edx), "+c" (func), "=&r" (bkup_ss), "=&r" (bkup_esp)
+ : "m" (StackPos), "r" (stack_seg)
+ : "cc", "memory");
+ return eax;
+}
+
+// Switch back to original caller's stack and call a function.
+u32
+__stack_hop_back(u32 eax, u32 edx, void *func)
+{
+ if (!MODESEGMENT)
+ return call16(eax, edx, func);
+ if (!MODE16 || !on_extra_stack())
+ return ((u32 (*)(u32, u32))func)(eax, edx);
+ ASSERT16();
+ u16 bkup_ss;
+ u32 bkup_stack_pos, temp;
+ asm volatile(
+ // Backup stack_pos and current %ss/%esp
+ "movl %6, %4\n"
+ "movw %%ss, %w3\n"
+ "movl %%esp, %6\n"
+ // Restore original callers' %ss/%esp
+ "movl -4(%4), %5\n"
+ "movl %5, %%ss\n"
+ "movw %%ds:-8(%4), %%sp\n"
+ "movl %5, %%ds\n"
+ // Call func
+ "calll *%2\n"
+ // Restore %ss/%esp and stack_pos
+ "movw %w3, %%ds\n"
+ "movw %w3, %%ss\n"
+ "movl %6, %%esp\n"
+ "movl %4, %6"
+ : "+a" (eax), "+d" (edx), "+c" (func), "=&r" (bkup_ss)
+ , "=&r" (bkup_stack_pos), "=&r" (temp), "+m" (StackPos)
+ :
+ : "cc", "memory");
+ return eax;
+}
+
+
+/****************************************************************
+ * External 16bit interface calling
+ ****************************************************************/
+
+// Far call 16bit code with a specified register state.
+void VISIBLE16
+_farcall16(struct bregs *callregs, u16 callregseg)
+{
+ if (need_hop_back()) {
+ stack_hop_back(_farcall16, callregs, callregseg);
+ return;
+ }
+ ASSERT16();
+ asm volatile(
+ "calll __farcall16\n"
+ : "+a" (callregs), "+m" (*callregs), "+d" (callregseg)
+ :
+ : "ebx", "ecx", "esi", "edi", "cc", "memory");
+}
+
+// Invoke external 16bit code.
+void
+farcall16(struct bregs *callregs)
+{
+ call16_override(0);
+ _farcall16(callregs, 0);
+}
+
+// Invoke external 16bit code in "big real" mode.
+void
+farcall16big(struct bregs *callregs)
+{
+ call16_override(1);
+ _farcall16(callregs, 0);
+}
+
+// Invoke a 16bit software interrupt.
+void
+__call16_int(struct bregs *callregs, u16 offset)
+{
+ callregs->code.offset = offset;
+ if (!MODESEGMENT) {
+ callregs->code.seg = SEG_BIOS;
+ _farcall16((void*)callregs - Call16Data.ss * 16, Call16Data.ss);
+ return;
+ }
+ callregs->code.seg = GET_SEG(CS);
+ _farcall16(callregs, GET_SEG(SS));
+}
+
+// Reset the machine
+void
+reset(void)
+{
+ extern void reset_vector(void) __noreturn;
+ if (!MODE16)
+ call16(0, 0, reset_vector);
+ reset_vector();
+}
+
+
+/****************************************************************
+ * Threads
+ ****************************************************************/
+
+// Thread info - stored at bottom of each thread stack - don't change
+// without also updating the inline assembler below.
+struct thread_info {
+ void *stackpos;
+ struct hlist_node node;
+};
+struct thread_info MainThread VARFSEG = {
+ NULL, { &MainThread.node, &MainThread.node.next }
+};
+#define THREADSTACKSIZE 4096
+
+// Check if any threads are running.
+static int
+have_threads(void)
+{
+ return (CONFIG_THREADS
+ && GET_FLATPTR(MainThread.node.next) != &MainThread.node);
+}
+
+// Return the 'struct thread_info' for the currently running thread.
+struct thread_info *
+getCurThread(void)
+{
+ u32 esp = getesp();
+ if (esp <= MAIN_STACK_MAX)
+ return &MainThread;
+ return (void*)ALIGN_DOWN(esp, THREADSTACKSIZE);
+}
+
+static u8 CanInterrupt, ThreadControl;
+
+// Initialize the support for internal threads.
+void
+thread_setup(void)
+{
+ CanInterrupt = 1;
+ call16_override(1);
+ if (! CONFIG_THREADS)
+ return;
+ ThreadControl = romfile_loadint("etc/threads", 1);
+}
+
+// Should hardware initialization threads run during optionrom execution.
+int
+threads_during_optionroms(void)
+{
+ return CONFIG_THREADS && CONFIG_RTC_TIMER && ThreadControl == 2 && in_post();
+}
+
+// Switch to next thread stack.
+static void
+switch_next(struct thread_info *cur)
+{
+ struct thread_info *next = container_of(
+ cur->node.next, struct thread_info, node);
+ if (cur == next)
+ // Nothing to do.
+ return;
+ asm volatile(
+ " pushl $1f\n" // store return pc
+ " pushl %%ebp\n" // backup %ebp
+ " movl %%esp, (%%eax)\n" // cur->stackpos = %esp
+ " movl (%%ecx), %%esp\n" // %esp = next->stackpos
+ " popl %%ebp\n" // restore %ebp
+ " retl\n" // restore pc
+ "1:\n"
+ : "+a"(cur), "+c"(next)
+ :
+ : "ebx", "edx", "esi", "edi", "cc", "memory");
+}
+
+// Last thing called from a thread (called on MainThread stack).
+static void
+__end_thread(struct thread_info *old)
+{
+ hlist_del(&old->node);
+ dprintf(DEBUG_thread, "\\%08x/ End thread\n", (u32)old);
+ free(old);
+ if (!have_threads())
+ dprintf(1, "All threads complete.\n");
+}
+
+void VISIBLE16 check_irqs(void);
+
+// Create a new thread and start executing 'func' in it.
+void
+run_thread(void (*func)(void*), void *data)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_THREADS || ! ThreadControl)
+ goto fail;
+ struct thread_info *thread;
+ thread = memalign_tmphigh(THREADSTACKSIZE, THREADSTACKSIZE);
+ if (!thread)
+ goto fail;
+
+ dprintf(DEBUG_thread, "/%08x\\ Start thread\n", (u32)thread);
+ thread->stackpos = (void*)thread + THREADSTACKSIZE;
+ struct thread_info *cur = getCurThread();
+ struct thread_info *edx = cur;
+ hlist_add_after(&thread->node, &cur->node);
+ asm volatile(
+ // Start thread
+ " pushl $1f\n" // store return pc
+ " pushl %%ebp\n" // backup %ebp
+ " movl %%esp, (%%edx)\n" // cur->stackpos = %esp
+ " movl (%%ebx), %%esp\n" // %esp = thread->stackpos
+ " calll *%%ecx\n" // Call func
+
+ // End thread
+ " movl %%ebx, %%eax\n" // %eax = thread
+ " movl 4(%%ebx), %%ebx\n" // %ebx = thread->node.next
+ " movl (%5), %%esp\n" // %esp = MainThread.stackpos
+ " calll %4\n" // call __end_thread(thread)
+ " movl -4(%%ebx), %%esp\n" // %esp = next->stackpos
+ " popl %%ebp\n" // restore %ebp
+ " retl\n" // restore pc
+ "1:\n"
+ : "+a"(data), "+c"(func), "+b"(thread), "+d"(edx)
+ : "m"(*(u8*)__end_thread), "m"(MainThread)
+ : "esi", "edi", "cc", "memory");
+ if (cur == &MainThread)
+ // Permit irqs to fire
+ check_irqs();
+ return;
+
+fail:
+ func(data);
+}
+
+
+/****************************************************************
+ * Thread helpers
+ ****************************************************************/
+
+// Low-level irq enable.
+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()) {
+ stack_hop_back(check_irqs, 0, 0);
+ return;
+ }
+ if (MODE16)
+ clock_poll_irq();
+ asm volatile("sti ; nop ; rep ; nop ; cli ; cld" : : :"memory");
+}
+
+// Briefly permit irqs to occur.
+void
+yield(void)
+{
+ if (MODESEGMENT || !CONFIG_THREADS) {
+ check_irqs();
+ return;
+ }
+ struct thread_info *cur = getCurThread();
+ // Switch to the next thread
+ switch_next(cur);
+ if (cur == &MainThread)
+ // Permit irqs to fire
+ check_irqs();
+}
+
+void VISIBLE16
+wait_irq(void)
+{
+ if (need_hop_back()) {
+ stack_hop_back(wait_irq, 0, 0);
+ return;
+ }
+ asm volatile("sti ; hlt ; cli ; cld": : :"memory");
+}
+
+// Wait for next irq to occur.
+void
+yield_toirq(void)
+{
+ if (!CONFIG_HARDWARE_IRQ
+ || (!MODESEGMENT && (have_threads() || !CanInterrupt))) {
+ // Threads still active or irqs not available - do a yield instead.
+ yield();
+ return;
+ }
+ wait_irq();
+}
+
+// Wait for all threads (other than the main thread) to complete.
+void
+wait_threads(void)
+{
+ ASSERT32FLAT();
+ while (have_threads())
+ yield();
+}
+
+void
+mutex_lock(struct mutex_s *mutex)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_THREADS)
+ return;
+ while (mutex->isLocked)
+ yield();
+ mutex->isLocked = 1;
+}
+
+void
+mutex_unlock(struct mutex_s *mutex)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_THREADS)
+ return;
+ mutex->isLocked = 0;
+}
+
+
+/****************************************************************
+ * Thread preemption
+ ****************************************************************/
+
+int CanPreempt VARFSEG;
+static u32 PreemptCount;
+
+// Turn on RTC irqs and arrange for them to check the 32bit threads.
+void
+start_preempt(void)
+{
+ if (! threads_during_optionroms())
+ return;
+ CanPreempt = 1;
+ PreemptCount = 0;
+ rtc_use();
+}
+
+// Turn off RTC irqs / stop checking for thread execution.
+void
+finish_preempt(void)
+{
+ if (! threads_during_optionroms()) {
+ yield();
+ return;
+ }
+ CanPreempt = 0;
+ rtc_release();
+ dprintf(9, "Done preempt - %d checks\n", PreemptCount);
+ yield();
+}
+
+// Check if preemption is on, and wait for it to complete if so.
+int
+wait_preempt(void)
+{
+ if (MODESEGMENT || !CONFIG_THREADS || !CanPreempt
+ || getesp() < MAIN_STACK_MAX)
+ return 0;
+ while (CanPreempt)
+ yield();
+ return 1;
+}
+
+// Try to execute 32bit threads.
+void VISIBLE32INIT
+yield_preempt(void)
+{
+ PreemptCount++;
+ switch_next(&MainThread);
+}
+
+// 16bit code that checks if threads are pending and executes them if so.
+void
+check_preempt(void)
+{
+ if (CONFIG_THREADS && GET_GLOBAL(CanPreempt) && have_threads())
+ call32(yield_preempt, 0, 0);
+}
+
+
+/****************************************************************
+ * call32 helper
+ ****************************************************************/
+
+struct call32_params_s {
+ void *func;
+ u32 eax, edx, ecx;
+};
+
+u32 VISIBLE32FLAT
+call32_params_helper(struct call32_params_s *params)
+{
+ return ((u32 (*)(u32, u32, u32))params->func)(
+ params->eax, params->edx, params->ecx);
+}
+
+u32
+__call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret)
+{
+ ASSERT16();
+ struct call32_params_s params = {func, eax, edx, ecx};
+ return call32(call32_params_helper, MAKE_FLATPTR(GET_SEG(SS), &params)
+ , errret);
+}
diff --git a/roms/seabios-hppa/src/stacks.h b/roms/seabios-hppa/src/stacks.h
new file mode 100644
index 000000000..518bd83a4
--- /dev/null
+++ b/roms/seabios-hppa/src/stacks.h
@@ -0,0 +1,81 @@
+// Misc function and variable declarations.
+#ifndef __STACKS_H
+#define __STACKS_H
+
+#include "autoconf.h" // CONFIG_*
+#include "types.h" // u32
+
+#define CALL32SMM_CMDID 0xb5
+#define CALL32SMM_ENTERID 0x1234
+#define CALL32SMM_RETURNID 0x5678
+
+// stacks.c
+extern int HaveSmmCall32;
+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);
+#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);
+#if CONFIG_X86
+void __call16_int(struct bregs *callregs, u16 offset);
+#define call16_int(nr, callregs) do { \
+ extern void irq_trampoline_ ##nr (void); \
+ __call16_int((callregs), (u32)&irq_trampoline_ ##nr ); \
+ } while (0)
+#elif CONFIG_PARISC
+#define call16_int(nr, callregs) do {} while(0)
+#endif
+void reset(void);
+extern struct thread_info MainThread;
+struct thread_info *getCurThread(void);
+void yield_toirq(void);
+#if CONFIG_THREADS
+int threads_during_optionroms(void);
+void yield(void);
+void thread_setup(void);
+void run_thread(void (*func)(void*), void *data);
+void wait_threads(void);
+#else
+#define threads_during_optionroms() (0)
+#define yield() while (0)
+#define thread_setup() while (0)
+#define run_thread(func,data) func(data)
+#define wait_threads() while (0)
+#endif
+struct mutex_s { u32 isLocked; };
+void mutex_lock(struct mutex_s *mutex);
+void mutex_unlock(struct mutex_s *mutex);
+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);
+#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
+
+// Check if a call to stack_hop_back is needed.
+static inline int
+need_hop_back(void)
+{
+ return !MODESEGMENT || on_extra_stack();
+}
+
+#endif // stacks.h
diff --git a/roms/seabios-hppa/src/std/LegacyBios.h b/roms/seabios-hppa/src/std/LegacyBios.h
new file mode 100644
index 000000000..5170c3786
--- /dev/null
+++ b/roms/seabios-hppa/src/std/LegacyBios.h
@@ -0,0 +1,985 @@
+/** @file
+ The EFI Legacy BIOS Protocol is used to abstract legacy Option ROM usage
+ under EFI and Legacy OS boot. This file also includes all the related
+ COMPATIBILIY16 structures and defintions.
+
+ Note: The names for EFI_IA32_REGISTER_SET elements were picked to follow
+ well known naming conventions.
+
+ Thunk is the code that switches from 32-bit protected environment into the 16-bit real-mode
+ environment. Reverse thunk is the code that does the opposite.
+
+Copyright (c) 2007 - 2010, 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.
+
+ @par Revision Reference:
+ This protocol is defined in Framework for EFI Compatibility Support Module spec
+ Version 0.97.
+
+**/
+
+#ifndef _EFI_LEGACY_BIOS_H_
+#define _EFI_LEGACY_BIOS_H_
+
+///
+///
+///
+#pragma pack(1)
+
+typedef UINT8 SERIAL_MODE;
+typedef UINT8 PARALLEL_MODE;
+
+#define EFI_COMPATIBILITY16_TABLE_SIGNATURE SIGNATURE_32 ('I', 'F', 'E', '$')
+
+///
+/// There is a table located within the traditional BIOS in either the 0xF000:xxxx or 0xE000:xxxx
+/// physical address range. It is located on a 16-byte boundary and provides the physical address of the
+/// entry point for the Compatibility16 functions. These functions provide the platform-specific
+/// information that is required by the generic EfiCompatibility code. The functions are invoked via
+/// thunking by using EFI_LEGACY_BIOS_PROTOCOL.FarCall86() with the 32-bit physical
+/// entry point.
+///
+typedef struct {
+ ///
+ /// The string "$EFI" denotes the start of the EfiCompatibility table. Byte 0 is "I," byte
+ /// 1 is "F," byte 2 is "E," and byte 3 is "$" and is normally accessed as a DWORD or UINT32.
+ ///
+ UINT32 Signature;
+
+ ///
+ /// The value required such that byte checksum of TableLength equals zero.
+ ///
+ UINT8 TableChecksum;
+
+ ///
+ /// The length of this table.
+ ///
+ UINT8 TableLength;
+
+ ///
+ /// The major EFI revision for which this table was generated.
+ ///
+ UINT8 EfiMajorRevision;
+
+ ///
+ /// The minor EFI revision for which this table was generated.
+ ///
+ UINT8 EfiMinorRevision;
+
+ ///
+ /// The major revision of this table.
+ ///
+ UINT8 TableMajorRevision;
+
+ ///
+ /// The minor revision of this table.
+ ///
+ UINT8 TableMinorRevision;
+
+ ///
+ /// Reserved for future usage.
+ ///
+ UINT16 Reserved;
+
+ ///
+ /// The segment of the entry point within the traditional BIOS for Compatibility16 functions.
+ ///
+ UINT16 Compatibility16CallSegment;
+
+ ///
+ /// The offset of the entry point within the traditional BIOS for Compatibility16 functions.
+ ///
+ UINT16 Compatibility16CallOffset;
+
+ ///
+ /// The segment of the entry point within the traditional BIOS for EfiCompatibility
+ /// to invoke the PnP installation check.
+ ///
+ UINT16 PnPInstallationCheckSegment;
+
+ ///
+ /// The Offset of the entry point within the traditional BIOS for EfiCompatibility
+ /// to invoke the PnP installation check.
+ ///
+ UINT16 PnPInstallationCheckOffset;
+
+ ///
+ /// EFI system resources table. Type EFI_SYSTEM_TABLE is defined in the IntelPlatform
+ ///Innovation Framework for EFI Driver Execution Environment Core Interface Specification (DXE CIS).
+ ///
+ UINT32 EfiSystemTable;
+
+ ///
+ /// The address of an OEM-provided identifier string. The string is null terminated.
+ ///
+ UINT32 OemIdStringPointer;
+
+ ///
+ /// The 32-bit physical address where ACPI RSD PTR is stored within the traditional
+ /// BIOS. The remained of the ACPI tables are located at their EFI addresses. The size
+ /// reserved is the maximum for ACPI 2.0. The EfiCompatibility will fill in the ACPI
+ /// RSD PTR with either the ACPI 1.0b or 2.0 values.
+ ///
+ UINT32 AcpiRsdPtrPointer;
+
+ ///
+ /// The OEM revision number. Usage is undefined but provided for OEM module usage.
+ ///
+ UINT16 OemRevision;
+
+ ///
+ /// The 32-bit physical address where INT15 E820 data is stored within the traditional
+ /// BIOS. The EfiCompatibility code will fill in the E820Pointer value and copy the
+ /// data to the indicated area.
+ ///
+ UINT32 E820Pointer;
+
+ ///
+ /// The length of the E820 data and is filled in by the EfiCompatibility code.
+ ///
+ UINT32 E820Length;
+
+ ///
+ /// The 32-bit physical address where the $PIR table is stored in the traditional BIOS.
+ /// The EfiCompatibility code will fill in the IrqRoutingTablePointer value and
+ /// copy the data to the indicated area.
+ ///
+ UINT32 IrqRoutingTablePointer;
+
+ ///
+ /// The length of the $PIR table and is filled in by the EfiCompatibility code.
+ ///
+ UINT32 IrqRoutingTableLength;
+
+ ///
+ /// The 32-bit physical address where the MP table is stored in the traditional BIOS.
+ /// The EfiCompatibility code will fill in the MpTablePtr value and copy the data
+ /// to the indicated area.
+ ///
+ UINT32 MpTablePtr;
+
+ ///
+ /// The length of the MP table and is filled in by the EfiCompatibility code.
+ ///
+ UINT32 MpTableLength;
+
+ ///
+ /// The segment of the OEM-specific INT table/code.
+ ///
+ UINT16 OemIntSegment;
+
+ ///
+ /// The offset of the OEM-specific INT table/code.
+ ///
+ UINT16 OemIntOffset;
+
+ ///
+ /// The segment of the OEM-specific 32-bit table/code.
+ ///
+ UINT16 Oem32Segment;
+
+ ///
+ /// The offset of the OEM-specific 32-bit table/code.
+ ///
+ UINT16 Oem32Offset;
+
+ ///
+ /// The segment of the OEM-specific 16-bit table/code.
+ ///
+ UINT16 Oem16Segment;
+
+ ///
+ /// The offset of the OEM-specific 16-bit table/code.
+ ///
+ UINT16 Oem16Offset;
+
+ ///
+ /// The segment of the TPM binary passed to 16-bit CSM.
+ ///
+ UINT16 TpmSegment;
+
+ ///
+ /// The offset of the TPM binary passed to 16-bit CSM.
+ ///
+ UINT16 TpmOffset;
+
+ ///
+ /// A pointer to a string identifying the independent BIOS vendor.
+ ///
+ UINT32 IbvPointer;
+
+ ///
+ /// This field is NULL for all systems not supporting PCI Express. This field is the base
+ /// value of the start of the PCI Express memory-mapped configuration registers and
+ /// must be filled in prior to EfiCompatibility code issuing the Compatibility16 function
+ /// Compatibility16InitializeYourself().
+ /// Compatibility16InitializeYourself() is defined in Compatability16
+ /// Functions.
+ ///
+ UINT32 PciExpressBase;
+
+ ///
+ /// Maximum PCI bus number assigned.
+ ///
+ UINT8 LastPciBus;
+
+ ///
+ /// Start address of UMB RAM
+ ///
+ UINT32 UmaAddress;
+
+ ///
+ /// Size of UMB RAM
+ ///
+ UINT32 UmaSize;
+
+ ///
+ /// Start address of persistent allocation in high (>1MiB) memory
+ ///
+ UINT32 HiPermanentMemoryAddress;
+
+ ///
+ /// Size of persistent allocation in high (>1MiB) memory
+ ///
+ UINT32 HiPermanentMemorySize;
+} EFI_COMPATIBILITY16_TABLE;
+
+///
+/// Functions provided by the CSM binary which communicate between the EfiCompatibility
+/// and Compatability16 code.
+///
+/// Inconsistent with the specification here:
+/// The member's name started with "Compatibility16" [defined in Intel Framework
+/// Compatibility Support Module Specification / 0.97 version]
+/// has been changed to "Legacy16" since keeping backward compatible.
+///
+typedef enum {
+ ///
+ /// Causes the Compatibility16 code to do any internal initialization required.
+ /// Input:
+ /// AX = Compatibility16InitializeYourself
+ /// ES:BX = Pointer to EFI_TO_COMPATIBILITY16_INIT_TABLE
+ /// Return:
+ /// AX = Return Status codes
+ ///
+ Legacy16InitializeYourself = 0x0000,
+
+ ///
+ /// Causes the Compatibility16 BIOS to perform any drive number translations to match the boot sequence.
+ /// Input:
+ /// AX = Compatibility16UpdateBbs
+ /// ES:BX = Pointer to EFI_TO_COMPATIBILITY16_BOOT_TABLE
+ /// Return:
+ /// AX = Returned status codes
+ ///
+ Legacy16UpdateBbs = 0x0001,
+
+ ///
+ /// Allows the Compatibility16 code to perform any final actions before booting. The Compatibility16
+ /// code is read/write.
+ /// Input:
+ /// AX = Compatibility16PrepareToBoot
+ /// ES:BX = Pointer to EFI_TO_COMPATIBILITY16_BOOT_TABLE structure
+ /// Return:
+ /// AX = Returned status codes
+ ///
+ Legacy16PrepareToBoot = 0x0002,
+
+ ///
+ /// Causes the Compatibility16 BIOS to boot. The Compatibility16 code is Read/Only.
+ /// Input:
+ /// AX = Compatibility16Boot
+ /// Output:
+ /// AX = Returned status codes
+ ///
+ Legacy16Boot = 0x0003,
+
+ ///
+ /// Allows the Compatibility16 code to get the last device from which a boot was attempted. This is
+ /// stored in CMOS and is the priority number of the last attempted boot device.
+ /// Input:
+ /// AX = Compatibility16RetrieveLastBootDevice
+ /// Output:
+ /// AX = Returned status codes
+ /// BX = Priority number of the boot device.
+ ///
+ Legacy16RetrieveLastBootDevice = 0x0004,
+
+ ///
+ /// Allows the Compatibility16 code rehook INT13, INT18, and/or INT19 after dispatching a legacy OpROM.
+ /// Input:
+ /// AX = Compatibility16DispatchOprom
+ /// ES:BX = Pointer to EFI_DISPATCH_OPROM_TABLE
+ /// Output:
+ /// AX = Returned status codes
+ /// BX = Number of non-BBS-compliant devices found. Equals 0 if BBS compliant.
+ ///
+ Legacy16DispatchOprom = 0x0005,
+
+ ///
+ /// Finds a free area in the 0xFxxxx or 0xExxxx region of the specified length and returns the address
+ /// of that region.
+ /// Input:
+ /// AX = Compatibility16GetTableAddress
+ /// BX = Allocation region
+ /// 00 = Allocate from either 0xE0000 or 0xF0000 64 KB blocks.
+ /// Bit 0 = 1 Allocate from 0xF0000 64 KB block
+ /// Bit 1 = 1 Allocate from 0xE0000 64 KB block
+ /// CX = Requested length in bytes.
+ /// DX = Required address alignment. Bit mapped. First non-zero bit from the right is the alignment.
+ /// Output:
+ /// AX = Returned status codes
+ /// DS:BX = Address of the region
+ ///
+ Legacy16GetTableAddress = 0x0006,
+
+ ///
+ /// Enables the EfiCompatibility module to do any nonstandard processing of keyboard LEDs or state.
+ /// Input:
+ /// AX = Compatibility16SetKeyboardLeds
+ /// CL = LED status.
+ /// Bit 0 Scroll Lock 0 = Off
+ /// Bit 1 NumLock
+ /// Bit 2 Caps Lock
+ /// Output:
+ /// AX = Returned status codes
+ ///
+ Legacy16SetKeyboardLeds = 0x0007,
+
+ ///
+ /// Enables the EfiCompatibility module to install an interrupt handler for PCI mass media devices that
+ /// do not have an OpROM associated with them. An example is SATA.
+ /// Input:
+ /// AX = Compatibility16InstallPciHandler
+ /// ES:BX = Pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure
+ /// Output:
+ /// AX = Returned status codes
+ ///
+ Legacy16InstallPciHandler = 0x0008
+} EFI_COMPATIBILITY_FUNCTIONS;
+
+
+///
+/// EFI_DISPATCH_OPROM_TABLE
+///
+typedef struct {
+ UINT16 PnPInstallationCheckSegment; ///< A pointer to the PnpInstallationCheck data structure.
+ UINT16 PnPInstallationCheckOffset; ///< A pointer to the PnpInstallationCheck data structure.
+ UINT16 OpromSegment; ///< The segment where the OpROM was placed. Offset is assumed to be 3.
+ UINT8 PciBus; ///< The PCI bus.
+ UINT8 PciDeviceFunction; ///< The PCI device * 0x08 | PCI function.
+ UINT8 NumberBbsEntries; ///< The number of valid BBS table entries upon entry and exit. The IBV code may
+ ///< increase this number, if BBS-compliant devices also hook INTs in order to force the
+ ///< OpROM BIOS Setup to be executed.
+ UINT32 BbsTablePointer; ///< A pointer to the BBS table.
+ UINT16 RuntimeSegment; ///< The segment where the OpROM can be relocated to. If this value is 0x0000, this
+ ///< means that the relocation of this run time code is not supported.
+ ///< Inconsistent with specification here:
+ ///< The member's name "OpromDestinationSegment" [defined in Intel Framework Compatibility Support Module Specification / 0.97 version]
+ ///< has been changed to "RuntimeSegment" since keeping backward compatible.
+
+} EFI_DISPATCH_OPROM_TABLE;
+
+///
+/// EFI_TO_COMPATIBILITY16_INIT_TABLE
+///
+typedef struct {
+ ///
+ /// Starting address of memory under 1 MB. The ending address is assumed to be 640 KB or 0x9FFFF.
+ ///
+ UINT32 BiosLessThan1MB;
+
+ ///
+ /// The starting address of the high memory block.
+ ///
+ UINT32 HiPmmMemory;
+
+ ///
+ /// The length of high memory block.
+ ///
+ UINT32 HiPmmMemorySizeInBytes;
+
+ ///
+ /// The segment of the reverse thunk call code.
+ ///
+ UINT16 ReverseThunkCallSegment;
+
+ ///
+ /// The offset of the reverse thunk call code.
+ ///
+ UINT16 ReverseThunkCallOffset;
+
+ ///
+ /// The number of E820 entries copied to the Compatibility16 BIOS.
+ ///
+ UINT32 NumberE820Entries;
+
+ ///
+ /// The amount of usable memory above 1 MB, e.g., E820 type 1 memory.
+ ///
+ UINT32 OsMemoryAbove1Mb;
+
+ ///
+ /// The start of thunk code in main memory. Memory cannot be used by BIOS or PMM.
+ ///
+ UINT32 ThunkStart;
+
+ ///
+ /// The size of the thunk code.
+ ///
+ UINT32 ThunkSizeInBytes;
+
+ ///
+ /// Starting address of memory under 1 MB.
+ ///
+ UINT32 LowPmmMemory;
+
+ ///
+ /// The length of low Memory block.
+ ///
+ UINT32 LowPmmMemorySizeInBytes;
+} EFI_TO_COMPATIBILITY16_INIT_TABLE;
+
+///
+/// DEVICE_PRODUCER_SERIAL.
+///
+typedef struct {
+ UINT16 Address; ///< I/O address assigned to the serial port.
+ UINT8 Irq; ///< IRQ assigned to the serial port.
+ SERIAL_MODE Mode; ///< Mode of serial port. Values are defined below.
+} DEVICE_PRODUCER_SERIAL;
+
+///
+/// DEVICE_PRODUCER_SERIAL's modes.
+///@{
+#define DEVICE_SERIAL_MODE_NORMAL 0x00
+#define DEVICE_SERIAL_MODE_IRDA 0x01
+#define DEVICE_SERIAL_MODE_ASK_IR 0x02
+#define DEVICE_SERIAL_MODE_DUPLEX_HALF 0x00
+#define DEVICE_SERIAL_MODE_DUPLEX_FULL 0x10
+///@)
+
+///
+/// DEVICE_PRODUCER_PARALLEL.
+///
+typedef struct {
+ UINT16 Address; ///< I/O address assigned to the parallel port.
+ UINT8 Irq; ///< IRQ assigned to the parallel port.
+ UINT8 Dma; ///< DMA assigned to the parallel port.
+ PARALLEL_MODE Mode; ///< Mode of the parallel port. Values are defined below.
+} DEVICE_PRODUCER_PARALLEL;
+
+///
+/// DEVICE_PRODUCER_PARALLEL's modes.
+///@{
+#define DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY 0x00
+#define DEVICE_PARALLEL_MODE_MODE_BIDIRECTIONAL 0x01
+#define DEVICE_PARALLEL_MODE_MODE_EPP 0x02
+#define DEVICE_PARALLEL_MODE_MODE_ECP 0x03
+///@}
+
+///
+/// DEVICE_PRODUCER_FLOPPY
+///
+typedef struct {
+ UINT16 Address; ///< I/O address assigned to the floppy.
+ UINT8 Irq; ///< IRQ assigned to the floppy.
+ UINT8 Dma; ///< DMA assigned to the floppy.
+ UINT8 NumberOfFloppy; ///< Number of floppies in the system.
+} DEVICE_PRODUCER_FLOPPY;
+
+///
+/// LEGACY_DEVICE_FLAGS
+///
+typedef struct {
+ UINT32 A20Kybd : 1; ///< A20 controller by keyboard controller.
+ UINT32 A20Port90 : 1; ///< A20 controlled by port 0x92.
+ UINT32 Reserved : 30; ///< Reserved for future usage.
+} LEGACY_DEVICE_FLAGS;
+
+///
+/// DEVICE_PRODUCER_DATA_HEADER
+///
+typedef struct {
+ DEVICE_PRODUCER_SERIAL Serial[4]; ///< Data for serial port x. Type DEVICE_PRODUCER_SERIAL is defined below.
+ DEVICE_PRODUCER_PARALLEL Parallel[3]; ///< Data for parallel port x. Type DEVICE_PRODUCER_PARALLEL is defined below.
+ DEVICE_PRODUCER_FLOPPY Floppy; ///< Data for floppy. Type DEVICE_PRODUCER_FLOPPY is defined below.
+ UINT8 MousePresent; ///< Flag to indicate if mouse is present.
+ LEGACY_DEVICE_FLAGS Flags; ///< Miscellaneous Boolean state information passed to CSM.
+} DEVICE_PRODUCER_DATA_HEADER;
+
+///
+/// ATAPI_IDENTIFY
+///
+typedef struct {
+ UINT16 Raw[256]; ///< Raw data from the IDE IdentifyDrive command.
+} ATAPI_IDENTIFY;
+
+///
+/// HDD_INFO
+///
+typedef struct {
+ ///
+ /// Status of IDE device. Values are defined below. There is one HDD_INFO structure
+ /// per IDE controller. The IdentifyDrive is per drive. Index 0 is master and index
+ /// 1 is slave.
+ ///
+ UINT16 Status;
+
+ ///
+ /// PCI bus of IDE controller.
+ ///
+ UINT32 Bus;
+
+ ///
+ /// PCI device of IDE controller.
+ ///
+ UINT32 Device;
+
+ ///
+ /// PCI function of IDE controller.
+ ///
+ UINT32 Function;
+
+ ///
+ /// Command ports base address.
+ ///
+ UINT16 CommandBaseAddress;
+
+ ///
+ /// Control ports base address.
+ ///
+ UINT16 ControlBaseAddress;
+
+ ///
+ /// Bus master address.
+ ///
+ UINT16 BusMasterAddress;
+
+ UINT8 HddIrq;
+
+ ///
+ /// Data that identifies the drive data; one per possible attached drive.
+ ///
+ ATAPI_IDENTIFY IdentifyDrive[2];
+} HDD_INFO;
+
+///
+/// HDD_INFO status bits
+///
+#define HDD_PRIMARY 0x01
+#define HDD_SECONDARY 0x02
+#define HDD_MASTER_ATAPI_CDROM 0x04
+#define HDD_SLAVE_ATAPI_CDROM 0x08
+#define HDD_MASTER_IDE 0x20
+#define HDD_SLAVE_IDE 0x40
+#define HDD_MASTER_ATAPI_ZIPDISK 0x10
+#define HDD_SLAVE_ATAPI_ZIPDISK 0x80
+
+///
+/// BBS_STATUS_FLAGS;\.
+///
+typedef struct {
+ UINT16 OldPosition : 4; ///< Prior priority.
+ UINT16 Reserved1 : 4; ///< Reserved for future use.
+ UINT16 Enabled : 1; ///< If 0, ignore this entry.
+ UINT16 Failed : 1; ///< 0 = Not known if boot failure occurred.
+ ///< 1 = Boot attempted failed.
+
+ ///
+ /// State of media present.
+ /// 00 = No bootable media is present in the device.
+ /// 01 = Unknown if a bootable media present.
+ /// 10 = Media is present and appears bootable.
+ /// 11 = Reserved.
+ ///
+ UINT16 MediaPresent : 2;
+ UINT16 Reserved2 : 4; ///< Reserved for future use.
+} BBS_STATUS_FLAGS;
+
+///
+/// BBS_TABLE, device type values & boot priority values.
+///
+typedef struct {
+ ///
+ /// The boot priority for this boot device. Values are defined below.
+ ///
+ UINT16 BootPriority;
+
+ ///
+ /// The PCI bus for this boot device.
+ ///
+ UINT32 Bus;
+
+ ///
+ /// The PCI device for this boot device.
+ ///
+ UINT32 Device;
+
+ ///
+ /// The PCI function for the boot device.
+ ///
+ UINT32 Function;
+
+ ///
+ /// The PCI class for this boot device.
+ ///
+ UINT8 Class;
+
+ ///
+ /// The PCI Subclass for this boot device.
+ ///
+ UINT8 SubClass;
+
+ ///
+ /// Segment:offset address of an ASCIIZ description string describing the manufacturer.
+ ///
+ UINT16 MfgStringOffset;
+
+ ///
+ /// Segment:offset address of an ASCIIZ description string describing the manufacturer.
+ ///
+ UINT16 MfgStringSegment;
+
+ ///
+ /// BBS device type. BBS device types are defined below.
+ ///
+ UINT16 DeviceType;
+
+ ///
+ /// Status of this boot device. Type BBS_STATUS_FLAGS is defined below.
+ ///
+ BBS_STATUS_FLAGS StatusFlags;
+
+ ///
+ /// Segment:Offset address of boot loader for IPL devices or install INT13 handler for
+ /// BCV devices.
+ ///
+ UINT16 BootHandlerOffset;
+
+ ///
+ /// Segment:Offset address of boot loader for IPL devices or install INT13 handler for
+ /// BCV devices.
+ ///
+ UINT16 BootHandlerSegment;
+
+ ///
+ /// Segment:offset address of an ASCIIZ description string describing this device.
+ ///
+ UINT16 DescStringOffset;
+
+ ///
+ /// Segment:offset address of an ASCIIZ description string describing this device.
+ ///
+ UINT16 DescStringSegment;
+
+ ///
+ /// Reserved.
+ ///
+ UINT32 InitPerReserved;
+
+ ///
+ /// The use of these fields is IBV dependent. They can be used to flag that an OpROM
+ /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI
+ /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup
+ ///
+ UINT32 AdditionalIrq13Handler;
+
+ ///
+ /// The use of these fields is IBV dependent. They can be used to flag that an OpROM
+ /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI
+ /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup
+ ///
+ UINT32 AdditionalIrq18Handler;
+
+ ///
+ /// The use of these fields is IBV dependent. They can be used to flag that an OpROM
+ /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI
+ /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup
+ ///
+ UINT32 AdditionalIrq19Handler;
+
+ ///
+ /// The use of these fields is IBV dependent. They can be used to flag that an OpROM
+ /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI
+ /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup
+ ///
+ UINT32 AdditionalIrq40Handler;
+ UINT8 AssignedDriveNumber;
+ UINT32 AdditionalIrq41Handler;
+ UINT32 AdditionalIrq46Handler;
+ UINT32 IBV1;
+ UINT32 IBV2;
+} BBS_TABLE;
+
+///
+/// BBS device type values
+///@{
+#define BBS_FLOPPY 0x01
+#define BBS_HARDDISK 0x02
+#define BBS_CDROM 0x03
+#define BBS_PCMCIA 0x04
+#define BBS_USB 0x05
+#define BBS_EMBED_NETWORK 0x06
+#define BBS_BEV_DEVICE 0x80
+#define BBS_UNKNOWN 0xff
+///@}
+
+///
+/// BBS boot priority values
+///@{
+#define BBS_DO_NOT_BOOT_FROM 0xFFFC
+#define BBS_LOWEST_PRIORITY 0xFFFD
+#define BBS_UNPRIORITIZED_ENTRY 0xFFFE
+#define BBS_IGNORE_ENTRY 0xFFFF
+///@}
+
+///
+/// SMM_ATTRIBUTES
+///
+typedef struct {
+ ///
+ /// Access mechanism used to generate the soft SMI. Defined types are below. The other
+ /// values are reserved for future usage.
+ ///
+ UINT16 Type : 3;
+
+ ///
+ /// The size of "port" in bits. Defined values are below.
+ ///
+ UINT16 PortGranularity : 3;
+
+ ///
+ /// The size of data in bits. Defined values are below.
+ ///
+ UINT16 DataGranularity : 3;
+
+ ///
+ /// Reserved for future use.
+ ///
+ UINT16 Reserved : 7;
+} SMM_ATTRIBUTES;
+
+///
+/// SMM_ATTRIBUTES type values.
+///@{
+#define STANDARD_IO 0x00
+#define STANDARD_MEMORY 0x01
+///@}
+
+///
+/// SMM_ATTRIBUTES port size constants.
+///@{
+#define PORT_SIZE_8 0x00
+#define PORT_SIZE_16 0x01
+#define PORT_SIZE_32 0x02
+#define PORT_SIZE_64 0x03
+///@}
+
+///
+/// SMM_ATTRIBUTES data size constants.
+///@{
+#define DATA_SIZE_8 0x00
+#define DATA_SIZE_16 0x01
+#define DATA_SIZE_32 0x02
+#define DATA_SIZE_64 0x03
+///@}
+
+///
+/// SMM_FUNCTION & relating constants.
+///
+typedef struct {
+ UINT16 Function : 15;
+ UINT16 Owner : 1;
+} SMM_FUNCTION;
+
+///
+/// SMM_FUNCTION Function constants.
+///@{
+#define INT15_D042 0x0000
+#define GET_USB_BOOT_INFO 0x0001
+#define DMI_PNP_50_57 0x0002
+///@}
+
+///
+/// SMM_FUNCTION Owner constants.
+///@{
+#define STANDARD_OWNER 0x0
+#define OEM_OWNER 0x1
+///@}
+
+///
+/// This structure assumes both port and data sizes are 1. SmmAttribute must be
+/// properly to reflect that assumption.
+///
+typedef struct {
+ ///
+ /// Describes the access mechanism, SmmPort, and SmmData sizes. Type
+ /// SMM_ATTRIBUTES is defined below.
+ ///
+ SMM_ATTRIBUTES SmmAttributes;
+
+ ///
+ /// Function Soft SMI is to perform. Type SMM_FUNCTION is defined below.
+ ///
+ SMM_FUNCTION SmmFunction;
+
+ ///
+ /// SmmPort size depends upon SmmAttributes and ranges from2 bytes to 16 bytes.
+ ///
+ UINT8 SmmPort;
+
+ ///
+ /// SmmData size depends upon SmmAttributes and ranges from2 bytes to 16 bytes.
+ ///
+ UINT8 SmmData;
+} SMM_ENTRY;
+
+///
+/// SMM_TABLE
+///
+typedef struct {
+ UINT16 NumSmmEntries; ///< Number of entries represented by SmmEntry.
+ SMM_ENTRY SmmEntry; ///< One entry per function. Type SMM_ENTRY is defined below.
+} SMM_TABLE;
+
+///
+/// UDC_ATTRIBUTES
+///
+typedef struct {
+ ///
+ /// This bit set indicates that the ServiceAreaData is valid.
+ ///
+ UINT8 DirectoryServiceValidity : 1;
+
+ ///
+ /// This bit set indicates to use the Reserve Area Boot Code Address (RACBA) only if
+ /// DirectoryServiceValidity is 0.
+ ///
+ UINT8 RabcaUsedFlag : 1;
+
+ ///
+ /// This bit set indicates to execute hard disk diagnostics.
+ ///
+ UINT8 ExecuteHddDiagnosticsFlag : 1;
+
+ ///
+ /// Reserved for future use. Set to 0.
+ ///
+ UINT8 Reserved : 5;
+} UDC_ATTRIBUTES;
+
+///
+/// UD_TABLE
+///
+typedef struct {
+ ///
+ /// This field contains the bit-mapped attributes of the PARTIES information. Type
+ /// UDC_ATTRIBUTES is defined below.
+ ///
+ UDC_ATTRIBUTES Attributes;
+
+ ///
+ /// This field contains the zero-based device on which the selected
+ /// ServiceDataArea is present. It is 0 for master and 1 for the slave device.
+ ///
+ UINT8 DeviceNumber;
+
+ ///
+ /// This field contains the zero-based index into the BbsTable for the parent device.
+ /// This index allows the user to reference the parent device information such as PCI
+ /// bus, device function.
+ ///
+ UINT8 BbsTableEntryNumberForParentDevice;
+
+ ///
+ /// This field contains the zero-based index into the BbsTable for the boot entry.
+ ///
+ UINT8 BbsTableEntryNumberForBoot;
+
+ ///
+ /// This field contains the zero-based index into the BbsTable for the HDD diagnostics entry.
+ ///
+ UINT8 BbsTableEntryNumberForHddDiag;
+
+ ///
+ /// The raw Beer data.
+ ///
+ UINT8 BeerData[128];
+
+ ///
+ /// The raw data of selected service area.
+ ///
+ UINT8 ServiceAreaData[64];
+} UD_TABLE;
+
+#define EFI_TO_LEGACY_MAJOR_VERSION 0x02
+#define EFI_TO_LEGACY_MINOR_VERSION 0x00
+#define MAX_IDE_CONTROLLER 8
+
+///
+/// EFI_TO_COMPATIBILITY16_BOOT_TABLE
+///
+typedef struct {
+ UINT16 MajorVersion; ///< The EfiCompatibility major version number.
+ UINT16 MinorVersion; ///< The EfiCompatibility minor version number.
+ UINT32 AcpiTable; ///< The location of the RSDT ACPI table. < 4G range.
+ UINT32 SmbiosTable; ///< The location of the SMBIOS table in EFI memory. < 4G range.
+ UINT32 SmbiosTableLength;
+ //
+ // Legacy SIO state
+ //
+ DEVICE_PRODUCER_DATA_HEADER SioData; ///< Standard traditional device information.
+ UINT16 DevicePathType; ///< The default boot type.
+ UINT16 PciIrqMask; ///< Mask of which IRQs have been assigned to PCI.
+ UINT32 NumberE820Entries; ///< Number of E820 entries. The number can change from the
+ ///< Compatibility16InitializeYourself() function.
+ //
+ // Controller & Drive Identify[2] per controller information
+ //
+ HDD_INFO HddInfo[MAX_IDE_CONTROLLER]; ///< Hard disk drive information, including raw Identify Drive data.
+ UINT32 NumberBbsEntries; ///< Number of entries in the BBS table
+ UINT32 BbsTable; ///< A pointer to the BBS table. Type BBS_TABLE is defined below.
+ UINT32 SmmTable; ///< A pointer to the SMM table. Type SMM_TABLE is defined below.
+ UINT32 OsMemoryAbove1Mb; ///< The amount of usable memory above 1 MB, i.e. E820 type 1 memory. This value can
+ ///< differ from the value in EFI_TO_COMPATIBILITY16_INIT_TABLE as more
+ ///< memory may have been discovered.
+ UINT32 UnconventionalDeviceTable; ///< Information to boot off an unconventional device like a PARTIES partition. Type
+ ///< UD_TABLE is defined below.
+} EFI_TO_COMPATIBILITY16_BOOT_TABLE;
+
+///
+/// EFI_LEGACY_INSTALL_PCI_HANDLER
+///
+typedef struct {
+ UINT8 PciBus; ///< The PCI bus of the device.
+ UINT8 PciDeviceFun; ///< The PCI device in bits 7:3 and function in bits 2:0.
+ UINT8 PciSegment; ///< The PCI segment of the device.
+ UINT8 PciClass; ///< The PCI class code of the device.
+ UINT8 PciSubclass; ///< The PCI subclass code of the device.
+ UINT8 PciInterface; ///< The PCI interface code of the device.
+ //
+ // Primary section
+ //
+ UINT8 PrimaryIrq; ///< The primary device IRQ.
+ UINT8 PrimaryReserved; ///< Reserved.
+ UINT16 PrimaryControl; ///< The primary device control I/O base.
+ UINT16 PrimaryBase; ///< The primary device I/O base.
+ UINT16 PrimaryBusMaster; ///< The primary device bus master I/O base.
+ //
+ // Secondary Section
+ //
+ UINT8 SecondaryIrq; ///< The secondary device IRQ.
+ UINT8 SecondaryReserved; ///< Reserved.
+ UINT16 SecondaryControl; ///< The secondary device control I/O base.
+ UINT16 SecondaryBase; ///< The secondary device I/O base.
+ UINT16 SecondaryBusMaster; ///< The secondary device bus master I/O base.
+} EFI_LEGACY_INSTALL_PCI_HANDLER;
+
+#endif
diff --git a/roms/seabios-hppa/src/std/acpi.h b/roms/seabios-hppa/src/std/acpi.h
new file mode 100644
index 000000000..81c22757f
--- /dev/null
+++ b/roms/seabios-hppa/src/std/acpi.h
@@ -0,0 +1,334 @@
+#ifndef __ACPI_H
+#define __ACPI_H
+
+#include "types.h" // u32
+
+/*
+ * ACPI 2.0 Generic Address Space definition.
+ */
+struct acpi_20_generic_address {
+ u8 address_space_id;
+ u8 register_bit_width;
+ u8 register_bit_offset;
+ u8 reserved;
+ u64 address;
+} PACKED;
+
+#define RSDP_SIGNATURE 0x2052545020445352LL // "RSD PTR "
+
+struct rsdp_descriptor { /* Root System Descriptor Pointer */
+ u64 signature; /* ACPI signature, contains "RSD PTR " */
+ u8 checksum; /* To make sum of struct == 0 */
+ u8 oem_id [6]; /* OEM identification */
+ u8 revision; /* Must be 0 for 1.0, 2 for 2.0 */
+ u32 rsdt_physical_address; /* 32-bit physical address of RSDT */
+ u32 length; /* XSDT Length in bytes including hdr */
+ u64 xsdt_physical_address; /* 64-bit physical address of XSDT */
+ u8 extended_checksum; /* Checksum of entire table */
+ u8 reserved [3]; /* Reserved field must be 0 */
+};
+
+/* Table structure from Linux kernel (the ACPI tables are under the
+ BSD license) */
+
+#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \
+ u32 signature; /* ACPI signature (4 ASCII characters) */ \
+ u32 length; /* Length of table, in bytes, including header */ \
+ u8 revision; /* ACPI Specification minor version # */ \
+ u8 checksum; /* To make sum of entire table == 0 */ \
+ u8 oem_id [6]; /* OEM identification */ \
+ u8 oem_table_id [8]; /* OEM table identification */ \
+ u32 oem_revision; /* OEM revision number */ \
+ u8 asl_compiler_id [4]; /* ASL compiler vendor ID */ \
+ u32 asl_compiler_revision; /* ASL compiler revision number */
+
+/*
+ * Fixed ACPI Description Table Fixed Feature Flags
+ */
+#define ACPI_FADT_F_WBINVD (1 << 0)
+#define ACPI_FADT_F_WBINVD_FLUSH (1 << 1)
+#define ACPI_FADT_F_PROC_C1 (1 << 2)
+#define ACPI_FADT_F_P_LVL2_UP (1 << 3)
+#define ACPI_FADT_F_PWR_BUTTON (1 << 4)
+#define ACPI_FADT_F_SLP_BUTTON (1 << 5)
+#define ACPI_FADT_F_FIX_RTC (1 << 6)
+#define ACPI_FADT_F_RTC_S4 (1 << 7)
+#define ACPI_FADT_F_TMR_VAL_EXT (1 << 8)
+#define ACPI_FADT_F_DCK_CAP (1 << 9)
+#define ACPI_FADT_F_RESET_REG_SUP (1 << 10)
+#define ACPI_FADT_F_SEALED_CASE (1 << 11)
+#define ACPI_FADT_F_HEADLESS (1 << 12)
+#define ACPI_FADT_F_CPU_SW_SLP (1 << 13)
+#define ACPI_FADT_F_PCI_EXP_WAK (1 << 14)
+#define ACPI_FADT_F_USE_PLATFORM_CLOCK (1 << 15)
+#define ACPI_FADT_F_S4_RTC_STS_VALID (1 << 16)
+#define ACPI_FADT_F_REMOTE_POWER_ON_CAPABLE (1 << 17)
+#define ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL (1 << 18)
+#define ACPI_FADT_F_FORCE_APIC_PHYSICAL_DESTINATION_MODE (1 << 19)
+#define ACPI_FADT_F_HW_REDUCED_ACPI (1 << 20)
+#define ACPI_FADT_F_LOW_POWER_S0_IDLE_CAPABLE (1 << 21)
+
+/*
+ * ACPI 1.0 Fixed ACPI Description Table (FADT)
+ */
+#define FACP_SIGNATURE 0x50434146 // FACP
+struct fadt_descriptor_rev1
+{
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
+ u32 firmware_ctrl; /* Physical address of FACS */
+ u32 dsdt; /* Physical address of DSDT */
+ u8 model; /* System Interrupt Model */
+ u8 reserved1; /* Reserved */
+ u16 sci_int; /* System vector of SCI interrupt */
+ u32 smi_cmd; /* Port address of SMI command port */
+ u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */
+ u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */
+ u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */
+ u8 reserved2; /* Reserved - must be zero */
+ u32 pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */
+ u32 pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */
+ u32 pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
+ u32 pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
+ u32 pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
+ u32 pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
+ u32 gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */
+ u32 gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */
+ u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */
+ u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */
+ u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
+ u8 pm_tmr_len; /* Byte Length of ports at pm_tm_blk */
+ u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */
+ u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
+ u8 gpe1_base; /* Offset in gpe model where gpe1 events start */
+ u8 reserved3; /* Reserved */
+ u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */
+ u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */
+ u16 flush_size; /* Size of area read to flush caches */
+ u16 flush_stride; /* Stride used in flushing caches */
+ u8 duty_offset; /* Bit location of duty cycle field in p_cnt reg */
+ u8 duty_width; /* Bit width of duty cycle field in p_cnt reg */
+ u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */
+ u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */
+ u8 century; /* Index to century in RTC CMOS RAM */
+ u8 reserved4; /* Reserved */
+ u8 reserved4a; /* Reserved */
+ u8 reserved4b; /* Reserved */
+ u32 flags;
+} PACKED;
+
+struct acpi_table_header /* ACPI common table header */
+{
+ ACPI_TABLE_HEADER_DEF
+} PACKED;
+
+/*
+ * ACPI 1.0 Root System Description Table (RSDT)
+ */
+#define RSDT_SIGNATURE 0x54445352 // RSDT
+struct rsdt_descriptor_rev1
+{
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
+ u32 table_offset_entry[0]; /* Array of pointers to other */
+ /* ACPI tables */
+} PACKED;
+
+/*
+ * ACPI 2.0 eXtended System Description Table (XSDT)
+ */
+#define XSDT_SIGNATURE 0x54445358 // XSDT
+struct xsdt_descriptor_rev2
+{
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
+ u64 table_offset_entry[0]; /* Array of pointers to other */
+ /* ACPI tables */
+} PACKED;
+
+/*
+ * ACPI 1.0 Firmware ACPI Control Structure (FACS)
+ */
+#define FACS_SIGNATURE 0x53434146 // FACS
+struct facs_descriptor_rev1
+{
+ u32 signature; /* ACPI Signature */
+ u32 length; /* Length of structure, in bytes */
+ u32 hardware_signature; /* Hardware configuration signature */
+ u32 firmware_waking_vector; /* ACPI OS waking vector */
+ u32 global_lock; /* Global Lock */
+ u32 flags;
+ u8 resverved3 [40]; /* Reserved - must be zero */
+} PACKED;
+
+/*
+ * Differentiated System Description Table (DSDT)
+ */
+#define DSDT_SIGNATURE 0x54445344 // DSDT
+
+/*
+ * MADT values and structures
+ */
+
+/* Values for MADT PCATCompat */
+
+#define DUAL_PIC 0
+#define MULTIPLE_APIC 1
+
+/* Master MADT */
+
+#define APIC_SIGNATURE 0x43495041 // APIC
+struct multiple_apic_table
+{
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
+ u32 local_apic_address; /* Physical address of local APIC */
+ u32 flags;
+} PACKED;
+
+/* Values for Type in APIC sub-headers */
+
+#define APIC_PROCESSOR 0
+#define APIC_IO 1
+#define APIC_XRUPT_OVERRIDE 2
+#define APIC_NMI 3
+#define APIC_LOCAL_NMI 4
+#define APIC_ADDRESS_OVERRIDE 5
+#define APIC_IO_SAPIC 6
+#define APIC_LOCAL_SAPIC 7
+#define APIC_XRUPT_SOURCE 8
+#define APIC_RESERVED 9 /* 9 and greater are reserved */
+
+/*
+ * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
+ */
+#define ACPI_SUB_HEADER_DEF /* Common ACPI sub-structure header */\
+ u8 type; \
+ u8 length;
+
+/* Sub-structures for MADT */
+
+struct madt_processor_apic
+{
+ ACPI_SUB_HEADER_DEF
+ u8 processor_id; /* ACPI processor id */
+ u8 local_apic_id; /* Processor's local APIC id */
+ u32 flags;
+} PACKED;
+
+struct madt_io_apic
+{
+ ACPI_SUB_HEADER_DEF
+ u8 io_apic_id; /* I/O APIC ID */
+ u8 reserved; /* Reserved - must be zero */
+ u32 address; /* APIC physical address */
+ u32 interrupt; /* Global system interrupt where INTI
+ * lines start */
+} PACKED;
+
+struct madt_intsrcovr {
+ ACPI_SUB_HEADER_DEF
+ u8 bus;
+ u8 source;
+ u32 gsi;
+ u16 flags;
+} PACKED;
+
+struct madt_local_nmi {
+ ACPI_SUB_HEADER_DEF
+ u8 processor_id; /* ACPI processor id */
+ u16 flags; /* MPS INTI flags */
+ u8 lint; /* Local APIC LINT# */
+} PACKED;
+
+/*
+ * HPET Description Table
+ */
+#define HPET_SIGNATURE 0x54455048 // HPET
+struct acpi_20_hpet {
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
+ u32 timer_block_id;
+ struct acpi_20_generic_address addr;
+ u8 hpet_number;
+ u16 min_tick;
+ u8 page_protect;
+} PACKED;
+
+/*
+ * SRAT (NUMA topology description) table
+ */
+
+#define SRAT_SIGNATURE 0x54415253 // SRAT
+struct system_resource_affinity_table
+{
+ ACPI_TABLE_HEADER_DEF
+ u32 reserved1;
+ u32 reserved2[2];
+} PACKED;
+
+#define SRAT_PROCESSOR 0
+#define SRAT_MEMORY 1
+
+struct srat_processor_affinity
+{
+ ACPI_SUB_HEADER_DEF
+ u8 proximity_lo;
+ u8 local_apic_id;
+ u32 flags;
+ u8 local_sapic_eid;
+ u8 proximity_hi[3];
+ u32 reserved;
+} PACKED;
+
+struct srat_memory_affinity
+{
+ ACPI_SUB_HEADER_DEF
+ u8 proximity[4];
+ u16 reserved1;
+ u64 base_addr;
+ u64 range_length;
+ u32 reserved2;
+ u32 flags;
+ u32 reserved3[2];
+} PACKED;
+
+/* PCI fw r3.0 MCFG table. */
+/* Subtable */
+struct acpi_mcfg_allocation {
+ u64 address; /* Base address, processor-relative */
+ u16 pci_segment; /* PCI segment group number */
+ u8 start_bus_number; /* Starting PCI Bus number */
+ u8 end_bus_number; /* Final PCI Bus number */
+ u32 reserved;
+} PACKED;
+
+#define MCFG_SIGNATURE 0x4746434d // MCFG
+struct acpi_table_mcfg {
+ ACPI_TABLE_HEADER_DEF;
+ u8 reserved[8];
+ struct acpi_mcfg_allocation allocation[0];
+} 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
+
+#define TPM2_SIGNATURE 0x324D5054
+struct tpm2_descriptor_rev2
+{
+ ACPI_TABLE_HEADER_DEF
+ u16 platform_class;
+ u16 reserved;
+ u64 address_of_control_area;
+ u32 start_method;
+ u8 start_method_params[12];
+ u32 log_area_minimum_length;
+ u64 log_area_start_address;
+} PACKED;
+
+#endif // acpi.h
diff --git a/roms/seabios-hppa/src/std/bda.h b/roms/seabios-hppa/src/std/bda.h
new file mode 100644
index 000000000..90d64a60d
--- /dev/null
+++ b/roms/seabios-hppa/src/std/bda.h
@@ -0,0 +1,174 @@
+// BIOS Data Area (and similar) definitions
+#ifndef __BDA_H
+#define __BDA_H
+
+#include "disk.h" // struct fdpt_s
+#include "types.h" // u8
+
+
+/****************************************************************
+ * Interrupt vector table
+ ****************************************************************/
+
+struct rmode_IVT {
+ struct segoff_s ivec[256];
+};
+
+
+/****************************************************************
+ * Bios Data Area (BDA)
+ ****************************************************************/
+
+struct bios_data_area_s {
+ // 40:00
+ u16 port_com[4];
+ u16 port_lpt[3];
+ u16 ebda_seg;
+ // 40:10
+ u16 equipment_list_flags;
+ u8 pad1;
+ u16 mem_size_kb;
+ u8 pad2;
+ u8 ps2_ctrl_flag;
+ u16 kbd_flag0;
+ u8 alt_keypad;
+ u16 kbd_buf_head;
+ u16 kbd_buf_tail;
+ // 40:1e
+ u8 kbd_buf[32];
+ u8 floppy_recalibration_status;
+ u8 floppy_motor_status;
+ // 40:40
+ u8 floppy_motor_counter;
+ u8 floppy_last_status;
+ u8 floppy_return_status[7];
+ u8 video_mode;
+ u16 video_cols;
+ u16 video_pagesize;
+ u16 video_pagestart;
+ // 40:50
+ u16 cursor_pos[8];
+ // 40:60
+ u16 cursor_type;
+ u8 video_page;
+ u16 crtc_address;
+ u8 video_msr;
+ u8 video_pal;
+ struct segoff_s jump;
+ u8 other_6b;
+ u32 timer_counter;
+ // 40:70
+ u8 timer_rollover;
+ u8 break_flag;
+ u16 soft_reset_flag;
+ u8 disk_last_status;
+ u8 hdcount;
+ u8 disk_control_byte;
+ u8 port_disk;
+ u8 lpt_timeout[4];
+ u8 com_timeout[4];
+ // 40:80
+ u16 kbd_buf_start_offset;
+ u16 kbd_buf_end_offset;
+ u8 video_rows;
+ u16 char_height;
+ u8 video_ctl;
+ u8 video_switches;
+ u8 modeset_ctl;
+ u8 dcc_index;
+ u8 floppy_last_data_rate;
+ u8 disk_status_controller;
+ u8 disk_error_controller;
+ u8 disk_interrupt_flag;
+ u8 floppy_harddisk_info;
+ // 40:90
+ u8 floppy_media_state[4];
+ u8 floppy_track[2];
+ u8 kbd_flag1;
+ u8 kbd_led;
+ struct segoff_s user_wait_complete_flag;
+ u32 user_wait_timeout;
+ // 40:A0
+ u8 rtc_wait_flag;
+ u8 other_a1[7];
+ struct segoff_s video_savetable;
+ u8 other_ac[4];
+ // 40:B0
+ u8 other_b0[5*16];
+} PACKED;
+
+// BDA floppy_recalibration_status bitdefs
+#define FRS_IRQ (1<<7)
+
+// BDA rtc_wait_flag bitdefs
+#define RWS_WAIT_PENDING (1<<0)
+#define RWS_WAIT_ELAPSED (1<<7)
+
+// BDA floppy_media_state bitdefs
+#define FMS_DRIVE_STATE_MASK (0x07)
+#define FMS_MEDIA_DRIVE_ESTABLISHED (1<<4)
+#define FMS_DOUBLE_STEPPING (1<<5)
+#define FMS_DATA_RATE_MASK (0xc0)
+
+// BDA kbd_flag[01] bitdefs
+#define KF0_RSHIFT (1<<0)
+#define KF0_LSHIFT (1<<1)
+#define KF0_CTRLACTIVE (1<<2)
+#define KF0_ALTACTIVE (1<<3)
+#define KF0_SCROLLACTIVE (1<<4)
+#define KF0_NUMACTIVE (1<<5)
+#define KF0_CAPSACTIVE (1<<6)
+#define KF0_LCTRL (1<<8)
+#define KF0_LALT (1<<9)
+#define KF0_PAUSEACTIVE (1<<11)
+#define KF0_SCROLL (1<<12)
+#define KF0_NUM (1<<13)
+#define KF0_CAPS (1<<14)
+
+#define KF1_LAST_E1 (1<<0)
+#define KF1_LAST_E0 (1<<1)
+#define KF1_RCTRL (1<<2)
+#define KF1_RALT (1<<3)
+#define KF1_101KBD (1<<4)
+
+// Limit of BDA timer_counter field
+#define TICKS_PER_DAY 1573040
+
+
+/****************************************************************
+ * Extended Bios Data Area (EBDA)
+ ****************************************************************/
+
+struct extended_bios_data_area_s {
+ u8 size;
+ u8 reserved1[0x21];
+ struct segoff_s far_call_pointer;
+ u8 mouse_flag1;
+ u8 mouse_flag2;
+ u8 mouse_data[0x08];
+ // 0x30
+ u8 other1[0x0d];
+
+ // 0x3d
+ struct fdpt_s fdpt[2];
+
+ // 0x5d
+ u8 other2[0xC4];
+
+ // 0x121 - Begin custom storage.
+} PACKED;
+
+
+/****************************************************************
+ * Bios Config Table
+ ****************************************************************/
+
+struct bios_config_table_s {
+ u16 size;
+ u8 model;
+ u8 submodel;
+ u8 biosrev;
+ u8 feature1, feature2, feature3, feature4, feature5;
+} PACKED;
+
+#endif // bda.h
diff --git a/roms/seabios-hppa/src/std/disk.h b/roms/seabios-hppa/src/std/disk.h
new file mode 100644
index 000000000..639710899
--- /dev/null
+++ b/roms/seabios-hppa/src/std/disk.h
@@ -0,0 +1,175 @@
+// Standard disk BIOS definitions.
+#ifndef __DISK_H
+#define __DISK_H
+
+#include "types.h" // u8
+
+#define DISK_RET_SUCCESS 0x00
+#define DISK_RET_EPARAM 0x01
+#define DISK_RET_EADDRNOTFOUND 0x02
+#define DISK_RET_EWRITEPROTECT 0x03
+#define DISK_RET_ECHANGED 0x06
+#define DISK_RET_EBOUNDARY 0x09
+#define DISK_RET_EBADTRACK 0x0c
+#define DISK_RET_ECONTROLLER 0x20
+#define DISK_RET_ETIMEOUT 0x80
+#define DISK_RET_ENOTLOCKED 0xb0
+#define DISK_RET_ELOCKED 0xb1
+#define DISK_RET_ENOTREMOVABLE 0xb2
+#define DISK_RET_ETOOMANYLOCKS 0xb4
+#define DISK_RET_EMEDIA 0xC0
+#define DISK_RET_ENOTREADY 0xAA
+
+
+/****************************************************************
+ * Interface structs
+ ****************************************************************/
+
+// Bios disk structures.
+struct int13ext_s {
+ u8 size;
+ u8 reserved;
+ u16 count;
+ struct segoff_s data;
+ u64 lba;
+} PACKED;
+
+// DPTE definition
+struct dpte_s {
+ u16 iobase1;
+ u16 iobase2;
+ u8 prefix;
+ u8 unused;
+ u8 irq;
+ u8 blkcount;
+ u8 dma;
+ u8 pio;
+ u16 options;
+ u16 reserved;
+ u8 revision;
+ u8 checksum;
+};
+
+// Disk Physical Table definition
+struct int13dpt_s {
+ u16 size;
+ u16 infos;
+ u32 cylinders;
+ u32 heads;
+ u32 spt;
+ u64 sector_count;
+ u16 blksize;
+ struct segoff_s dpte;
+ u16 key;
+ u8 dpi_length;
+ u8 reserved1;
+ u16 reserved2;
+ u8 host_bus[4];
+ u8 iface_type[8];
+ u64 iface_path;
+ union {
+ struct {
+ u64 device_path;
+ u8 reserved3;
+ u8 checksum;
+ } phoenix;
+ struct {
+ u64 device_path[2];
+ u8 reserved3;
+ u8 checksum;
+ } t13;
+ };
+} PACKED;
+
+// Floppy info
+struct fdpt_s {
+ u16 cylinders;
+ u8 heads;
+ u8 a0h_signature;
+ u8 phys_sectors;
+ u16 precompensation;
+ u8 reserved;
+ u8 drive_control_byte;
+ u16 phys_cylinders;
+ u8 phys_heads;
+ u16 landing_zone;
+ u8 sectors;
+ u8 checksum;
+} PACKED;
+
+// Floppy "Disk Base Table"
+struct floppy_dbt_s {
+ u8 specify1;
+ u8 specify2;
+ u8 shutoff_ticks;
+ u8 bps_code;
+ u8 sectors;
+ u8 interblock_len;
+ u8 data_len;
+ u8 gap_len;
+ u8 fill_byte;
+ u8 settle_time;
+ u8 startup_time;
+} PACKED;
+
+struct floppy_ext_dbt_s {
+ struct floppy_dbt_s dbt;
+ // Extra fields
+ u8 max_track;
+ u8 data_rate;
+ u8 drive_type;
+} PACKED;
+
+
+/****************************************************************
+ * Master boot record
+ ****************************************************************/
+
+struct packed_chs_s {
+ u8 heads;
+ u8 sptcyl;
+ u8 cyllow;
+} PACKED;
+
+struct partition_s {
+ u8 status;
+ struct packed_chs_s first;
+ u8 type;
+ struct packed_chs_s last;
+ u32 lba;
+ u32 count;
+} PACKED;
+
+struct mbr_s {
+ u8 code[440];
+ // 0x01b8
+ u32 diskseg;
+ // 0x01bc
+ u16 null;
+ // 0x01be
+ struct partition_s partitions[4];
+ // 0x01fe
+ u16 signature;
+} PACKED;
+
+#define MBR_SIGNATURE 0xaa55
+
+
+/****************************************************************
+ * ElTorito CDROM interface
+ ****************************************************************/
+
+struct eltorito_s {
+ u8 size;
+ u8 media;
+ u8 emulated_drive;
+ u8 controller_index;
+ u32 ilba;
+ u16 device_spec;
+ u16 buffer_segment;
+ u16 load_segment;
+ u16 sector_count;
+ struct packed_chs_s chs;
+} PACKED;
+
+#endif // disk.h
diff --git a/roms/seabios-hppa/src/std/mptable.h b/roms/seabios-hppa/src/std/mptable.h
new file mode 100644
index 000000000..fa6a22949
--- /dev/null
+++ b/roms/seabios-hppa/src/std/mptable.h
@@ -0,0 +1,77 @@
+#ifndef __MPTABLE_H
+#define __MPTABLE_H
+
+#include "types.h" // u32
+
+#define MPTABLE_SIGNATURE 0x5f504d5f // "_MP_"
+
+struct mptable_floating_s {
+ u32 signature;
+ u32 physaddr;
+ u8 length;
+ u8 spec_rev;
+ u8 checksum;
+ u8 feature1;
+ u8 feature2;
+ u8 reserved[3];
+};
+
+#define MPCONFIG_SIGNATURE 0x504d4350 // "PCMP"
+
+struct mptable_config_s {
+ u32 signature;
+ u16 length;
+ u8 spec;
+ u8 checksum;
+ char oemid[8];
+ char productid[12];
+ u32 oemptr;
+ u16 oemsize;
+ u16 entrycount;
+ u32 lapic;
+ u16 exttable_length;
+ u8 exttable_checksum;
+ u8 reserved;
+} PACKED;
+
+#define MPT_TYPE_CPU 0
+#define MPT_TYPE_BUS 1
+#define MPT_TYPE_IOAPIC 2
+#define MPT_TYPE_INTSRC 3
+#define MPT_TYPE_LOCAL_INT 4
+
+struct mpt_cpu {
+ u8 type;
+ u8 apicid;
+ u8 apicver;
+ u8 cpuflag;
+ u32 cpusignature;
+ u32 featureflag;
+ u32 reserved[2];
+} PACKED;
+
+struct mpt_bus {
+ u8 type;
+ u8 busid;
+ char bustype[6];
+} PACKED;
+
+struct mpt_ioapic {
+ u8 type;
+ u8 apicid;
+ u8 apicver;
+ u8 flags;
+ u32 apicaddr;
+} PACKED;
+
+struct mpt_intsrc {
+ u8 type;
+ u8 irqtype;
+ u16 irqflag;
+ u8 srcbus;
+ u8 srcbusirq;
+ u8 dstapic;
+ u8 dstirq;
+} PACKED;
+
+#endif // mptable.h
diff --git a/roms/seabios-hppa/src/std/multiboot.h b/roms/seabios-hppa/src/std/multiboot.h
new file mode 100644
index 000000000..6c9512703
--- /dev/null
+++ b/roms/seabios-hppa/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/roms/seabios-hppa/src/std/optionrom.h b/roms/seabios-hppa/src/std/optionrom.h
new file mode 100644
index 000000000..94ca4ae10
--- /dev/null
+++ b/roms/seabios-hppa/src/std/optionrom.h
@@ -0,0 +1,59 @@
+#ifndef __OPTIONROMS_H
+#define __OPTIONROMS_H
+
+#include "types.h" // u32
+
+#define OPTION_ROM_SIGNATURE 0xaa55
+
+struct rom_header {
+ u16 signature;
+ u8 size;
+ u8 initVector[4];
+ u8 reserved[17];
+ u16 pcioffset;
+ u16 pnpoffset;
+} PACKED;
+
+#define PCI_ROM_SIGNATURE 0x52494350 // "PCIR"
+
+struct pci_data {
+ u32 signature;
+ u16 vendor;
+ u16 device;
+ u16 vitaldata;
+ u16 dlen;
+ u8 drevision;
+ u8 class_lo;
+ u16 class_hi;
+ u16 ilen;
+ u16 irevision;
+ u8 type;
+ u8 indicator;
+ u16 reserved;
+} PACKED;
+
+struct pnp_data {
+ u32 signature;
+ u8 revision;
+ u8 len;
+ u16 nextoffset;
+ u8 reserved_08;
+ u8 checksum;
+ u32 devid;
+ u16 manufacturer;
+ u16 productname;
+ u8 type_lo;
+ u16 type_hi;
+ u8 dev_flags;
+ u16 bcv;
+ u16 dv;
+ u16 bev;
+ u16 reserved_1c;
+ u16 staticresource;
+} PACKED;
+
+#define OPTION_ROM_ALIGN 2048
+#define OPTION_ROM_INITVECTOR offsetof(struct rom_header, initVector[0])
+#define PCIROM_CODETYPE_X86 0
+
+#endif
diff --git a/roms/seabios-hppa/src/std/pirtable.h b/roms/seabios-hppa/src/std/pirtable.h
new file mode 100644
index 000000000..9de3a4389
--- /dev/null
+++ b/roms/seabios-hppa/src/std/pirtable.h
@@ -0,0 +1,35 @@
+#ifndef __PIRTABLE_H
+#define __PIRTABLE_H
+
+#include "types.h" // u32
+
+struct link_info {
+ u8 link;
+ u16 bitmap;
+} PACKED;
+
+struct pir_slot {
+ u8 bus;
+ u8 dev;
+ struct link_info links[4];
+ u8 slot_nr;
+ u8 reserved;
+} PACKED;
+
+struct pir_header {
+ u32 signature;
+ u16 version;
+ u16 size;
+ u8 router_bus;
+ u8 router_devfunc;
+ u16 exclusive_irqs;
+ u32 compatible_devid;
+ u32 miniport_data;
+ u8 reserved[11];
+ u8 checksum;
+ struct pir_slot slots[0];
+} PACKED;
+
+#define PIR_SIGNATURE 0x52495024 // $PIR
+
+#endif // pirtable.h
diff --git a/roms/seabios-hppa/src/std/pmm.h b/roms/seabios-hppa/src/std/pmm.h
new file mode 100644
index 000000000..80027f38b
--- /dev/null
+++ b/roms/seabios-hppa/src/std/pmm.h
@@ -0,0 +1,19 @@
+#ifndef __PMM_H
+#define __PMM_H
+
+#include "types.h" // u32
+
+#define PMM_SIGNATURE 0x4d4d5024 // $PMM
+
+struct pmmheader {
+ u32 signature;
+ u8 version;
+ u8 length;
+ u8 checksum;
+ struct segoff_s entry;
+ u8 reserved[5];
+} PACKED;
+
+#define PMM_FUNCTION_NOT_SUPPORTED 0xffffffff
+
+#endif // pmm.h
diff --git a/roms/seabios-hppa/src/std/pnpbios.h b/roms/seabios-hppa/src/std/pnpbios.h
new file mode 100644
index 000000000..0871e3ab5
--- /dev/null
+++ b/roms/seabios-hppa/src/std/pnpbios.h
@@ -0,0 +1,24 @@
+#ifndef __PNPHEADER_H
+#define __PNPHEADER_H
+
+#define PNP_SIGNATURE 0x506e5024 // $PnP
+
+struct pnpheader {
+ u32 signature;
+ u8 version;
+ u8 length;
+ u16 control;
+ u8 checksum;
+ u32 eventloc;
+ u16 real_ip;
+ u16 real_cs;
+ u16 prot_ip;
+ u32 prot_base;
+ u32 oemid;
+ u16 real_ds;
+ u32 prot_database;
+} PACKED;
+
+#define FUNCTION_NOT_SUPPORTED 0x82
+
+#endif // pnpheader.h
diff --git a/roms/seabios-hppa/src/std/smbios.h b/roms/seabios-hppa/src/std/smbios.h
new file mode 100644
index 000000000..4ccf2ea34
--- /dev/null
+++ b/roms/seabios-hppa/src/std/smbios.h
@@ -0,0 +1,167 @@
+#ifndef __SMBIOS_H
+#define __SMBIOS_H
+
+#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 {
+ u32 signature;
+ u8 checksum;
+ u8 length;
+ u8 smbios_major_version;
+ u8 smbios_minor_version;
+ u16 max_structure_size;
+ u8 entry_point_revision;
+ u8 formatted_area[5];
+ char intermediate_anchor_string[5];
+ u8 intermediate_checksum;
+ u16 structure_table_length;
+ u32 structure_table_address;
+ u16 number_of_structures;
+ u8 smbios_bcd_revision;
+} PACKED;
+
+/* This goes at the beginning of every SMBIOS structure. */
+struct smbios_structure_header {
+ u8 type;
+ u8 length;
+ u16 handle;
+} PACKED;
+
+/* SMBIOS type 0 - BIOS Information */
+struct smbios_type_0 {
+ struct smbios_structure_header header;
+ u8 vendor_str;
+ u8 bios_version_str;
+ u16 bios_starting_address_segment;
+ u8 bios_release_date_str;
+ u8 bios_rom_size;
+ u8 bios_characteristics[8];
+ u8 bios_characteristics_extension_bytes[2];
+ u8 system_bios_major_release;
+ u8 system_bios_minor_release;
+ u8 embedded_controller_major_release;
+ u8 embedded_controller_minor_release;
+} PACKED;
+
+/* SMBIOS type 1 - System Information */
+struct smbios_type_1 {
+ struct smbios_structure_header header;
+ u8 manufacturer_str;
+ u8 product_name_str;
+ u8 version_str;
+ u8 serial_number_str;
+ u8 uuid[16];
+ u8 wake_up_type;
+ u8 sku_number_str;
+ u8 family_str;
+} PACKED;
+
+/* SMBIOS type 3 - System Enclosure (v2.3) */
+struct smbios_type_3 {
+ struct smbios_structure_header header;
+ u8 manufacturer_str;
+ u8 type;
+ u8 version_str;
+ u8 serial_number_str;
+ u8 asset_tag_number_str;
+ u8 boot_up_state;
+ u8 power_supply_state;
+ u8 thermal_state;
+ u8 security_status;
+ u32 oem_defined;
+ u8 height;
+ u8 number_of_power_cords;
+ u8 contained_element_count;
+ // contained elements follow
+} PACKED;
+
+/* SMBIOS type 4 - Processor Information (v2.0) */
+struct smbios_type_4 {
+ struct smbios_structure_header header;
+ u8 socket_designation_str;
+ u8 processor_type;
+ u8 processor_family;
+ u8 processor_manufacturer_str;
+ u32 processor_id[2];
+ u8 processor_version_str;
+ u8 voltage;
+ u16 external_clock;
+ u16 max_speed;
+ u16 current_speed;
+ u8 status;
+ u8 processor_upgrade;
+ u16 l1_cache_handle;
+ u16 l2_cache_handle;
+ u16 l3_cache_handle;
+} PACKED;
+
+/* SMBIOS type 16 - Physical Memory Array
+ * Associated with one type 17 (Memory Device).
+ */
+struct smbios_type_16 {
+ struct smbios_structure_header header;
+ u8 location;
+ u8 use;
+ u8 error_correction;
+ u32 maximum_capacity;
+ u16 memory_error_information_handle;
+ u16 number_of_memory_devices;
+} PACKED;
+
+/* SMBIOS type 17 - Memory Device
+ * Associated with one type 19
+ */
+struct smbios_type_17 {
+ struct smbios_structure_header header;
+ u16 physical_memory_array_handle;
+ u16 memory_error_information_handle;
+ u16 total_width;
+ u16 data_width;
+ u16 size;
+ u8 form_factor;
+ u8 device_set;
+ u8 device_locator_str;
+ u8 bank_locator_str;
+ u8 memory_type;
+ u16 type_detail;
+} PACKED;
+
+/* SMBIOS type 19 - Memory Array Mapped Address */
+struct smbios_type_19 {
+ struct smbios_structure_header header;
+ u32 starting_address;
+ u32 ending_address;
+ u16 memory_array_handle;
+ u8 partition_width;
+} PACKED;
+
+/* SMBIOS type 20 - Memory Device Mapped Address */
+struct smbios_type_20 {
+ struct smbios_structure_header header;
+ u32 starting_address;
+ u32 ending_address;
+ u16 memory_device_handle;
+ u16 memory_array_mapped_address_handle;
+ u8 partition_row_position;
+ u8 interleave_position;
+ u8 interleaved_data_depth;
+} PACKED;
+
+/* SMBIOS type 32 - System Boot Information */
+struct smbios_type_32 {
+ struct smbios_structure_header header;
+ u8 reserved[6];
+ u8 boot_status;
+} PACKED;
+
+/* SMBIOS type 127 -- End-of-table */
+struct smbios_type_127 {
+ struct smbios_structure_header header;
+} PACKED;
+
+#endif // smbios.h
diff --git a/roms/seabios-hppa/src/std/tcg.h b/roms/seabios-hppa/src/std/tcg.h
new file mode 100644
index 000000000..98cca4996
--- /dev/null
+++ b/roms/seabios-hppa/src/std/tcg.h
@@ -0,0 +1,580 @@
+#ifndef STD_TCG_H
+#define STD_TCG_H
+
+#include "types.h"
+
+#define SHA1_BUFSIZE 20
+#define SHA256_BUFSIZE 32
+#define SHA384_BUFSIZE 48
+#define SHA512_BUFSIZE 64
+#define SM3_256_BUFSIZE 32
+#define SHA3_256_BUFSIZE 32
+#define SHA3_384_BUFSIZE 48
+#define SHA3_512_BUFSIZE 64
+
+
+/****************************************************************
+ * 16bit BIOS interface
+ ****************************************************************/
+
+/* 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)
+
+/* 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,
+};
+
+/* 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;
+ u8 event[0];
+} PACKED;
+
+
+/****************************************************************
+ * TPM v1.2 hardware commands
+ ****************************************************************/
+
+#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_SetTempDeactivated 0x00000073
+#define TPM_ORD_Startup 0x00000099
+#define TPM_ORD_PhysicalPresence 0x4000000a
+#define TPM_ORD_Extend 0x00000014
+#define TSC_ORD_ResetEstablishmentBit 0x4000000b
+
+#define TPM_ST_CLEAR 0x0001
+#define TPM_ST_STATE 0x0002
+#define TPM_ST_DEACTIVATED 0x0003
+
+#define TPM_PP_CMD_ENABLE 0x0020
+#define TPM_PP_PRESENT 0x0008
+#define TPM_PP_NOT_PRESENT_LOCK 0x0014
+
+/* TPM command error codes */
+#define TPM_INVALID_POSTINIT 0x26
+#define TPM_BAD_LOCALITY 0x3d
+
+/* TPM command tags */
+#define TPM_TAG_RQU_CMD 0x00c1
+#define TPM_TAG_RQU_AUTH1_CMD 0x00c2
+#define TPM_TAG_RQU_AUTH2_CMD 0x00c3
+
+struct tpm_req_header {
+ u16 tag;
+ u32 totlen;
+ u32 ordinal;
+} PACKED;
+
+struct tpm_rsp_header {
+ u16 tag;
+ u32 totlen;
+ u32 errcode;
+} PACKED;
+
+struct tpm_req_extend {
+ struct tpm_req_header hdr;
+ u32 pcrindex;
+ u8 digest[SHA1_BUFSIZE];
+} PACKED;
+
+struct tpm_rsp_extend {
+ struct tpm_rsp_header hdr;
+ u8 digest[SHA1_BUFSIZE];
+} PACKED;
+
+struct tpm_req_getcap {
+ struct tpm_req_header hdr;
+ u32 capArea;
+ u32 subCapSize;
+ u32 subCap;
+} PACKED;
+
+#define TPM_CAP_FLAG 0x04
+#define TPM_CAP_PROPERTY 0x05
+#define TPM_CAP_FLAG_PERMANENT 0x108
+#define TPM_CAP_FLAG_VOLATILE 0x109
+#define TPM_CAP_PROP_OWNER 0x111
+#define TPM_CAP_PROP_TIS_TIMEOUT 0x115
+#define TPM_CAP_PROP_DURATION 0x120
+
+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,
+ PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE,
+};
+
+struct tpm_res_getcap_perm_flags {
+ struct tpm_rsp_header hdr;
+ u32 size;
+ struct tpm_permanent_flags perm_flags;
+} PACKED;
+
+struct tpm_stclear_flags {
+ u16 tag;
+ u8 flags[5];
+} PACKED;
+
+#define STCLEAR_FLAG_IDX_DEACTIVATED 0
+#define STCLEAR_FLAG_IDX_DISABLE_FORCE_CLEAR 1
+#define STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE 2
+#define STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE_LOCK 3
+#define STCLEAR_FLAG_IDX_GLOBAL_LOCK 4
+
+struct tpm_res_getcap_stclear_flags {
+ struct tpm_rsp_header hdr;
+ u32 size;
+ struct tpm_stclear_flags stclear_flags;
+} PACKED;
+
+struct tpm_res_getcap_ownerauth {
+ struct tpm_rsp_header hdr;
+ u32 size;
+ u8 flag;
+} PACKED;
+
+struct tpm_res_getcap_timeouts {
+ struct tpm_rsp_header hdr;
+ u32 size;
+ u32 timeouts[4];
+} PACKED;
+
+struct tpm_res_getcap_durations {
+ struct tpm_rsp_header hdr;
+ u32 size;
+ u32 durations[3];
+} PACKED;
+
+struct tpm_res_sha1start {
+ struct tpm_rsp_header hdr;
+ u32 max_num_bytes;
+} PACKED;
+
+struct tpm_res_sha1complete {
+ struct tpm_rsp_header hdr;
+ u8 hash[20];
+} PACKED;
+
+
+/****************************************************************
+ * TPM v2.0 hardware commands
+ ****************************************************************/
+
+#define TPM2_NO 0
+#define TPM2_YES 1
+
+#define TPM2_SU_CLEAR 0x0000
+#define TPM2_SU_STATE 0x0001
+
+#define TPM2_RH_OWNER 0x40000001
+#define TPM2_RS_PW 0x40000009
+#define TPM2_RH_ENDORSEMENT 0x4000000b
+#define TPM2_RH_PLATFORM 0x4000000c
+
+#define TPM2_ALG_SHA1 0x0004
+#define TPM2_ALG_SHA256 0x000b
+#define TPM2_ALG_SHA384 0x000c
+#define TPM2_ALG_SHA512 0x000d
+#define TPM2_ALG_SM3_256 0x0012
+#define TPM2_ALG_SHA3_256 0x0027
+#define TPM2_ALG_SHA3_384 0x0028
+#define TPM2_ALG_SHA3_512 0x0029
+
+#define TPM2_ALG_SHA1_FLAG (1 << 0)
+#define TPM2_ALG_SHA256_FLAG (1 << 1)
+#define TPM2_ALG_SHA384_FLAG (1 << 2)
+#define TPM2_ALG_SHA512_FLAG (1 << 3)
+#define TPM2_ALG_SM3_256_FLAG (1 << 4)
+#define TPM2_ALG_SHA3_256_FLAG (1 << 5)
+#define TPM2_ALG_SHA3_384_FLAG (1 << 6)
+#define TPM2_ALG_SHA3_512_FLAG (1 << 7)
+
+/* TPM 2 command tags */
+#define TPM2_ST_NO_SESSIONS 0x8001
+#define TPM2_ST_SESSIONS 0x8002
+
+/* TPM 2 commands */
+#define TPM2_CC_HierarchyControl 0x121
+#define TPM2_CC_Clear 0x126
+#define TPM2_CC_ClearControl 0x127
+#define TPM2_CC_HierarchyChangeAuth 0x129
+#define TPM2_CC_PCR_Allocate 0x12b
+#define TPM2_CC_SelfTest 0x143
+#define TPM2_CC_Startup 0x144
+#define TPM2_CC_Shutdown 0x145
+#define TPM2_CC_StirRandom 0x146
+#define TPM2_CC_GetCapability 0x17a
+#define TPM2_CC_GetRandom 0x17b
+#define TPM2_CC_PCR_Extend 0x182
+
+/* TPM 2 error codes */
+#define TPM2_RC_INITIALIZE 0x100
+
+/* TPM 2 Capabilities */
+#define TPM2_CAP_PCRS 0x00000005
+
+/* TPM 2 data structures */
+
+struct tpm2_req_stirrandom {
+ struct tpm_req_header hdr;
+ u16 size;
+ u64 stir;
+} PACKED;
+
+struct tpm2_req_getrandom {
+ struct tpm_req_header hdr;
+ u16 bytesRequested;
+} PACKED;
+
+struct tpm2b_20 {
+ u16 size;
+ u8 buffer[20];
+} PACKED;
+
+struct tpm2_res_getrandom {
+ struct tpm_rsp_header hdr;
+ struct tpm2b_20 rnd;
+} PACKED;
+
+struct tpm2_authblock {
+ u32 handle;
+ u16 noncesize; /* always 0 */
+ u8 contsession; /* always TPM2_YES */
+ u16 pwdsize; /* always 0 */
+} PACKED;
+
+struct tpm2_req_hierarchychangeauth {
+ struct tpm_req_header hdr;
+ u32 authhandle;
+ u32 authblocksize;
+ struct tpm2_authblock authblock;
+ struct tpm2b_20 newAuth;
+} PACKED;
+
+struct tpm2_req_extend {
+ struct tpm_req_header hdr;
+ u32 pcrindex;
+ u32 authblocksize;
+ struct tpm2_authblock authblock;
+ u8 digest[0];
+} PACKED;
+
+struct tpm2_req_clearcontrol {
+ struct tpm_req_header hdr;
+ u32 authhandle;
+ u32 authblocksize;
+ struct tpm2_authblock authblock;
+ u8 disable;
+} PACKED;
+
+struct tpm2_req_clear {
+ struct tpm_req_header hdr;
+ u32 authhandle;
+ u32 authblocksize;
+ struct tpm2_authblock authblock;
+} PACKED;
+
+struct tpm2_req_hierarchycontrol {
+ struct tpm_req_header hdr;
+ u32 authhandle;
+ u32 authblocksize;
+ struct tpm2_authblock authblock;
+ u32 enable;
+ u8 state;
+} PACKED;
+
+struct tpm2_req_getcapability {
+ struct tpm_req_header hdr;
+ u32 capability;
+ u32 property;
+ u32 propertycount;
+} PACKED;
+
+struct tpm2_res_getcapability {
+ struct tpm_rsp_header hdr;
+ u8 moreData;
+ u32 capability;
+ u8 data[0]; /* capability dependent data */
+} PACKED;
+
+struct tpm2_req_pcr_allocate {
+ struct tpm_req_header hdr;
+ u32 authhandle;
+ u32 authblocksize;
+ struct tpm2_authblock authblock;
+ u32 count;
+ u8 tpms_pcr_selections[4];
+} PACKED;
+
+struct tpms_pcr_selection {
+ u16 hashAlg;
+ u8 sizeOfSelect;
+ u8 pcrSelect[0];
+} PACKED;
+
+struct tpml_pcr_selection {
+ u32 count;
+ struct tpms_pcr_selection selections[0];
+} PACKED;
+
+
+/****************************************************************
+ * ACPI TCPA table interface
+ ****************************************************************/
+
+/* event types: 10.4.1 / table 11 */
+#define EV_POST_CODE 1
+#define EV_NO_ACTION 3
+#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
+
+struct tpm2_digest_value {
+ u16 hashAlg;
+ u8 hash[0]; /* size depends on hashAlg */
+} PACKED;
+
+struct tpm2_digest_values {
+ u32 count;
+ struct tpm2_digest_value digest[0];
+} PACKED;
+
+// Each entry in the TPM log contains: a tpm_log_header, a variable
+// length digest, a tpm_log_trailer, and a variable length event. The
+// 'digest' matches what is sent to the TPM hardware via the Extend
+// command. On TPM1.2 the digest is a SHA1 hash; on TPM2.0 the digest
+// contains a tpm2_digest_values struct followed by a variable number
+// of tpm2_digest_value structs (as specified by the hardware via the
+// TPM2_CAP_PCRS request).
+struct tpm_log_header {
+ u32 pcrindex;
+ u32 eventtype;
+ u8 digest[0];
+} PACKED;
+
+struct tpm_log_trailer {
+ u32 eventdatasize;
+ u8 event[0];
+} PACKED;
+
+struct TCG_EfiSpecIdEventStruct {
+ u8 signature[16];
+ u32 platformClass;
+ u8 specVersionMinor;
+ u8 specVersionMajor;
+ u8 specErrata;
+ u8 uintnSize;
+ u32 numberOfAlgorithms;
+ struct TCG_EfiSpecIdEventAlgorithmSize {
+ u16 algorithmId;
+ u16 digestSize;
+ } digestSizes[];
+ /*
+ u8 vendorInfoSize;
+ u8 vendorInfo[0];
+ */
+} PACKED;
+
+#define TPM_TCPA_ACPI_CLASS_CLIENT 0
+
+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;
+
+
+/****************************************************************
+ * Physical presence interface
+ ****************************************************************/
+
+#define TPM_STATE_ENABLED 1
+#define TPM_STATE_ACTIVE 2
+#define TPM_STATE_OWNED 4
+#define TPM_STATE_OWNERINSTALL 8
+
+#define TPM_PPI_OP_NOOP 0
+#define TPM_PPI_OP_ENABLE 1
+#define TPM_PPI_OP_DISABLE 2
+#define TPM_PPI_OP_ACTIVATE 3
+#define TPM_PPI_OP_DEACTIVATE 4
+#define TPM_PPI_OP_CLEAR 5
+#define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8
+#define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9
+
+#endif // tcg.h
diff --git a/roms/seabios-hppa/src/std/vbe.h b/roms/seabios-hppa/src/std/vbe.h
new file mode 100644
index 000000000..94b4ad86f
--- /dev/null
+++ b/roms/seabios-hppa/src/std/vbe.h
@@ -0,0 +1,156 @@
+#ifndef __VBE_H
+#define __VBE_H
+
+#include "types.h" // u8
+
+#define VESA_SIGNATURE 0x41534556 // VESA
+#define VBE2_SIGNATURE 0x32454256 // VBE2
+
+struct vbe_info {
+ u32 signature;
+ u16 version;
+ struct segoff_s oem_string;
+ u32 capabilities;
+ struct segoff_s video_mode;
+ u16 total_memory;
+ u16 oem_revision;
+ struct segoff_s oem_vendor_string;
+ struct segoff_s oem_product_string;
+ struct segoff_s oem_revision_string;
+ u8 reserved[222];
+} PACKED;
+
+struct vbe_mode_info {
+ /* VBE */
+ u16 mode_attributes;
+ u8 winA_attributes;
+ u8 winB_attributes;
+ u16 win_granularity;
+ u16 win_size;
+ u16 winA_seg;
+ u16 winB_seg;
+ struct segoff_s win_func_ptr;
+ u16 bytes_per_scanline;
+ /* VBE 1.2 */
+ u16 xres;
+ u16 yres;
+ u8 xcharsize;
+ u8 ycharsize;
+ u8 planes;
+ u8 bits_per_pixel;
+ u8 banks;
+ u8 mem_model;
+ u8 bank_size;
+ u8 pages;
+ u8 reserved0;
+ /* Direct Color */
+ u8 red_size;
+ u8 red_pos;
+ u8 green_size;
+ u8 green_pos;
+ u8 blue_size;
+ u8 blue_pos;
+ u8 alpha_size;
+ u8 alpha_pos;
+ u8 directcolor_info;
+ /* VBE 2.0 */
+ u32 phys_base;
+ u32 reserved1;
+ u16 reserved2;
+ /* VBE 3.0 */
+ u16 linear_bytes_per_scanline;
+ u8 bank_pages;
+ u8 linear_pages;
+ u8 linear_red_size;
+ u8 linear_red_pos;
+ u8 linear_green_size;
+ u8 linear_green_pos;
+ u8 linear_blue_size;
+ u8 linear_blue_pos;
+ u8 linear_alpha_size;
+ u8 linear_alpha_pos;
+ u32 pixclock_max;
+ u8 reserved[190];
+} PACKED;
+
+struct vbe_crtc_info {
+ u16 horiz_total;
+ u16 horiz_sync_start;
+ u16 horiz_sync_end;
+ u16 vert_total;
+ u16 vert_sync_start;
+ u16 vert_sync_end;
+ u8 flags;
+ u32 pixclock;
+ u16 refresh_rate;
+ u8 reserved[40];
+} PACKED;
+
+/* VBE Return Status Info */
+/* AL */
+#define VBE_RETURN_STATUS_SUPPORTED 0x4F
+#define VBE_RETURN_STATUS_UNSUPPORTED 0x00
+/* AH */
+#define VBE_RETURN_STATUS_SUCCESSFULL 0x00
+#define VBE_RETURN_STATUS_FAILED 0x01
+#define VBE_RETURN_STATUS_NOT_SUPPORTED 0x02
+#define VBE_RETURN_STATUS_INVALID 0x03
+
+/* VBE Mode Numbers */
+
+#define VBE_MODE_VESA_DEFINED 0x0100
+#define VBE_MODE_REFRESH_RATE_USE_CRTC 0x0800
+#define VBE_MODE_LINEAR_FRAME_BUFFER 0x4000
+#define VBE_MODE_PRESERVE_DISPLAY_MEMORY 0x8000
+
+#define VBE_VESA_MODE_END_OF_LIST 0xFFFF
+
+/* Capabilities */
+
+#define VBE_CAPABILITY_8BIT_DAC 0x0001
+#define VBE_CAPABILITY_NOT_VGA_COMPATIBLE 0x0002
+#define VBE_CAPABILITY_RAMDAC_USE_BLANK_BIT 0x0004
+#define VBE_CAPABILITY_STEREOSCOPIC_SUPPORT 0x0008
+#define VBE_CAPABILITY_STEREO_VIA_VESA_EVC 0x0010
+
+/* Mode Attributes */
+
+#define VBE_MODE_ATTRIBUTE_SUPPORTED 0x0001
+#define VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE 0x0002
+#define VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT 0x0004
+#define VBE_MODE_ATTRIBUTE_COLOR_MODE 0x0008
+#define VBE_MODE_ATTRIBUTE_GRAPHICS_MODE 0x0010
+#define VBE_MODE_ATTRIBUTE_NOT_VGA_COMPATIBLE 0x0020
+#define VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW 0x0040
+#define VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE 0x0080
+#define VBE_MODE_ATTRIBUTE_DOUBLE_SCAN_MODE 0x0100
+#define VBE_MODE_ATTRIBUTE_INTERLACE_MODE 0x0200
+#define VBE_MODE_ATTRIBUTE_HARDWARE_TRIPLE_BUFFER 0x0400
+#define VBE_MODE_ATTRIBUTE_HARDWARE_STEREOSCOPIC_DISPLAY 0x0800
+#define VBE_MODE_ATTRIBUTE_DUAL_DISPLAY_START_ADDRESS 0x1000
+
+#define VBE_MODE_ATTTRIBUTE_LFB_ONLY ( VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE )
+
+/* Window attributes */
+
+#define VBE_WINDOW_ATTRIBUTE_RELOCATABLE 0x01
+#define VBE_WINDOW_ATTRIBUTE_READABLE 0x02
+#define VBE_WINDOW_ATTRIBUTE_WRITEABLE 0x04
+
+/* Memory model */
+
+#define VBE_MEMORYMODEL_TEXT_MODE 0x00
+#define VBE_MEMORYMODEL_CGA_GRAPHICS 0x01
+#define VBE_MEMORYMODEL_HERCULES_GRAPHICS 0x02
+#define VBE_MEMORYMODEL_PLANAR 0x03
+#define VBE_MEMORYMODEL_PACKED_PIXEL 0x04
+#define VBE_MEMORYMODEL_NON_CHAIN_4_256 0x05
+#define VBE_MEMORYMODEL_DIRECT_COLOR 0x06
+#define VBE_MEMORYMODEL_YUV 0x07
+
+/* DirectColorModeInfo */
+
+#define VBE_DIRECTCOLOR_COLOR_RAMP_PROGRAMMABLE 0x01
+#define VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE 0x02
+
+#endif
diff --git a/roms/seabios-hppa/src/std/vga.h b/roms/seabios-hppa/src/std/vga.h
new file mode 100644
index 000000000..de9ec7506
--- /dev/null
+++ b/roms/seabios-hppa/src/std/vga.h
@@ -0,0 +1,63 @@
+#ifndef __VGA_H
+#define __VGA_H
+// Standard structure definitions for vgabios video tables
+
+#include "types.h" // u8
+
+// standard BIOS Video Parameter Table
+struct video_param_s {
+ u8 twidth;
+ u8 theightm1;
+ u8 cheight;
+ u16 slength;
+ u8 sequ_regs[4];
+ u8 miscreg;
+ u8 crtc_regs[25];
+ u8 actl_regs[20];
+ u8 grdc_regs[9];
+} PACKED;
+
+// Standard Video Save Pointer Table
+struct video_save_pointer_s {
+ struct segoff_s videoparam;
+ struct segoff_s paramdynamicsave;
+ struct segoff_s textcharset;
+ struct segoff_s graphcharset;
+ struct segoff_s secsavepointer;
+ u8 reserved[8];
+} PACKED;
+
+// Data returned by int101B
+struct video_func_static {
+ u32 modes;
+ u8 reserved_0x04[3];
+ u8 scanlines;
+ u8 cblocks;
+ u8 active_cblocks;
+ u16 misc_flags;
+ u8 reserved_0x0c[2];
+ u8 save_flags;
+ u8 reserved_0x0f;
+} PACKED;
+
+struct video_func_info {
+ struct segoff_s static_functionality;
+ u8 bda_0x49[30];
+ u8 bda_0x84[3];
+ u8 dcc_index;
+ u8 dcc_alt;
+ u16 colors;
+ u8 pages;
+ u8 scan_lines;
+ u8 primary_char;
+ u8 secondar_char;
+ u8 misc;
+ u8 non_vga_mode;
+ u8 reserved_2f[2];
+ u8 video_mem;
+ u8 save_flags;
+ u8 disp_info;
+ u8 reserved_34[12];
+} PACKED;
+
+#endif // vga.h
diff --git a/roms/seabios-hppa/src/string.c b/roms/seabios-hppa/src/string.c
new file mode 100644
index 000000000..11a96f364
--- /dev/null
+++ b/roms/seabios-hppa/src/string.c
@@ -0,0 +1,276 @@
+// String manipulation functions.
+//
+// Copyright (C) 2008-2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "stacks.h" // yield
+#include "string.h" // memcpy
+#include "farptr.h" // SET_SEG
+
+
+/****************************************************************
+ * String ops
+ ****************************************************************/
+
+// Sum the bytes in the specified area.
+u8
+checksum_far(u16 buf_seg, void *buf_far, u32 len)
+{
+ SET_SEG(ES, buf_seg);
+ u32 i;
+ u8 sum = 0;
+ for (i=0; i<len; i++)
+ sum += GET_VAR(ES, ((u8*)buf_far)[i]);
+ return sum;
+}
+
+u8
+checksum(void *buf, u32 len)
+{
+ return checksum_far(GET_SEG(SS), buf, len);
+}
+
+size_t
+strlen(const char *s)
+{
+ if (__builtin_constant_p(s))
+ return __builtin_strlen(s);
+ const char *p = s;
+ while (*p)
+ p++;
+ return p-s;
+}
+
+int
+memcmp_far(u16 s1seg, const void *s1, u16 s2seg, const void *s2, size_t n)
+{
+ while (n--) {
+ int d = GET_FARVAR(s1seg, *(u8*)s1) - GET_FARVAR(s2seg, *(u8*)s2);
+ if (d)
+ return d < 0 ? -1 : 1;
+ s1++;
+ s2++;
+ }
+ return 0;
+}
+
+// Compare two areas of memory.
+int
+memcmp(const void *s1, const void *s2, size_t n)
+{
+ while (n) {
+ if (*(u8*)s1 != *(u8*)s2)
+ return *(u8*)s1 < *(u8*)s2 ? -1 : 1;
+ s1++;
+ s2++;
+ n--;
+ }
+ return 0;
+}
+
+// Compare two strings.
+int
+strcmp(const char *s1, const char *s2)
+{
+ for (;;) {
+ if (*s1 != *s2)
+ return *s1 < *s2 ? -1 : 1;
+ if (! *s1)
+ return 0;
+ s1++;
+ s2++;
+ }
+}
+
+inline void
+memset_far(u16 d_seg, void *d_far, u8 c, size_t len)
+{
+#if CONFIG_X86
+ SET_SEG(ES, d_seg);
+ asm volatile(
+ "rep stosb %%es:(%%di)"
+ : "+c"(len), "+D"(d_far)
+ : "a"(c), "m" (__segment_ES)
+ : "cc", "memory");
+#else
+ memset(d_far, c, len);
+#endif
+}
+
+inline void
+memset16_far(u16 d_seg, void *d_far, u16 c, size_t len)
+{
+ len /= 2;
+#if CONFIG_X86
+ SET_SEG(ES, d_seg);
+ asm volatile(
+ "rep stosw %%es:(%%di)"
+ : "+c"(len), "+D"(d_far)
+ : "a"(c), "m" (__segment_ES)
+ : "cc", "memory");
+#else
+ while (len)
+ ((u16 *)d_far)[--len] = c;
+#endif
+}
+
+void *
+memset(void *s, int c, size_t n)
+{
+ while (n)
+ ((char *)s)[--n] = c;
+ return s;
+}
+
+void memset_fl(void *ptr, u8 val, size_t size)
+{
+ if (MODESEGMENT)
+ memset_far(FLATPTR_TO_SEG(ptr), (void*)(FLATPTR_TO_OFFSET(ptr)),
+ val, size);
+ else
+ memset(ptr, val, size);
+}
+
+inline void
+memcpy_far(u16 d_seg, void *d_far, u16 s_seg, const void *s_far, size_t len)
+{
+#if CONFIG_X86
+ SET_SEG(ES, d_seg);
+ u16 bkup_ds;
+ asm volatile(
+ "movw %%ds, %w0\n"
+ "movw %w4, %%ds\n"
+ "rep movsb (%%si),%%es:(%%di)\n"
+ "movw %w0, %%ds"
+ : "=&r"(bkup_ds), "+c"(len), "+S"(s_far), "+D"(d_far)
+ : "r"(s_seg), "m" (__segment_ES)
+ : "cc", "memory");
+#else
+ memcpy(d_far, s_far, len);
+#endif
+}
+
+inline void
+memcpy_fl(void *d_fl, const void *s_fl, size_t len)
+{
+ if (MODESEGMENT)
+ memcpy_far(FLATPTR_TO_SEG(d_fl), (void*)FLATPTR_TO_OFFSET(d_fl)
+ , FLATPTR_TO_SEG(s_fl), (void*)FLATPTR_TO_OFFSET(s_fl)
+ , len);
+ else
+ memcpy(d_fl, s_fl, len);
+}
+
+void * __VISIBLE
+#undef memcpy
+memcpy(void *d1, const void *s1, size_t len)
+#if MODESEGMENT == 0
+#define memcpy __builtin_memcpy
+#endif
+{
+#if CONFIG_X86
+ SET_SEG(ES, GET_SEG(SS));
+ void *d = d1;
+ if (((u32)d1 | (u32)s1 | len) & 3) {
+ // non-aligned memcpy
+ asm volatile(
+ "rep movsb (%%esi),%%es:(%%edi)"
+ : "+c"(len), "+S"(s1), "+D"(d)
+ : "m" (__segment_ES) : "cc", "memory");
+ return d1;
+ }
+ // Common case - use 4-byte copy
+ len /= 4;
+ asm volatile(
+ "rep movsl (%%esi),%%es:(%%edi)"
+ : "+c"(len), "+S"(s1), "+D"(d)
+ : "m" (__segment_ES) : "cc", "memory");
+ return d1;
+#else
+ char *d = (char *)d1;
+ char *s = (char *)s1;
+ while (len--)
+ *d++ = *s++;
+ return d1;
+#endif
+}
+
+// Copy to/from memory mapped IO. IO mem is very slow, so yield
+// periodically.
+void
+iomemcpy(void *d, const void *s, u32 len)
+{
+#if CONFIG_X86
+ ASSERT32FLAT();
+ yield();
+ while (len > 3) {
+ u32 copylen = len;
+ if (copylen > 2048)
+ copylen = 2048;
+ copylen /= 4;
+ len -= copylen * 4;
+ asm volatile(
+ "rep movsl (%%esi),%%es:(%%edi)"
+ : "+c"(copylen), "+S"(s), "+D"(d)
+ : : "cc", "memory");
+ yield();
+ }
+ if (len)
+ // Copy any remaining bytes.
+ memcpy(d, s, len);
+#else
+ memcpy(d, s, len);
+#endif
+}
+
+void *
+memmove(void *d, const void *s, size_t len)
+{
+ if (s >= d)
+ return memcpy(d, s, len);
+
+ d += len-1;
+ s += len-1;
+ while (len--) {
+ *(char*)d = *(char*)s;
+ d--;
+ s--;
+ }
+
+ return d;
+}
+
+// Copy a string - truncating it if necessary.
+char *
+strtcpy(char *dest, const char *src, size_t len)
+{
+ char *d = dest;
+ while (--len && *src != '\0')
+ *d++ = *src++;
+ *d = '\0';
+ return dest;
+}
+
+// locate first occurrence of character c in the string s
+char *
+strchr(const char *s, int c)
+{
+ for (; *s; s++)
+ if (*s == c)
+ return (char*)s;
+ return NULL;
+}
+
+// Remove any trailing blank characters (spaces, new lines, carriage returns)
+char *
+nullTrailingSpace(char *buf)
+{
+ int len = strlen(buf);
+ char *end = &buf[len-1];
+ while (end >= buf && *end <= ' ')
+ *(end--) = '\0';
+ while (*buf && *buf <= ' ')
+ buf++;
+ return buf;
+}
diff --git a/roms/seabios-hppa/src/string.h b/roms/seabios-hppa/src/string.h
new file mode 100644
index 000000000..d069989db
--- /dev/null
+++ b/roms/seabios-hppa/src/string.h
@@ -0,0 +1,31 @@
+// String manipulation function defs.
+#ifndef __STRING_H
+#define __STRING_H
+
+#include "types.h" // u32
+
+// string.c
+u8 checksum_far(u16 buf_seg, void *buf_far, u32 len);
+u8 checksum(void *buf, u32 len);
+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);
+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);
+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
+#define memcpy __builtin_memcpy
+#endif
+void iomemcpy(void *d, const void *s, u32 len);
+void *memmove(void *d, const void *s, size_t len);
+char *strtcpy(char *dest, const char *src, size_t len);
+char *strchr(const char *s, int c);
+char *nullTrailingSpace(char *buf);
+
+#endif // string.h
diff --git a/roms/seabios-hppa/src/system.c b/roms/seabios-hppa/src/system.c
new file mode 100644
index 000000000..438e60e2c
--- /dev/null
+++ b/roms/seabios-hppa/src/system.c
@@ -0,0 +1,357 @@
+// Handler for int 0x15 "system" calls
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#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 "output.h" // debug_enter
+#include "string.h" // memcpy_far
+#include "util.h" // handle_1553
+#include "x86.h" // set_a20
+
+static void
+handle_152400(struct bregs *regs)
+{
+ set_a20(0);
+ set_code_success(regs);
+}
+
+static void
+handle_152401(struct bregs *regs)
+{
+ set_a20(1);
+ set_code_success(regs);
+}
+
+static void
+handle_152402(struct bregs *regs)
+{
+ regs->al = get_a20();
+ set_code_success(regs);
+}
+
+static void
+handle_152403(struct bregs *regs)
+{
+ regs->bx = 3;
+ set_code_success(regs);
+}
+
+static void
+handle_1524XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+static void
+handle_1524(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x00: handle_152400(regs); break;
+ case 0x01: handle_152401(regs); break;
+ case 0x02: handle_152402(regs); break;
+ case 0x03: handle_152403(regs); break;
+ default: handle_1524XX(regs); break;
+ }
+}
+
+// removable media eject
+static void
+handle_1552(struct bregs *regs)
+{
+ set_code_success(regs);
+}
+
+static void
+handle_1587(struct bregs *regs)
+{
+ // +++ should probably have descriptor checks
+ // +++ should have exception handlers
+
+ u8 prev_a20_enable = set_a20(1); // enable A20 line
+
+ // 128K max of transfer on 386+ ???
+ // source == destination ???
+
+ // ES:SI points to descriptor table
+ // offset use initially comments
+ // ==============================================
+ // 00..07 Unused zeros Null descriptor
+ // 08..0f GDT zeros filled in by BIOS
+ // 10..17 source ssssssss source of data
+ // 18..1f dest dddddddd destination of data
+ // 20..27 CS zeros filled in by BIOS
+ // 28..2f SS zeros filled in by BIOS
+
+// check for access rights of source & dest here
+
+ // Initialize GDT descriptor
+ u64 *gdt_far = (void*)(regs->si + 0);
+ u16 gdt_seg = regs->es;
+ u32 loc = (u32)MAKE_FLATPTR(gdt_seg, gdt_far);
+ SET_FARVAR(gdt_seg, gdt_far[1], GDT_DATA | GDT_LIMIT((6*sizeof(u64))-1)
+ | GDT_BASE(loc));
+ // Initialize CS descriptor
+ u64 lim = GDT_LIMIT(0x0ffff);
+ if (in_post())
+ lim = GDT_GRANLIMIT(0xffffffff);
+ SET_FARVAR(gdt_seg, gdt_far[4], GDT_CODE | lim | GDT_BASE(BUILD_BIOS_ADDR));
+ // Initialize SS descriptor
+ loc = (u32)MAKE_FLATPTR(GET_SEG(SS), 0);
+ SET_FARVAR(gdt_seg, gdt_far[5], GDT_DATA | lim | GDT_BASE(loc));
+
+ SET_SEG(ES, gdt_seg);
+ u16 count = regs->cx, si = 0, di = 0;
+ asm volatile(
+ // Load new descriptor tables
+ " lgdtw %%es:(1<<3)(%%eax)\n"
+ " lidtw %%cs:pmode_IDT_info\n"
+
+ // Enable protected mode
+ " movl %%cr0, %%eax\n"
+ " orl $" __stringify(CR0_PE) ", %%eax\n"
+ " movl %%eax, %%cr0\n"
+
+ // far jump to flush CPU queue after transition to protected mode
+ " ljmpw $(4<<3), $1f\n"
+
+ // GDT points to valid descriptor table, now load DS, ES
+ "1:movw $(2<<3), %%ax\n" // 2nd descriptor in table, TI=GDT, RPL=00
+ " movw %%ax, %%ds\n"
+ " movw $(3<<3), %%ax\n" // 3rd descriptor in table, TI=GDT, RPL=00
+ " movw %%ax, %%es\n"
+
+ // memcpy CX words using 32bit memcpy if applicable
+ " testw $1, %%cx\n"
+ " jnz 3f\n"
+ " shrw $1, %%cx\n"
+ " rep movsl %%ds:(%%si), %%es:(%%di)\n"
+
+ // Restore DS and ES segment limits to 0xffff
+ "2:movw $(5<<3), %%ax\n" // 5th descriptor in table (SS)
+ " movw %%ax, %%ds\n"
+ " movw %%ax, %%es\n"
+
+ // Disable protected mode
+ " movl %%cr0, %%eax\n"
+ " andl $~" __stringify(CR0_PE) ", %%eax\n"
+ " movl %%eax, %%cr0\n"
+
+ // far jump to flush CPU queue after transition to real mode
+ " ljmpw $" __stringify(SEG_BIOS) ", $4f\n"
+
+ // Slower 16bit copy method
+ "3:rep movsw %%ds:(%%si), %%es:(%%di)\n"
+ " jmp 2b\n"
+
+ // restore IDT to normal real-mode defaults
+ "4:lidtw %%cs:rmode_IDT_info\n"
+
+ // Restore %ds (from %ss)
+ " movw %%ss, %%ax\n"
+ " movw %%ax, %%ds\n"
+ : "+a" (gdt_far), "+c"(count), "+m" (__segment_ES)
+ : "S" (si), "D" (di)
+ : "cc");
+
+ set_a20(prev_a20_enable);
+
+ set_code_success(regs);
+}
+
+// Get the amount of extended memory (above 1M)
+static void
+handle_1588(struct bregs *regs)
+{
+ u32 rs = GET_GLOBAL(LegacyRamSize);
+
+ // According to Ralf Brown's interrupt the limit should be 15M,
+ // but real machines mostly return max. 63M.
+ if (rs > 64*1024*1024)
+ regs->ax = 63 * 1024;
+ else
+ regs->ax = (rs - 1*1024*1024) / 1024;
+ set_success(regs);
+}
+
+// Switch to protected mode
+void VISIBLE16
+handle_1589(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_15);
+ set_a20(1);
+
+ pic_reset(regs->bl, regs->bh);
+
+ u64 *gdt_far = (void*)(regs->si + 0);
+ u16 gdt_seg = regs->es;
+ SET_FARVAR(gdt_seg, gdt_far[7], GDT_CODE | GDT_LIMIT(BUILD_BIOS_SIZE-1)
+ | GDT_BASE(BUILD_BIOS_ADDR));
+
+ regs->ds = 3<<3; // 3rd gdt descriptor is %ds
+ regs->es = 4<<3; // 4th gdt descriptor is %es
+ regs->code.seg = 6<<3; // 6th gdt descriptor is %cs
+
+ set_code_success(regs);
+
+ asm volatile(
+ // Load new descriptor tables
+ " lgdtw %%es:(1<<3)(%%si)\n"
+ " lidtw %%es:(2<<3)(%%si)\n"
+
+ // Enable protected mode
+ " movl %%cr0, %%eax\n"
+ " orl $" __stringify(CR0_PE) ", %%eax\n"
+ " movl %%eax, %%cr0\n"
+
+ // far jump to flush CPU queue after transition to protected mode
+ " ljmpw $(7<<3), $1f\n"
+
+ // GDT points to valid descriptor table, now load SS
+ "1:movw $(5<<3), %%ax\n"
+ " movw %%ax, %%ds\n"
+ " movw %%ax, %%ss\n"
+ :
+ : "S"(gdt_far), "m" (__segment_ES)
+ : "eax", "cc");
+}
+
+// Device busy interrupt. Called by Int 16h when no key available
+static void
+handle_1590(struct bregs *regs)
+{
+}
+
+// Interrupt complete. Called by Int 16h when key becomes available
+static void
+handle_1591(struct bregs *regs)
+{
+}
+
+// keyboard intercept
+static void
+handle_154f(struct bregs *regs)
+{
+ set_invalid_silent(regs);
+}
+
+static void
+handle_15c0(struct bregs *regs)
+{
+ regs->es = SEG_BIOS;
+ regs->bx = (u32)&BIOS_CONFIG_TABLE;
+ set_code_success(regs);
+}
+
+static void
+handle_15c1(struct bregs *regs)
+{
+ regs->es = get_ebda_seg();
+ set_success(regs);
+}
+
+static void
+handle_15e801(struct bregs *regs)
+{
+ // my real system sets ax and bx to 0
+ // this is confirmed by Ralph Brown list
+ // but syslinux v1.48 is known to behave
+ // strangely if ax is set to 0
+ // regs.u.r16.ax = 0;
+ // regs.u.r16.bx = 0;
+
+ u32 rs = GET_GLOBAL(LegacyRamSize);
+
+ // Get the amount of extended memory (above 1M)
+ if (rs > 16*1024*1024) {
+ // limit to 15M
+ regs->cx = 15*1024;
+ // Get the amount of extended memory above 16M in 64k blocks
+ regs->dx = (rs - 16*1024*1024) / (64*1024);
+ } else {
+ regs->cx = (rs - 1*1024*1024) / 1024;
+ regs->dx = 0;
+ }
+
+ // Set configured memory equal to extended memory
+ regs->ax = regs->cx;
+ regs->bx = regs->dx;
+
+ set_success(regs);
+}
+
+static void
+handle_15e820(struct bregs *regs)
+{
+ int count = GET_GLOBAL(e820_count);
+ if (regs->edx != 0x534D4150 || regs->bx >= count
+ || regs->ecx < sizeof(e820_list[0])) {
+ set_code_invalid(regs, RET_EUNSUPPORTED);
+ return;
+ }
+
+ memcpy_far(regs->es, (void*)(regs->di+0)
+ , get_global_seg(), &e820_list[regs->bx]
+ , sizeof(e820_list[0]));
+ if (regs->bx == count-1)
+ regs->ebx = 0;
+ else
+ regs->ebx++;
+ regs->eax = 0x534D4150;
+ regs->ecx = sizeof(e820_list[0]);
+ set_success(regs);
+}
+
+static void
+handle_15e8XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+static void
+handle_15e8(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x01: handle_15e801(regs); break;
+ case 0x20: handle_15e820(regs); break;
+ default: handle_15e8XX(regs); break;
+ }
+}
+
+static void
+handle_15XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+// INT 15h System Services Entry Point
+void VISIBLE16
+handle_15(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_15);
+ switch (regs->ah) {
+ case 0x24: handle_1524(regs); break;
+ case 0x4f: handle_154f(regs); break;
+ case 0x52: handle_1552(regs); break;
+ case 0x53: handle_1553(regs); break;
+ case 0x5f: handle_155f(regs); break;
+ case 0x7f: handle_157f(regs); break;
+ case 0x83: handle_1583(regs); break;
+ case 0x86: handle_1586(regs); break;
+ case 0x87: handle_1587(regs); break;
+ case 0x88: handle_1588(regs); break;
+ case 0x90: handle_1590(regs); break;
+ case 0x91: handle_1591(regs); break;
+ case 0xc0: handle_15c0(regs); break;
+ case 0xc1: handle_15c1(regs); break;
+ case 0xc2: handle_15c2(regs); break;
+ case 0xe8: handle_15e8(regs); break;
+ default: handle_15XX(regs); break;
+ }
+}
diff --git a/roms/seabios-hppa/src/tcgbios.c b/roms/seabios-hppa/src/tcgbios.c
new file mode 100644
index 000000000..31f4d7b82
--- /dev/null
+++ b/roms/seabios-hppa/src/tcgbios.c
@@ -0,0 +1,2321 @@
+// 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 "bregs.h" // struct bregs
+#include "byteorder.h" // cpu_to_*
+#include "config.h" // CONFIG_TCGBIOS
+#include "farptr.h" // MAKE_FLATPTR
+#include "fw/paravirt.h" // runningOnXen
+#include "hw/tpm_drivers.h" // tpm_drivers[]
+#include "output.h" // dprintf
+#include "sha.h" // sha1, sha256, ...
+#include "std/acpi.h" // RSDP_SIGNATURE, rsdt_descriptor
+#include "std/smbios.h" // struct smbios_entry_point
+#include "std/tcg.h" // TCG_PC_LOGOVERFLOW
+#include "string.h" // checksum
+#include "tcgbios.h"// tpm_*, prototypes
+#include "util.h" // printf, get_keystroke
+#include "stacks.h" // wait_threads, reset
+#include "malloc.h" // malloc_high
+
+
+/****************************************************************
+ * ACPI TCPA table interface
+ ****************************************************************/
+
+struct {
+ /* length of the TCPA log buffer */
+ u32 log_area_minimum_length;
+
+ /* start address of TCPA log buffer */
+ u8 * log_area_start_address;
+
+ /* number of log entries written */
+ u32 entry_count;
+
+ /* address to write next log entry to */
+ u8 * log_area_next_entry;
+
+ /* address of last entry written (need for TCG_StatusCheck) */
+ u8 * log_area_last_entry;
+} tpm_state VARLOW;
+
+static int tpm_set_log_area(u8 *log_area_start_address,
+ u32 log_area_minimum_length)
+{
+ if (!log_area_start_address || !log_area_minimum_length)
+ return -1;
+
+ memset(log_area_start_address, 0, log_area_minimum_length);
+ tpm_state.log_area_start_address = log_area_start_address;
+ tpm_state.log_area_minimum_length = log_area_minimum_length;
+ tpm_state.log_area_next_entry = log_area_start_address;
+ tpm_state.log_area_last_entry = NULL;
+ tpm_state.entry_count = 0;
+ return 0;
+}
+
+static int
+tpm_tcpa_probe(void)
+{
+ struct tcpa_descriptor_rev2 *tcpa = find_acpi_table(TCPA_SIGNATURE);
+ if (!tcpa)
+ return -1;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: TCPA: LASA = %p, LAML = %u\n",
+ (u8 *)(long)tcpa->log_area_start_address,
+ tcpa->log_area_minimum_length);
+
+ return tpm_set_log_area((u8*)(long)tcpa->log_area_start_address,
+ tcpa->log_area_minimum_length);
+}
+
+static int
+tpm_tpm2_probe(void)
+{
+ struct tpm2_descriptor_rev2 *tpm2 = find_acpi_table(TPM2_SIGNATURE);
+ if (!tpm2)
+ return -1;
+
+ if (tpm2->length < 76)
+ return -1;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM2: LASA = %p, LAML = %u\n",
+ (u8 *)(long)tpm2->log_area_start_address,
+ tpm2->log_area_minimum_length);
+
+ return tpm_set_log_area((u8*)(long)tpm2->log_area_start_address,
+ tpm2->log_area_minimum_length);
+}
+
+/*
+ * Extend the ACPI log with the given entry by copying the
+ * entry data into the log.
+ * Input
+ * entry : The header data to use (including the variable length digest)
+ * digest_len : Length of the digest in 'entry'
+ * event : Pointer to the event body to be copied into the log
+ * event_len : Length of 'event'
+ *
+ * Output:
+ * Returns an error code in case of faiure, 0 in case of success
+ */
+static int
+tpm_log_event(struct tpm_log_header *entry, int digest_len
+ , const void *event, int event_len)
+{
+ dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
+ tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
+
+ if (tpm_state.log_area_next_entry == NULL)
+ return -1;
+
+ u32 size = (sizeof(*entry) + digest_len
+ + sizeof(struct tpm_log_trailer) + event_len);
+ u32 logsize = (tpm_state.log_area_next_entry + size
+ - tpm_state.log_area_start_address);
+ if (logsize > tpm_state.log_area_minimum_length) {
+ dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
+ return -1;
+ }
+
+ void *dest = tpm_state.log_area_next_entry;
+ memcpy(dest, entry, sizeof(*entry) + digest_len);
+ struct tpm_log_trailer *t = dest + sizeof(*entry) + digest_len;
+ t->eventdatasize = event_len;
+ memcpy(t->event, event, event_len);
+
+ tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
+ tpm_state.log_area_next_entry += size;
+ tpm_state.entry_count++;
+
+ return 0;
+}
+
+
+/****************************************************************
+ * Digest formatting
+ ****************************************************************/
+
+static TPMVersion TPM_version;
+static u32 tpm20_pcr_selection_size;
+static struct tpml_pcr_selection *tpm20_pcr_selection;
+
+// A 'struct tpm_log_entry' is a local data structure containing a
+// 'tpm_log_header' followed by space for the maximum supported
+// digest. (The digest is a sha1 hash on tpm1.2 or a series of
+// tpm2_digest_value structs on tpm2.0)
+struct tpm_log_entry {
+ struct tpm_log_header hdr;
+ u8 pad[sizeof(struct tpm2_digest_values)
+ + 8 * sizeof(struct tpm2_digest_value)
+ + SHA1_BUFSIZE + SHA256_BUFSIZE + SHA384_BUFSIZE
+ + SHA512_BUFSIZE + SM3_256_BUFSIZE + SHA3_256_BUFSIZE
+ + SHA3_384_BUFSIZE + SHA3_512_BUFSIZE];
+} PACKED;
+
+static const struct hash_parameters {
+ u16 hashalg;
+ u8 hashalg_flag;
+ u8 hash_buffersize;
+ const char *name;
+ void (*hashfunc)(const u8 *data, u32 length, u8 *hash);
+} hash_parameters[] = {
+ {
+ .hashalg = TPM2_ALG_SHA1,
+ .hashalg_flag = TPM2_ALG_SHA1_FLAG,
+ .hash_buffersize = SHA1_BUFSIZE,
+ .name = "SHA1",
+ .hashfunc = sha1,
+ }, {
+ .hashalg = TPM2_ALG_SHA256,
+ .hashalg_flag = TPM2_ALG_SHA256_FLAG,
+ .hash_buffersize = SHA256_BUFSIZE,
+ .name = "SHA256",
+ .hashfunc = sha256,
+ }, {
+ .hashalg = TPM2_ALG_SHA384,
+ .hashalg_flag = TPM2_ALG_SHA384_FLAG,
+ .hash_buffersize = SHA384_BUFSIZE,
+ .name = "SHA384",
+ .hashfunc = sha384,
+ }, {
+ .hashalg = TPM2_ALG_SHA512,
+ .hashalg_flag = TPM2_ALG_SHA512_FLAG,
+ .hash_buffersize = SHA512_BUFSIZE,
+ .name = "SHA512",
+ .hashfunc = sha512,
+ }, {
+ .hashalg = TPM2_ALG_SM3_256,
+ .hashalg_flag = TPM2_ALG_SM3_256_FLAG,
+ .hash_buffersize = SM3_256_BUFSIZE,
+ .name = "SM3-256",
+ }, {
+ .hashalg = TPM2_ALG_SHA3_256,
+ .hashalg_flag = TPM2_ALG_SHA3_256_FLAG,
+ .hash_buffersize = SHA3_256_BUFSIZE,
+ .name = "SHA3-256",
+ }, {
+ .hashalg = TPM2_ALG_SHA3_384,
+ .hashalg_flag = TPM2_ALG_SHA3_384_FLAG,
+ .hash_buffersize = SHA3_384_BUFSIZE,
+ .name = "SHA3-384",
+ }, {
+ .hashalg = TPM2_ALG_SHA3_512,
+ .hashalg_flag = TPM2_ALG_SHA3_512_FLAG,
+ .hash_buffersize = SHA3_512_BUFSIZE,
+ .name = "SHA3-512",
+ }
+};
+
+static int
+tpm20_get_hash_buffersize(u16 hashAlg)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
+ if (hash_parameters[i].hashalg == hashAlg)
+ return hash_parameters[i].hash_buffersize;
+ }
+ return -1;
+}
+
+static u8
+tpm20_hashalg_to_flag(u16 hashAlg)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
+ if (hash_parameters[i].hashalg == hashAlg)
+ return hash_parameters[i].hashalg_flag;
+ }
+ return 0;
+}
+
+static u16
+tpm20_hashalg_flag_to_hashalg(u8 hashalg_flag)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
+ if (hash_parameters[i].hashalg_flag == hashalg_flag)
+ return hash_parameters[i].hashalg;
+ }
+ return 0;
+}
+
+static const char *
+tpm20_hashalg_flag_to_name(u8 hashalg_flag)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
+ if (hash_parameters[i].hashalg_flag == hashalg_flag)
+ return hash_parameters[i].name;
+ }
+ return NULL;
+}
+
+static void tpm2_hash_data(u16 hashAlg, const u8 *data, u32 data_len, u8 *hash)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
+ if (hash_parameters[i].hashalg == hashAlg) {
+ if (hash_parameters[i].hashfunc) {
+ hash_parameters[i].hashfunc(data, data_len, hash);
+ } else {
+ memset(hash, 0xff, hash_parameters[i].hash_buffersize);
+ }
+ }
+ }
+}
+
+// Add an entry at the start of the log describing digest formats
+static int
+tpm20_write_EfiSpecIdEventStruct(void)
+{
+ if (!tpm20_pcr_selection)
+ return -1;
+
+ struct {
+ struct TCG_EfiSpecIdEventStruct hdr;
+ u8 pad[sizeof(struct tpm_log_entry) + sizeof(u8)];
+ } event = {
+ .hdr.signature = "Spec ID Event03",
+ .hdr.platformClass = TPM_TCPA_ACPI_CLASS_CLIENT,
+ .hdr.specVersionMinor = 0,
+ .hdr.specVersionMajor = 2,
+ .hdr.specErrata = 2,
+ .hdr.uintnSize = 2,
+ };
+
+ struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
+ void *nsel, *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;
+
+ u32 count, numAlgs = 0;
+ for (count = 0; count < be32_to_cpu(tpm20_pcr_selection->count); count++) {
+ u8 sizeOfSelect = sel->sizeOfSelect;
+
+ nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
+ if (nsel > end)
+ break;
+
+ if (!sizeOfSelect || sel->pcrSelect[0] == 0) {
+ sel = nsel;
+ continue;
+ }
+
+ int hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg));
+ if (hsize < 0) {
+ dprintf(DEBUG_tcg, "TPM is using an unsupported hash: %d\n",
+ be16_to_cpu(sel->hashAlg));
+ return -1;
+ }
+
+ int event_size = offsetof(struct TCG_EfiSpecIdEventStruct
+ , digestSizes[count+1]);
+ if (event_size > sizeof(event) - sizeof(u8)) {
+ dprintf(DEBUG_tcg, "EfiSpecIdEventStruct pad too small\n");
+ return -1;
+ }
+
+ event.hdr.digestSizes[numAlgs].algorithmId = be16_to_cpu(sel->hashAlg);
+ event.hdr.digestSizes[numAlgs].digestSize = hsize;
+ numAlgs++;
+
+ sel = nsel;
+ }
+
+ if (sel != end) {
+ dprintf(DEBUG_tcg, "Malformed pcr selection structure fron TPM\n");
+ return -1;
+ }
+
+ event.hdr.numberOfAlgorithms = numAlgs;
+ int event_size = offsetof(struct TCG_EfiSpecIdEventStruct
+ , digestSizes[numAlgs]);
+ u8 *vendorInfoSize = (void*)&event + event_size;
+ *vendorInfoSize = 0;
+ event_size += sizeof(*vendorInfoSize);
+
+ struct tpm_log_entry le = {
+ .hdr.eventtype = EV_NO_ACTION,
+ };
+ return tpm_log_event(&le.hdr, SHA1_BUFSIZE, &event, event_size);
+}
+
+/*
+ * Build the TPM2 tpm2_digest_values data structure from the given hash.
+ * Follow the PCR bank configuration of the TPM and write the same hash
+ * in either truncated or zero-padded form in the areas of all the other
+ * hashes. For example, write the sha1 hash in the area of the sha256
+ * hash and fill the remaining bytes with zeros. Or truncate the sha256
+ * hash when writing it in the area of the sha1 hash.
+ *
+ * le: the log entry to build the digest in
+ * hashdata: the data to hash
+ * hashdata_len: the length of the hashdata
+ * bigEndian: whether to build in big endian format for the TPM or
+ * little endian for the log
+ *
+ * Returns the digest size; -1 on fatal error
+ */
+static int
+tpm20_build_digest(struct tpm_log_entry *le,
+ const u8 *hashdata, u32 hashdata_len, int bigEndian)
+{
+ if (!tpm20_pcr_selection)
+ return -1;
+
+ struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
+ void *nsel, *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;
+ void *dest = le->hdr.digest + sizeof(struct tpm2_digest_values);
+
+ u32 count, numAlgs = 0;
+ for (count = 0; count < be32_to_cpu(tpm20_pcr_selection->count); count++) {
+ u8 sizeOfSelect = sel->sizeOfSelect;
+
+ nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
+ if (nsel > end)
+ break;
+
+ /* PCR 0-7 unused? -- skip */
+ if (!sizeOfSelect || sel->pcrSelect[0] == 0) {
+ sel = nsel;
+ continue;
+ }
+
+ int hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg));
+ if (hsize < 0) {
+ dprintf(DEBUG_tcg, "TPM is using an unsupported hash: %d\n",
+ be16_to_cpu(sel->hashAlg));
+ return -1;
+ }
+
+ /* buffer size sanity check before writing */
+ struct tpm2_digest_value *v = dest;
+ if (dest + sizeof(*v) + hsize > (void*)le + sizeof(*le)) {
+ dprintf(DEBUG_tcg, "tpm_log_entry is too small\n");
+ return -1;
+ }
+
+ if (bigEndian)
+ v->hashAlg = sel->hashAlg;
+ else
+ v->hashAlg = be16_to_cpu(sel->hashAlg);
+
+ tpm2_hash_data(be16_to_cpu(sel->hashAlg), hashdata, hashdata_len,
+ v->hash);
+
+ dest += sizeof(*v) + hsize;
+ sel = nsel;
+
+ numAlgs++;
+ }
+
+ if (sel != end) {
+ dprintf(DEBUG_tcg, "Malformed pcr selection structure fron TPM\n");
+ return -1;
+ }
+
+ struct tpm2_digest_values *v = (void*)le->hdr.digest;
+ if (bigEndian)
+ v->count = cpu_to_be32(numAlgs);
+ else
+ v->count = numAlgs;
+
+ return dest - (void*)le->hdr.digest;
+}
+
+static int
+tpm12_build_digest(struct tpm_log_entry *le,
+ const u8 *hashdata, u32 hashdata_len)
+{
+ sha1(hashdata, hashdata_len, le->hdr.digest);
+ return SHA1_BUFSIZE;
+}
+
+static int
+tpm12_build_digest_direct(struct tpm_log_entry *le, const u8 *sha1)
+{
+ // On TPM 1.2 the digest contains just the SHA1 hash
+ memcpy(le->hdr.digest, sha1, SHA1_BUFSIZE);
+ return SHA1_BUFSIZE;
+}
+
+static int
+tpm_build_digest(struct tpm_log_entry *le, const u8 *hashdata, u32 hashdata_len
+ , int bigEndian)
+{
+ switch (TPM_version) {
+ case TPM_VERSION_1_2:
+ return tpm12_build_digest(le, hashdata, hashdata_len);
+ case TPM_VERSION_2:
+ return tpm20_build_digest(le, hashdata, hashdata_len, bigEndian);
+ }
+ return -1;
+}
+
+
+/****************************************************************
+ * TPM hardware command wrappers
+ ****************************************************************/
+
+// Helper function for sending tpm commands that take a single
+// optional parameter (0, 1, or 2 bytes) and have no special response.
+static int
+tpm_simple_cmd(u8 locty, u32 ordinal
+ , int param_size, u16 param, enum tpmDurationType to_t)
+{
+ struct {
+ struct tpm_req_header trqh;
+ u16 param;
+ } PACKED req = {
+ .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + param_size),
+ .trqh.ordinal = cpu_to_be32(ordinal),
+ .param = param_size == 2 ? cpu_to_be16(param) : param,
+ };
+ switch (TPM_version) {
+ case TPM_VERSION_1_2:
+ req.trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD);
+ break;
+ case TPM_VERSION_2:
+ req.trqh.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
+ break;
+ }
+
+ u8 obuffer[64];
+ struct tpm_rsp_header *trsh = (void*)obuffer;
+ u32 obuffer_len = sizeof(obuffer);
+ memset(obuffer, 0x0, sizeof(obuffer));
+
+ int ret = tpmhw_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
+ ret = ret ? -1 : be32_to_cpu(trsh->errcode);
+ dprintf(DEBUG_tcg, "Return from tpm_simple_cmd(%x, %x) = %x\n",
+ ordinal, param, ret);
+ return ret;
+}
+
+static int
+tpm20_getcapability(u32 capability, u32 property, u32 count,
+ struct tpm_rsp_header *rsp, u32 rsize)
+{
+ struct tpm2_req_getcapability trg = {
+ .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+ .hdr.totlen = cpu_to_be32(sizeof(trg)),
+ .hdr.ordinal = cpu_to_be32(TPM2_CC_GetCapability),
+ .capability = cpu_to_be32(capability),
+ .property = cpu_to_be32(property),
+ .propertycount = cpu_to_be32(count),
+ };
+
+ u32 resp_size = rsize;
+ int ret = tpmhw_transmit(0, &trg.hdr, rsp, &resp_size,
+ TPM_DURATION_TYPE_SHORT);
+ ret = (ret ||
+ rsize < be32_to_cpu(rsp->totlen)) ? -1 : be32_to_cpu(rsp->errcode);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetCapability = 0x%08x\n",
+ ret);
+
+ return ret;
+}
+
+static int
+tpm20_get_pcrbanks(void)
+{
+ u8 buffer[128];
+ struct tpm2_res_getcapability *trg =
+ (struct tpm2_res_getcapability *)&buffer;
+
+ int ret = tpm20_getcapability(TPM2_CAP_PCRS, 0, 8, &trg->hdr,
+ sizeof(buffer));
+ if (ret)
+ return ret;
+
+ /* defend against (broken) TPM sending packets that are too short */
+ u32 resplen = be32_to_cpu(trg->hdr.totlen);
+ if (resplen <= offsetof(struct tpm2_res_getcapability, data))
+ return -1;
+
+ u32 size = resplen - offsetof(struct tpm2_res_getcapability, data);
+ /* we need a valid tpml_pcr_selection up to and including sizeOfSelect */
+ if (size < offsetof(struct tpml_pcr_selection, selections) +
+ offsetof(struct tpms_pcr_selection, pcrSelect))
+ return -1;
+
+ tpm20_pcr_selection = malloc_high(size);
+ if (tpm20_pcr_selection) {
+ memcpy(tpm20_pcr_selection, &trg->data, size);
+ tpm20_pcr_selection_size = size;
+ } else {
+ warn_noalloc();
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static int
+tpm20_get_suppt_pcrbanks(u8 *suppt_pcrbanks, u8 *active_pcrbanks)
+{
+ *suppt_pcrbanks = 0;
+ *active_pcrbanks = 0;
+
+ if (!tpm20_pcr_selection)
+ return -1;
+
+ struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
+ void *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;
+
+ while (1) {
+ u8 sizeOfSelect = sel->sizeOfSelect;
+ void *nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
+ if (nsel > end)
+ return 0;
+
+ u16 hashalg = be16_to_cpu(sel->hashAlg);
+ u8 hashalg_flag = tpm20_hashalg_to_flag(hashalg);
+
+ *suppt_pcrbanks |= hashalg_flag;
+
+ unsigned i;
+ for (i = 0; i < sizeOfSelect; i++) {
+ if (sel->pcrSelect[i]) {
+ *active_pcrbanks |= hashalg_flag;
+ break;
+ }
+ }
+
+ sel = nsel;
+ }
+}
+
+static int
+tpm20_set_pcrbanks(u32 active_banks)
+{
+ struct tpm2_req_pcr_allocate trpa = {
+ .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
+ .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Allocate),
+ .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
+ .authblocksize = cpu_to_be32(sizeof(trpa.authblock)),
+ .authblock = {
+ .handle = cpu_to_be32(TPM2_RS_PW),
+ .noncesize = cpu_to_be16(0),
+ .contsession = TPM2_YES,
+ .pwdsize = cpu_to_be16(0),
+ },
+ };
+ struct tpms_pcr_selection3 {
+ u16 hashAlg;
+ u8 sizeOfSelect;
+ u8 pcrSelect[3];
+ } tps[ARRAY_SIZE(trpa.tpms_pcr_selections)];
+ int i = 0;
+ u8 hashalg_flag = TPM2_ALG_SHA1_FLAG;
+ u8 dontcare, suppt_banks;
+
+ tpm20_get_suppt_pcrbanks(&suppt_banks, &dontcare);
+
+ while (hashalg_flag) {
+ if ((hashalg_flag & suppt_banks)) {
+ u16 hashalg = tpm20_hashalg_flag_to_hashalg(hashalg_flag);
+
+ if (hashalg) {
+ u8 mask = 0;
+ tps[i].hashAlg = cpu_to_be16(hashalg);
+ tps[i].sizeOfSelect = 3;
+
+ if (active_banks & hashalg_flag)
+ mask = 0xff;
+
+ tps[i].pcrSelect[0] = mask;
+ tps[i].pcrSelect[1] = mask;
+ tps[i].pcrSelect[2] = mask;
+ i++;
+ }
+ }
+ hashalg_flag <<= 1;
+ }
+
+ trpa.count = cpu_to_be32(i);
+ memcpy(trpa.tpms_pcr_selections, tps, i * sizeof(tps[0]));
+ trpa.hdr.totlen = cpu_to_be32(offsetof(struct tpm2_req_pcr_allocate,
+ tpms_pcr_selections) +
+ i * sizeof(tps[0]));
+
+ struct tpm_rsp_header rsp;
+ u32 resp_length = sizeof(rsp);
+
+ int ret = tpmhw_transmit(0, &trpa.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_SHORT);
+ ret = ret ? -1 : be32_to_cpu(rsp.errcode);
+
+ return ret;
+}
+
+static int tpm20_activate_pcrbanks(u32 active_banks)
+{
+ int ret = tpm20_set_pcrbanks(active_banks);
+ if (!ret)
+ ret = tpm_simple_cmd(0, TPM2_CC_Shutdown,
+ 2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT);
+ if (!ret)
+ reset();
+ return ret;
+}
+
+static int
+tpm12_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
+{
+ struct tpm_req_getcap trgc = {
+ .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
+ .hdr.totlen = cpu_to_be32(sizeof(trgc)),
+ .hdr.ordinal = cpu_to_be32(TPM_ORD_GetCapability),
+ .capArea = cpu_to_be32(cap),
+ .subCapSize = cpu_to_be32(sizeof(trgc.subCap)),
+ .subCap = cpu_to_be32(subcap)
+ };
+ u32 resp_size = rsize;
+ int ret = tpmhw_transmit(0, &trgc.hdr, rsp, &resp_size,
+ TPM_DURATION_TYPE_SHORT);
+ ret = (ret || resp_size != rsize) ? -1 : be32_to_cpu(rsp->errcode);
+ dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(%d, %d)"
+ " = %x\n", cap, subcap, ret);
+ return ret;
+}
+
+static int
+tpm12_read_permanent_flags(char *buf, int buf_len)
+{
+ memset(buf, 0, buf_len);
+
+ struct tpm_res_getcap_perm_flags pf;
+ int ret = tpm12_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT
+ , &pf.hdr, sizeof(pf));
+ if (ret)
+ return -1;
+
+ memcpy(buf, &pf.perm_flags, buf_len);
+
+ return 0;
+}
+
+static int
+tpm12_determine_timeouts(void)
+{
+ struct tpm_res_getcap_timeouts timeouts;
+ int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT
+ , &timeouts.hdr, sizeof(timeouts));
+ if (ret)
+ return ret;
+
+ struct tpm_res_getcap_durations durations;
+ ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION
+ , &durations.hdr, sizeof(durations));
+ if (ret)
+ return ret;
+
+ int i;
+ 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]);
+
+ tpmhw_set_timeouts(timeouts.timeouts, durations.durations);
+
+ return 0;
+}
+
+static void
+tpm20_set_timeouts(void)
+{
+ u32 durations[3] = {
+ TPM2_DEFAULT_DURATION_SHORT,
+ TPM2_DEFAULT_DURATION_MEDIUM,
+ TPM2_DEFAULT_DURATION_LONG,
+ };
+ u32 timeouts[4] = {
+ TIS2_DEFAULT_TIMEOUT_A,
+ TIS2_DEFAULT_TIMEOUT_B,
+ TIS2_DEFAULT_TIMEOUT_C,
+ TIS2_DEFAULT_TIMEOUT_D,
+ };
+
+ tpmhw_set_timeouts(timeouts, durations);
+}
+
+static int
+tpm12_extend(struct tpm_log_entry *le, int digest_len)
+{
+ struct tpm_req_extend tre = {
+ .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
+ .hdr.totlen = cpu_to_be32(sizeof(tre)),
+ .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend),
+ .pcrindex = cpu_to_be32(le->hdr.pcrindex),
+ };
+ memcpy(tre.digest, le->hdr.digest, sizeof(tre.digest));
+
+ struct tpm_rsp_extend rsp;
+ u32 resp_length = sizeof(rsp);
+ int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_SHORT);
+ if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
+ return -1;
+
+ return 0;
+}
+
+static int tpm20_extend(struct tpm_log_entry *le, int digest_len)
+{
+ struct tpm2_req_extend tmp_tre = {
+ .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
+ .hdr.totlen = cpu_to_be32(0),
+ .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend),
+ .pcrindex = cpu_to_be32(le->hdr.pcrindex),
+ .authblocksize = cpu_to_be32(sizeof(tmp_tre.authblock)),
+ .authblock = {
+ .handle = cpu_to_be32(TPM2_RS_PW),
+ .noncesize = cpu_to_be16(0),
+ .contsession = TPM2_YES,
+ .pwdsize = cpu_to_be16(0),
+ },
+ };
+ u8 buffer[sizeof(tmp_tre) + sizeof(le->pad)];
+ struct tpm2_req_extend *tre = (struct tpm2_req_extend *)buffer;
+
+ memcpy(tre, &tmp_tre, sizeof(tmp_tre));
+ memcpy(&tre->digest[0], le->hdr.digest, digest_len);
+
+ tre->hdr.totlen = cpu_to_be32(sizeof(tmp_tre) + digest_len);
+
+ struct tpm_rsp_header rsp;
+ u32 resp_length = sizeof(rsp);
+ int ret = tpmhw_transmit(0, &tre->hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_SHORT);
+ if (ret || resp_length != sizeof(rsp) || rsp.errcode)
+ return -1;
+
+ return 0;
+}
+
+static int
+tpm_extend(struct tpm_log_entry *le, int digest_len)
+{
+ switch (TPM_version) {
+ case TPM_VERSION_1_2:
+ return tpm12_extend(le, digest_len);
+ case TPM_VERSION_2:
+ return tpm20_extend(le, digest_len);
+ }
+ return -1;
+}
+
+static int
+tpm20_stirrandom(void)
+{
+ struct tpm2_req_stirrandom stir = {
+ .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+ .hdr.totlen = cpu_to_be32(sizeof(stir)),
+ .hdr.ordinal = cpu_to_be32(TPM2_CC_StirRandom),
+ .size = cpu_to_be16(sizeof(stir.stir)),
+ .stir = rdtscll(),
+ };
+ /* set more bits to stir with */
+ stir.stir += swab64(rdtscll());
+
+ struct tpm_rsp_header rsp;
+ u32 resp_length = sizeof(rsp);
+ int ret = tpmhw_transmit(0, &stir.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_SHORT);
+ if (ret || resp_length != sizeof(rsp) || rsp.errcode)
+ ret = -1;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_StirRandom = 0x%08x\n",
+ ret);
+
+ return ret;
+}
+
+static int
+tpm20_getrandom(u8 *buf, u16 buf_len)
+{
+ struct tpm2_res_getrandom rsp;
+
+ if (buf_len > sizeof(rsp.rnd.buffer))
+ return -1;
+
+ struct tpm2_req_getrandom trgr = {
+ .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+ .hdr.totlen = cpu_to_be32(sizeof(trgr)),
+ .hdr.ordinal = cpu_to_be32(TPM2_CC_GetRandom),
+ .bytesRequested = cpu_to_be16(buf_len),
+ };
+ u32 resp_length = sizeof(rsp);
+
+ int ret = tpmhw_transmit(0, &trgr.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_MEDIUM);
+ if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
+ ret = -1;
+ else
+ memcpy(buf, rsp.rnd.buffer, buf_len);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetRandom = 0x%08x\n",
+ ret);
+
+ return ret;
+}
+
+static int
+tpm20_hierarchycontrol(u32 hierarchy, u8 state)
+{
+ /* we will try to deactivate the TPM now - ignoring all errors */
+ struct tpm2_req_hierarchycontrol trh = {
+ .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
+ .hdr.totlen = cpu_to_be32(sizeof(trh)),
+ .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyControl),
+ .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
+ .authblocksize = cpu_to_be32(sizeof(trh.authblock)),
+ .authblock = {
+ .handle = cpu_to_be32(TPM2_RS_PW),
+ .noncesize = cpu_to_be16(0),
+ .contsession = TPM2_YES,
+ .pwdsize = cpu_to_be16(0),
+ },
+ .enable = cpu_to_be32(hierarchy),
+ .state = state,
+ };
+ struct tpm_rsp_header rsp;
+ u32 resp_length = sizeof(rsp);
+ int ret = tpmhw_transmit(0, &trh.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_MEDIUM);
+ if (ret || resp_length != sizeof(rsp) || rsp.errcode)
+ ret = -1;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyControl = 0x%08x\n",
+ ret);
+
+ return ret;
+}
+
+static int
+tpm20_hierarchychangeauth(u8 auth[20])
+{
+ struct tpm2_req_hierarchychangeauth trhca = {
+ .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
+ .hdr.totlen = cpu_to_be32(sizeof(trhca)),
+ .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyChangeAuth),
+ .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
+ .authblocksize = cpu_to_be32(sizeof(trhca.authblock)),
+ .authblock = {
+ .handle = cpu_to_be32(TPM2_RS_PW),
+ .noncesize = cpu_to_be16(0),
+ .contsession = TPM2_YES,
+ .pwdsize = cpu_to_be16(0),
+ },
+ .newAuth = {
+ .size = cpu_to_be16(sizeof(trhca.newAuth.buffer)),
+ },
+ };
+ memcpy(trhca.newAuth.buffer, auth, sizeof(trhca.newAuth.buffer));
+
+ struct tpm_rsp_header rsp;
+ u32 resp_length = sizeof(rsp);
+ int ret = tpmhw_transmit(0, &trhca.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_MEDIUM);
+ if (ret || resp_length != sizeof(rsp) || rsp.errcode)
+ ret = -1;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyChangeAuth = 0x%08x\n",
+ ret);
+
+ return ret;
+}
+
+
+/****************************************************************
+ * Setup and Measurements
+ ****************************************************************/
+
+static int TPM_has_physical_presence;
+u8 TPM_working VARLOW;
+
+static int
+tpm_is_working(void)
+{
+ return CONFIG_TCGBIOS && TPM_working;
+}
+
+static void
+tpm_set_failure(void)
+{
+ switch (TPM_version) {
+ case TPM_VERSION_1_2:
+ /*
+ * We will try to deactivate the TPM now - ignoring all errors
+ * Physical presence is asserted.
+ */
+
+ tpm_simple_cmd(0, TPM_ORD_SetTempDeactivated,
+ 0, 0, TPM_DURATION_TYPE_SHORT);
+ break;
+ case TPM_VERSION_2:
+ tpm20_hierarchycontrol(TPM2_RH_ENDORSEMENT, TPM2_NO);
+ tpm20_hierarchycontrol(TPM2_RH_OWNER, TPM2_NO);
+ tpm20_hierarchycontrol(TPM2_RH_PLATFORM, TPM2_NO);
+ break;
+ }
+
+ TPM_working = 0;
+}
+
+/*
+ * 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'
+ * event : pointer to info (e.g., string) to be added to log as-is
+ * event_length: length of the event
+ * hashdata : pointer to the data to be hashed
+ * hashdata_length: length of the data to be hashed
+ */
+static void
+tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
+ const char *event, u32 event_length,
+ const u8 *hashdata, u32 hashdata_length)
+{
+ if (!tpm_is_working())
+ return;
+
+ struct tpm_log_entry le = {
+ .hdr.pcrindex = pcrindex,
+ .hdr.eventtype = event_type,
+ };
+ int digest_len = tpm_build_digest(&le, hashdata, hashdata_length, 1);
+ if (digest_len < 0)
+ return;
+ int ret = tpm_extend(&le, digest_len);
+ if (ret) {
+ tpm_set_failure();
+ return;
+ }
+ tpm_build_digest(&le, hashdata, hashdata_length, 0);
+ tpm_log_event(&le.hdr, digest_len, event, event_length);
+}
+
+// Add an EV_ACTION measurement to the list of measurements
+static void
+tpm_add_action(u32 pcrIndex, const char *string)
+{
+ u32 len = strlen(string);
+ tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
+ string, len, (u8 *)string, len);
+}
+
+/*
+ * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
+ */
+static void
+tpm_add_event_separators(void)
+{
+ static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
+ u32 pcrIndex;
+ for (pcrIndex = 0; pcrIndex <= 7; pcrIndex++)
+ tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
+ (const char *)evt_separator,
+ sizeof(evt_separator),
+ evt_separator,
+ sizeof(evt_separator));
+}
+
+static void
+tpm_smbios_measure(void)
+{
+ 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;
+
+ sha1((const u8 *)sep->structure_table_address,
+ sep->structure_table_length, pcctes.digest);
+ tpm_add_measurement_to_log(1,
+ EV_EVENT_TAG,
+ (const char *)&pcctes, sizeof(pcctes),
+ (u8 *)&pcctes, sizeof(pcctes));
+}
+
+static int
+tpm12_assert_physical_presence(void)
+{
+ int ret = tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
+ 2, TPM_PP_PRESENT, TPM_DURATION_TYPE_SHORT);
+ if (!ret)
+ return 0;
+
+ struct tpm_permanent_flags pf;
+ ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
+ if (ret)
+ return -1;
+
+ /* check if hardware physical presence is supported */
+ if (pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE]) {
+ /* HW phys. presence may not be asserted... */
+ return 0;
+ }
+
+ if (!pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK]
+ && !pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE]) {
+ tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
+ 2, TPM_PP_CMD_ENABLE, TPM_DURATION_TYPE_SHORT);
+
+ return tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
+ 2, TPM_PP_PRESENT, TPM_DURATION_TYPE_SHORT);
+ }
+ return -1;
+}
+
+static int
+tpm12_startup(void)
+{
+ dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
+ int ret = tpm_simple_cmd(0, TPM_ORD_Startup,
+ 2, TPM_ST_CLEAR, TPM_DURATION_TYPE_SHORT);
+ if (CONFIG_COREBOOT && ret == TPM_INVALID_POSTINIT)
+ /* with other firmware on the system the TPM may already have been
+ * initialized
+ */
+ ret = 0;
+ if (ret)
+ goto err_exit;
+
+ /* assertion of physical presence is only possible after startup */
+ ret = tpm12_assert_physical_presence();
+ if (!ret)
+ TPM_has_physical_presence = 1;
+
+ ret = tpm12_determine_timeouts();
+ if (ret)
+ goto err_exit;
+
+ ret = tpm_simple_cmd(0, TPM_ORD_SelfTestFull,
+ 0, 0, TPM_DURATION_TYPE_LONG);
+ if (ret)
+ goto err_exit;
+
+ ret = tpm_simple_cmd(3, TSC_ORD_ResetEstablishmentBit,
+ 0, 0, TPM_DURATION_TYPE_SHORT);
+ if (ret && ret != TPM_BAD_LOCALITY)
+ goto err_exit;
+
+ return 0;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_set_failure();
+ return -1;
+}
+
+static int
+tpm20_startup(void)
+{
+ tpm20_set_timeouts();
+
+ int ret = tpm_simple_cmd(0, TPM2_CC_Startup,
+ 2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_CLEAR) = 0x%08x\n",
+ ret);
+
+ if (CONFIG_COREBOOT && ret == TPM2_RC_INITIALIZE)
+ /* with other firmware on the system the TPM may already have been
+ * initialized
+ */
+ ret = 0;
+
+ if (ret)
+ goto err_exit;
+
+ ret = tpm_simple_cmd(0, TPM2_CC_SelfTest,
+ 1, TPM2_YES, TPM_DURATION_TYPE_LONG);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest = 0x%08x\n",
+ ret);
+
+ if (ret)
+ goto err_exit;
+
+ ret = tpm20_get_pcrbanks();
+ if (ret)
+ goto err_exit;
+
+ ret = tpm20_write_EfiSpecIdEventStruct();
+ if (ret)
+ goto err_exit;
+
+ return 0;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_set_failure();
+ return -1;
+}
+
+static int
+tpm_startup(void)
+{
+ switch (TPM_version) {
+ case TPM_VERSION_1_2:
+ return tpm12_startup();
+ case TPM_VERSION_2:
+ return tpm20_startup();
+ }
+ return -1;
+}
+
+void
+tpm_setup(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ int ret = tpm_tpm2_probe();
+ if (ret) {
+ ret = tpm_tcpa_probe();
+ if (ret)
+ return;
+ }
+
+ TPM_version = tpmhw_probe();
+ if (TPM_version == TPM_VERSION_NONE)
+ return;
+
+ dprintf(DEBUG_tcg,
+ "TCGBIOS: Detected a TPM %s.\n",
+ (TPM_version == TPM_VERSION_1_2) ? "1.2" : "2");
+
+ TPM_working = 1;
+
+ if (runningOnXen())
+ return;
+
+ ret = tpm_startup();
+ if (ret)
+ return;
+
+ tpm_smbios_measure();
+ tpm_add_action(2, "Start Option ROM Scan");
+}
+
+static void
+tpm20_prepboot(void)
+{
+ int ret = tpm20_stirrandom();
+ if (ret)
+ goto err_exit;
+
+ u8 auth[20];
+ ret = tpm20_getrandom(&auth[0], sizeof(auth));
+ if (ret)
+ goto err_exit;
+
+ ret = tpm20_hierarchychangeauth(auth);
+ if (ret)
+ goto err_exit;
+
+ return;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_set_failure();
+}
+
+void
+tpm_prepboot(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ switch (TPM_version) {
+ case TPM_VERSION_1_2:
+ if (TPM_has_physical_presence)
+ tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
+ 2, TPM_PP_NOT_PRESENT_LOCK, TPM_DURATION_TYPE_SHORT);
+ break;
+ case TPM_VERSION_2:
+ tpm20_prepboot();
+ break;
+ }
+
+ tpm_add_action(4, "Calling INT 19h");
+ tpm_add_event_separators();
+}
+
+/*
+ * Add measurement to the log about an option rom
+ */
+void
+tpm_option_rom(const void *addr, u32 len)
+{
+ if (!tpm_is_working())
+ return;
+
+ struct pcctes_romex pcctes = {
+ .eventid = 7,
+ .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
+ };
+ sha1((const u8 *)addr, len, pcctes.digest);
+ tpm_add_measurement_to_log(2,
+ EV_EVENT_TAG,
+ (const char *)&pcctes, sizeof(pcctes),
+ (u8 *)&pcctes, sizeof(pcctes));
+}
+
+void
+tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
+{
+ if (!tpm_is_working())
+ return;
+
+ if (length < 0x200)
+ return;
+
+ const char *string = "Booting BCV device 00h (Floppy)";
+ if (bootdrv == 0x80)
+ string = "Booting BCV device 80h (HDD)";
+ tpm_add_action(4, string);
+
+ /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
+ /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
+ string = "MBR";
+ tpm_add_measurement_to_log(4, EV_IPL,
+ string, strlen(string),
+ addr, 0x1b8);
+
+ /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
+ string = "MBR PARTITION_TABLE";
+ tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
+ string, strlen(string),
+ addr + 0x1b8, 0x48);
+}
+
+void
+tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
+{
+ if (!tpm_is_working())
+ return;
+
+ tpm_add_action(4, "Booting from CD ROM device");
+
+ /* specs: see section 'El Torito' */
+ const char *string = "EL TORITO IPL";
+ tpm_add_measurement_to_log(4, EV_IPL,
+ string, strlen(string),
+ addr, length);
+}
+
+void
+tpm_add_cdrom_catalog(const u8 *addr, u32 length)
+{
+ if (!tpm_is_working())
+ return;
+
+ tpm_add_action(4, "Booting from CD ROM device");
+
+ /* specs: see section 'El Torito' */
+ const char *string = "BOOT CATALOG";
+ tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
+ string, strlen(string),
+ addr, length);
+}
+
+void
+tpm_s3_resume(void)
+{
+ if (!tpm_is_working())
+ return;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
+
+ int ret = -1;
+
+ switch (TPM_version) {
+ case TPM_VERSION_1_2:
+ ret = tpm_simple_cmd(0, TPM_ORD_Startup,
+ 2, TPM_ST_STATE, TPM_DURATION_TYPE_SHORT);
+ break;
+ case TPM_VERSION_2:
+ ret = tpm_simple_cmd(0, TPM2_CC_Startup,
+ 2, TPM2_SU_STATE, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_STATE) = 0x%08x\n",
+ ret);
+
+ if (ret)
+ goto err_exit;
+
+
+ ret = tpm_simple_cmd(0, TPM2_CC_SelfTest,
+ 1, TPM2_YES, TPM_DURATION_TYPE_LONG);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest() = 0x%08x\n",
+ ret);
+
+ break;
+ }
+
+ if (ret)
+ goto err_exit;
+
+ return;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_set_failure();
+}
+
+
+/****************************************************************
+ * BIOS interface
+ ****************************************************************/
+
+u8 TPM_interface_shutdown VARLOW;
+
+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);
+}
+
+static u32
+hash_log_extend(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length
+ , void *event, int extend)
+{
+ if (pcpes->pcrindex >= 24)
+ return TCG_INVALID_INPUT_PARA;
+ if (hashdata)
+ sha1(hashdata, hashdata_length, pcpes->digest);
+
+ struct tpm_log_entry le = {
+ .hdr.pcrindex = pcpes->pcrindex,
+ .hdr.eventtype = pcpes->eventtype,
+ };
+ int digest_len = tpm12_build_digest_direct(&le, pcpes->digest);
+ if (digest_len < 0)
+ return TCG_GENERAL_ERROR;
+ if (extend) {
+ int ret = tpm_extend(&le, digest_len);
+ if (ret)
+ return TCG_TCG_COMMAND_ERROR;
+ }
+ tpm12_build_digest_direct(&le, pcpes->digest);
+ int ret = tpm_log_event(&le.hdr, digest_len
+ , pcpes->event, pcpes->eventdatasize);
+ if (ret)
+ return TCG_PC_LOGOVERFLOW;
+ return 0;
+}
+
+static u32
+hash_log_extend_event_int(const struct hleei_short *hleei_s,
+ struct hleeo *hleeo)
+{
+ u32 rc = 0;
+ struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
+ const void *logdataptr;
+ u32 logdatalen;
+ struct pcpes *pcpes;
+ u32 pcrindex;
+
+ /* short or long version? */
+ switch (hleei_s->ipblength) {
+ case sizeof(struct hleei_short):
+ /* short */
+ logdataptr = hleei_s->logdataptr;
+ logdatalen = hleei_s->logdatalen;
+ pcrindex = hleei_s->pcrindex;
+ break;
+
+ case sizeof(struct hleei_long):
+ /* long */
+ logdataptr = hleei_l->logdataptr;
+ logdatalen = hleei_l->logdatalen;
+ pcrindex = hleei_l->pcrindex;
+ break;
+
+ default:
+ /* bad input block */
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+
+ pcpes = (struct pcpes *)logdataptr;
+
+ if (pcpes->pcrindex != pcrindex
+ || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+ rc = hash_log_extend(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen
+ , pcpes->event, 1);
+ if (rc)
+ goto err_exit;
+
+ hleeo->opblength = sizeof(struct hleeo);
+ hleeo->reserved = 0;
+ hleeo->eventnumber = tpm_state.entry_count;
+ memcpy(hleeo->digest, pcpes->digest, sizeof(hleeo->digest));
+
+err_exit:
+ if (rc != 0) {
+ hleeo->opblength = 4;
+ hleeo->reserved = 0;
+ }
+
+ return rc;
+}
+
+static u32
+pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
+{
+ u32 rc = 0;
+ struct tpm_req_header *trh = (void*)pttti->tpmopin;
+
+ if (pttti->ipblength < sizeof(struct pttti) + sizeof(*trh)
+ || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
+ || pttti->opblength < sizeof(struct pttto)) {
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+
+ u16 tag = be16_to_cpu(trh->tag);
+
+ switch (TPM_version) {
+ case TPM_VERSION_1_2:
+ if (tag != TPM_TAG_RQU_CMD && tag != TPM_TAG_RQU_AUTH1_CMD
+ && tag != TPM_TAG_RQU_AUTH2_CMD) {
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+ break;
+ case TPM_VERSION_2:
+ if (tag != TPM2_ST_NO_SESSIONS && tag != TPM2_ST_SESSIONS) {
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+ }
+
+ u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
+ int ret = tpmhw_transmit(0, trh, pttto->tpmopout, &resbuflen,
+ TPM_DURATION_TYPE_LONG /* worst case */);
+ if (ret) {
+ rc = TCG_FATAL_COM_ERROR;
+ 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
+shutdown_preboot_interface(void)
+{
+ TPM_interface_shutdown = 1;
+ return 0;
+}
+
+static u32
+hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
+{
+ u32 rc = 0;
+ u16 size;
+ struct pcpes *pcpes;
+
+ size = hlei->ipblength;
+ if (size != sizeof(*hlei)) {
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+
+ pcpes = (struct pcpes *)hlei->logdataptr;
+
+ if (pcpes->pcrindex != hlei->pcrindex
+ || pcpes->eventtype != hlei->logeventtype
+ || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+ rc = hash_log_extend(pcpes, hlei->hashdataptr, hlei->hashdatalen
+ , pcpes->event, 0);
+ if (rc)
+ goto err_exit;
+
+ /* updating the log was fine */
+ hleo->opblength = sizeof(struct hleo);
+ hleo->reserved = 0;
+ hleo->eventnumber = tpm_state.entry_count;
+
+err_exit:
+ if (rc != 0) {
+ hleo->opblength = 2;
+ hleo->reserved = 0;
+ }
+
+ return rc;
+}
+
+static u32
+hash_all_int(const struct hai *hai, u8 *hash)
+{
+ if (hai->ipblength != sizeof(struct hai) ||
+ hai->hashdataptr == 0 ||
+ hai->hashdatalen == 0 ||
+ hai->algorithmid != TPM_ALG_SHA)
+ return TCG_INVALID_INPUT_PARA;
+
+ sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
+ return 0;
+}
+
+static u32
+tss_int(struct ti *ti, struct to *to)
+{
+ to->opblength = sizeof(struct to);
+ to->reserved = 0;
+
+ return TCG_PC_UNSUPPORTED;
+}
+
+static u32
+compact_hash_log_extend_event_int(u8 *buffer,
+ u32 info,
+ u32 length,
+ u32 pcrindex,
+ u32 *edx_ptr)
+{
+ struct pcpes pcpes = {
+ .pcrindex = pcrindex,
+ .eventtype = EV_COMPACT_HASH,
+ .eventdatasize = sizeof(info),
+ };
+ u32 rc = hash_log_extend(&pcpes, buffer, length, &info, 1);
+ if (rc)
+ return rc;
+
+ *edx_ptr = tpm_state.entry_count;
+ return 0;
+}
+
+void VISIBLE32FLAT
+tpm_interrupt_handler32(struct bregs *regs)
+{
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ set_cf(regs, 0);
+
+ if (TPM_interface_shutdown && regs->al) {
+ regs->eax = TCG_INTERFACE_SHUTDOWN;
+ return;
+ }
+
+ switch ((enum irq_ids)regs->al) {
+ case TCG_StatusCheck:
+ if (!tpmhw_is_present()) {
+ /* 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)tpm_state.log_area_start_address;
+ regs->edi = (u32)tpm_state.log_area_last_entry;
+ }
+ break;
+
+ case TCG_HashLogExtendEvent:
+ regs->eax =
+ hash_log_extend_event_int(
+ (struct hleei_short *)input_buf32(regs),
+ (struct hleeo *)output_buf32(regs));
+ break;
+
+ case TCG_PassThroughToTPM:
+ regs->eax =
+ pass_through_to_tpm_int((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_int((struct hlei*)input_buf32(regs),
+ (struct hleo*)output_buf32(regs));
+ break;
+
+ case TCG_HashAll:
+ regs->eax =
+ hash_all_int((struct hai*)input_buf32(regs),
+ (u8 *)output_buf32(regs));
+ break;
+
+ case TCG_TSS:
+ regs->eax = tss_int((struct ti*)input_buf32(regs),
+ (struct to*)output_buf32(regs));
+ break;
+
+ case TCG_CompactHashLogExtendEvent:
+ regs->eax =
+ compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
+ regs->esi,
+ regs->ecx,
+ regs->edx,
+ &regs->edx);
+ break;
+
+ default:
+ set_cf(regs, 1);
+ }
+
+ return;
+}
+
+
+/****************************************************************
+ * TPM Configuration Menu
+ ****************************************************************/
+
+typedef u8 tpm_ppi_code;
+
+static int
+tpm12_read_has_owner(int *has_owner)
+{
+ struct tpm_res_getcap_ownerauth oauth;
+ int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_OWNER
+ , &oauth.hdr, sizeof(oauth));
+ if (ret)
+ return -1;
+
+ *has_owner = oauth.flag;
+
+ return 0;
+}
+
+static int
+tpm12_enable_tpm(int enable, int verbose)
+{
+ struct tpm_permanent_flags pf;
+ int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
+ if (ret)
+ return -1;
+
+ if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable)
+ return 0;
+
+ ret = tpm_simple_cmd(0, enable ? TPM_ORD_PhysicalEnable
+ : TPM_ORD_PhysicalDisable,
+ 0, 0, TPM_DURATION_TYPE_SHORT);
+ if (ret) {
+ if (enable)
+ dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
+ else
+ dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
+ }
+ return ret;
+}
+
+static int
+tpm12_activate_tpm(int activate, int allow_reset, int verbose)
+{
+ struct tpm_permanent_flags pf;
+ int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
+ if (ret)
+ return -1;
+
+ if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate)
+ return 0;
+
+ if (pf.flags[PERM_FLAG_IDX_DISABLE])
+ return 0;
+
+ ret = tpm_simple_cmd(0, TPM_ORD_PhysicalSetDeactivated,
+ 1, activate ? 0x00 : 0x01, TPM_DURATION_TYPE_SHORT);
+ if (ret)
+ return ret;
+
+ if (activate && allow_reset) {
+ if (verbose) {
+ printf("Requiring a reboot to activate the TPM.\n");
+
+ msleep(2000);
+ }
+ reset();
+ }
+
+ return 0;
+}
+
+static int
+tpm12_enable_activate(int allow_reset, int verbose)
+{
+ int ret = tpm12_enable_tpm(1, verbose);
+ if (ret)
+ return ret;
+
+ return tpm12_activate_tpm(1, allow_reset, verbose);
+}
+
+static int
+tpm12_force_clear(int enable_activate_before, int enable_activate_after,
+ int verbose)
+{
+ int has_owner;
+ int ret = tpm12_read_has_owner(&has_owner);
+ if (ret)
+ return -1;
+ if (!has_owner) {
+ if (verbose)
+ printf("TPM does not have an owner.\n");
+ return 0;
+ }
+
+ if (enable_activate_before) {
+ ret = tpm12_enable_activate(0, verbose);
+ if (ret) {
+ dprintf(DEBUG_tcg,
+ "TCGBIOS: Enabling/activating the TPM failed.\n");
+ return ret;
+ }
+ }
+
+ ret = tpm_simple_cmd(0, TPM_ORD_ForceClear,
+ 0, 0, TPM_DURATION_TYPE_SHORT);
+ if (ret)
+ return ret;
+
+ if (!enable_activate_after) {
+ if (verbose)
+ printf("Owner successfully cleared.\n"
+ "You will need to enable/activate the TPM again.\n\n");
+ return 0;
+ }
+
+ return tpm12_enable_activate(1, verbose);
+}
+
+static int
+tpm12_set_owner_install(int allow, int verbose)
+{
+ int has_owner;
+ int ret = tpm12_read_has_owner(&has_owner);
+ if (ret)
+ return -1;
+ if (has_owner) {
+ if (verbose)
+ printf("Must first remove owner.\n");
+ return 0;
+ }
+
+ struct tpm_permanent_flags pf;
+ ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
+ if (ret)
+ return -1;
+
+ if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
+ if (verbose)
+ printf("TPM must first be enable.\n");
+ return 0;
+ }
+
+ ret = tpm_simple_cmd(0, TPM_ORD_SetOwnerInstall,
+ 1, allow ? 0x01 : 0x00, TPM_DURATION_TYPE_SHORT);
+ if (ret)
+ return ret;
+
+ if (verbose)
+ printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
+
+ return 0;
+}
+
+static int
+tpm12_process_cfg(tpm_ppi_code msgCode, int verbose)
+{
+ int ret = 0;
+
+ switch (msgCode) {
+ case TPM_PPI_OP_NOOP: /* no-op */
+ break;
+
+ case TPM_PPI_OP_ENABLE:
+ ret = tpm12_enable_tpm(1, verbose);
+ break;
+
+ case TPM_PPI_OP_DISABLE:
+ ret = tpm12_enable_tpm(0, verbose);
+ break;
+
+ case TPM_PPI_OP_ACTIVATE:
+ ret = tpm12_activate_tpm(1, 1, verbose);
+ break;
+
+ case TPM_PPI_OP_DEACTIVATE:
+ ret = tpm12_activate_tpm(0, 1, verbose);
+ break;
+
+ case TPM_PPI_OP_CLEAR:
+ ret = tpm12_force_clear(1, 0, verbose);
+ break;
+
+ case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
+ ret = tpm12_set_owner_install(1, verbose);
+ break;
+
+ case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
+ ret = tpm12_set_owner_install(0, verbose);
+ break;
+
+ default:
+ break;
+ }
+
+ if (ret)
+ printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
+
+ return ret;
+}
+
+static int
+tpm20_clearcontrol(u8 disable, int verbose)
+{
+ struct tpm2_req_clearcontrol trc = {
+ .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
+ .hdr.totlen = cpu_to_be32(sizeof(trc)),
+ .hdr.ordinal = cpu_to_be32(TPM2_CC_ClearControl),
+ .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
+ .authblocksize = cpu_to_be32(sizeof(trc.authblock)),
+ .authblock = {
+ .handle = cpu_to_be32(TPM2_RS_PW),
+ .noncesize = cpu_to_be16(0),
+ .contsession = TPM2_YES,
+ .pwdsize = cpu_to_be16(0),
+ },
+ .disable = disable,
+ };
+ struct tpm_rsp_header rsp;
+ u32 resp_length = sizeof(rsp);
+ int ret = tpmhw_transmit(0, &trc.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_SHORT);
+ if (ret || resp_length != sizeof(rsp) || rsp.errcode)
+ ret = -1;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_ClearControl = 0x%08x\n",
+ ret);
+
+ return ret;
+}
+
+static int
+tpm20_clear(void)
+{
+ struct tpm2_req_clear trq = {
+ .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
+ .hdr.totlen = cpu_to_be32(sizeof(trq)),
+ .hdr.ordinal = cpu_to_be32(TPM2_CC_Clear),
+ .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
+ .authblocksize = cpu_to_be32(sizeof(trq.authblock)),
+ .authblock = {
+ .handle = cpu_to_be32(TPM2_RS_PW),
+ .noncesize = cpu_to_be16(0),
+ .contsession = TPM2_YES,
+ .pwdsize = cpu_to_be16(0),
+ },
+ };
+ struct tpm_rsp_header rsp;
+ u32 resp_length = sizeof(rsp);
+ int ret = tpmhw_transmit(0, &trq.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_MEDIUM);
+ if (ret || resp_length != sizeof(rsp) || rsp.errcode)
+ ret = -1;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Clear = 0x%08x\n",
+ ret);
+
+ return ret;
+}
+
+static int
+tpm20_process_cfg(tpm_ppi_code msgCode, int verbose)
+{
+ int ret = 0;
+
+ switch (msgCode) {
+ case TPM_PPI_OP_NOOP: /* no-op */
+ break;
+
+ case TPM_PPI_OP_CLEAR:
+ ret = tpm20_clearcontrol(0, verbose);
+ if (!ret)
+ ret = tpm20_clear();
+ break;
+ }
+
+ if (ret)
+ printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
+
+ return ret;
+}
+
+static int
+tpm12_get_tpm_state(void)
+{
+ int state = 0;
+ struct tpm_permanent_flags pf;
+ int has_owner;
+
+ if (tpm12_read_permanent_flags((char *)&pf, sizeof(pf)) ||
+ tpm12_read_has_owner(&has_owner))
+ return ~0;
+
+ if (!pf.flags[PERM_FLAG_IDX_DISABLE])
+ state |= TPM_STATE_ENABLED;
+
+ if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED])
+ state |= TPM_STATE_ACTIVE;
+
+ if (has_owner) {
+ state |= TPM_STATE_OWNED;
+ } else {
+ if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
+ state |= TPM_STATE_OWNERINSTALL;
+ }
+
+ return state;
+}
+
+static void
+tpm12_show_tpm_menu(int state, int next_scancodes[7])
+{
+ int i = 0;
+
+ printf("\nThe current state of the TPM is:\n");
+
+ if (state & TPM_STATE_ENABLED)
+ printf(" Enabled");
+ else
+ printf(" Disabled");
+
+ if (state & TPM_STATE_ACTIVE)
+ printf(" and active\n");
+ else
+ printf(" and deactivated\n");
+
+ if (state & TPM_STATE_OWNED)
+ printf(" Ownership has been taken\n");
+ else {
+ printf(" Ownership has not been taken\n");
+ if (state & TPM_STATE_OWNERINSTALL)
+ printf(" A user can take ownership of the TPM\n");
+ else
+ printf(" Taking ownership of the TPM has been disabled\n");
+ }
+
+ if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) !=
+ (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) {
+ printf("\nNote: To make use of all functionality, the TPM must be "
+ "enabled and active.\n");
+ }
+
+ printf("\nAvailable options are:\n");
+ if (state & TPM_STATE_ENABLED) {
+ printf(" d. Disable the TPM\n");
+ next_scancodes[i++] = 32;
+
+ if (state & TPM_STATE_ACTIVE) {
+ printf(" v. Deactivate the TPM\n");
+ next_scancodes[i++] = 47;
+
+ if (state & TPM_STATE_OWNERINSTALL) {
+ printf(" p. Prevent installation of an owner\n");
+ next_scancodes[i++] = 25;
+ } else {
+ printf(" s. Allow installation of an owner\n");
+ next_scancodes[i++] = 31;
+ }
+ } else {
+ printf(" a. Activate the TPM\n");
+ next_scancodes[i++] = 30;
+ }
+
+ } else {
+ printf(" e. Enable the TPM\n");
+ next_scancodes[i++] = 18;
+ }
+
+ if (state & TPM_STATE_OWNED) {
+ printf(" c. Clear ownership\n");
+ next_scancodes[i++] = 46;
+ }
+
+ next_scancodes[i++] = 0;
+}
+
+static void
+tpm12_menu(void)
+{
+ int scancode, next_scancodes[7];
+ tpm_ppi_code msgCode;
+ int state = 0, i;
+ int waitkey;
+
+ printf("The Trusted Platform Module (TPM) is a hardware device in "
+ "this machine.\n"
+ "It can help verify the integrity of system software.\n\n");
+
+ for (;;) {
+ if ((state = tpm12_get_tpm_state()) != ~0) {
+ tpm12_show_tpm_menu(state, next_scancodes);
+ } else {
+ printf("TPM is not working correctly.\n");
+ return;
+ }
+
+ printf("\nIf no change is desired or if this menu was reached by "
+ "mistake, press ESC to\n"
+ "reboot the machine.\n");
+
+ msgCode = TPM_PPI_OP_NOOP;
+
+ waitkey = 1;
+
+ while (waitkey) {
+ while ((scancode = get_keystroke(1000)) == ~0)
+ ;
+
+ switch (scancode) {
+ case 1:
+ // ESC
+ reset();
+ break;
+ case 18: /* e. enable */
+ msgCode = TPM_PPI_OP_ENABLE;
+ break;
+ case 32: /* d. disable */
+ msgCode = TPM_PPI_OP_DISABLE;
+ break;
+ case 30: /* a. activate */
+ msgCode = TPM_PPI_OP_ACTIVATE;
+ break;
+ case 47: /* v. deactivate */
+ msgCode = TPM_PPI_OP_DEACTIVATE;
+ break;
+ case 46: /* c. clear owner */
+ msgCode = TPM_PPI_OP_CLEAR;
+ break;
+ case 25: /* p. prevent ownerinstall */
+ msgCode = TPM_PPI_OP_SET_OWNERINSTALL_FALSE;
+ break;
+ case 31: /* s. allow ownerinstall */
+ msgCode = TPM_PPI_OP_SET_OWNERINSTALL_TRUE;
+ break;
+ default:
+ continue;
+ }
+
+ /*
+ * Using the next_scancodes array, check whether the
+ * pressed key is currently a valid option.
+ */
+ for (i = 0; i < sizeof(next_scancodes); i++) {
+ if (next_scancodes[i] == 0)
+ break;
+
+ if (next_scancodes[i] == scancode) {
+ tpm12_process_cfg(msgCode, 1);
+ waitkey = 0;
+ break;
+ }
+ }
+ }
+ }
+}
+
+static int
+tpm20_menu_change_active_pcrbanks(void)
+{
+ u8 active_banks, suppt_banks;
+
+ tpm20_get_suppt_pcrbanks(&suppt_banks, &active_banks);
+
+ u8 activate_banks = active_banks;
+
+ while (1) {
+ u8 hashalg_flag = TPM2_ALG_SHA1_FLAG;
+ u8 i = 0;
+
+ printf("\nToggle active PCR banks by pressing number key\n\n");
+
+ while (hashalg_flag) {
+ u8 flag = hashalg_flag & suppt_banks;
+ const char *hashname = tpm20_hashalg_flag_to_name(flag);
+
+ i++;
+ if (hashname) {
+ printf(" %d: %s", i, hashname);
+ if (activate_banks & hashalg_flag)
+ printf(" (enabled)");
+ printf("\n");
+ }
+
+ hashalg_flag <<= 1;
+ }
+ printf("\n"
+ "ESC: return to previous menu without changes\n");
+ if (activate_banks)
+ printf("A : activate selection\n");
+
+ u8 flagnum;
+ int show = 0;
+ while (!show) {
+ int scancode = get_keystroke(1000);
+
+ switch (scancode) {
+ case ~0:
+ continue;
+ case 1: /* ESC */
+ printf("\n");
+ return -1;
+ case 2 ... 6: /* keys 1 .. 5 */
+ flagnum = scancode - 1;
+ if (flagnum > i)
+ continue;
+ if (suppt_banks & (1 << (flagnum - 1))) {
+ activate_banks ^= 1 << (flagnum - 1);
+ show = 1;
+ }
+ break;
+ case 30: /* a */
+ if (activate_banks)
+ tpm20_activate_pcrbanks(activate_banks);
+ }
+ }
+ }
+}
+
+static void
+tpm20_menu(void)
+{
+ int scan_code;
+ tpm_ppi_code msgCode;
+
+ for (;;) {
+ printf("1. Clear TPM\n");
+ printf("2. Change active PCR banks\n");
+
+ printf("\nIf no change is desired or if this menu was reached by "
+ "mistake, press ESC to\n"
+ "reboot the machine.\n");
+
+ msgCode = TPM_PPI_OP_NOOP;
+
+ while ((scan_code = get_keystroke(1000)) == ~0)
+ ;
+
+ switch (scan_code) {
+ case 1:
+ // ESC
+ reset();
+ break;
+ case 2:
+ msgCode = TPM_PPI_OP_CLEAR;
+ break;
+ case 3:
+ tpm20_menu_change_active_pcrbanks();
+ continue;
+ default:
+ continue;
+ }
+
+ tpm20_process_cfg(msgCode, 0);
+ }
+}
+
+void
+tpm_menu(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ while (get_keystroke(0) >= 0)
+ ;
+ wait_threads();
+
+ switch (TPM_version) {
+ case TPM_VERSION_1_2:
+ tpm12_menu();
+ break;
+ case TPM_VERSION_2:
+ tpm20_menu();
+ break;
+ }
+}
+
+int
+tpm_can_show_menu(void)
+{
+ switch (TPM_version) {
+ case TPM_VERSION_1_2:
+ return tpm_is_working() && TPM_has_physical_presence;
+ case TPM_VERSION_2:
+ return tpm_is_working();
+ }
+ return 0;
+}
diff --git a/roms/seabios-hppa/src/tcgbios.h b/roms/seabios-hppa/src/tcgbios.h
new file mode 100644
index 000000000..32fb94171
--- /dev/null
+++ b/roms/seabios-hppa/src/tcgbios.h
@@ -0,0 +1,19 @@
+#ifndef TCGBIOS_H
+#define TCGBIOS_H
+
+#include "types.h"
+
+struct bregs;
+void tpm_interrupt_handler32(struct bregs *regs);
+
+void tpm_setup(void);
+void tpm_prepboot(void);
+void tpm_s3_resume(void);
+void tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length);
+void tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length);
+void tpm_add_cdrom_catalog(const u8 *addr, u32 length);
+void tpm_option_rom(const void *addr, u32 len);
+int tpm_can_show_menu(void);
+void tpm_menu(void);
+
+#endif /* TCGBIOS_H */
diff --git a/roms/seabios-hppa/src/types.h b/roms/seabios-hppa/src/types.h
new file mode 100644
index 000000000..5887ecf5c
--- /dev/null
+++ b/roms/seabios-hppa/src/types.h
@@ -0,0 +1,162 @@
+// Basic type definitions for X86 cpus.
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __TYPES_H
+#define __TYPES_H
+
+typedef unsigned char u8;
+typedef signed char s8;
+typedef unsigned short u16;
+typedef signed short s16;
+typedef unsigned int u32;
+typedef signed int s32;
+typedef unsigned long long u64;
+typedef signed long long s64;
+typedef u32 size_t;
+
+union u64_u32_u {
+ struct { u32 lo, hi; };
+ u64 val;
+};
+
+#if MODE16 == 1
+typedef u16 portaddr_t;
+#else
+typedef unsigned int portaddr_t;
+#endif
+
+// Definition for common 16bit segment/offset pointers.
+struct segoff_s {
+ union {
+ struct {
+ portaddr_t offset;
+ u16 seg;
+ };
+ u32 segoff;
+ };
+};
+
+#ifdef MANUAL_NO_JUMP_TABLE
+# define default case 775324556: asm(""); default
+#endif
+
+#ifdef WHOLE_PROGRAM
+# define __VISIBLE __attribute__((externally_visible))
+#else
+# define __VISIBLE
+#endif
+
+#define UNIQSEC __FILE__ "." __stringify(__LINE__)
+
+#define __noreturn __attribute__((noreturn))
+extern void __force_link_error__only_in_32bit_flat(void) __noreturn;
+extern void __force_link_error__only_in_32bit_segmented(void) __noreturn;
+extern void __force_link_error__only_in_16bit(void) __noreturn;
+
+#define __ASM(code) asm(".section .text.asm." UNIQSEC "\n\t" code)
+
+#if MODE16 == 1
+// Notes a function as externally visible in the 16bit code chunk.
+# define VISIBLE16 __VISIBLE
+// Notes a function as externally visible in the 32bit flat code chunk.
+# define VISIBLE32FLAT
+// Notes a 32bit flat function that will only be called during init.
+# define VISIBLE32INIT
+// Notes a function as externally visible in the 32bit segmented code chunk.
+# define VISIBLE32SEG
+// Designate a variable as (only) visible to 16bit code.
+# define VAR16 __section(".data16." UNIQSEC)
+// Designate a variable as (only) visible to 32bit segmented code.
+# define VAR32SEG __section(".discard.var32seg." UNIQSEC)
+// Designate a variable as visible and located in the e-segment.
+# define VARLOW __section(".discard.varlow." UNIQSEC) __VISIBLE __weak
+// Designate a variable as visible and located in the f-segment.
+# 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 accessible via 32bit "init" functions
+# define VARVERIFY32INIT __section(".discard.varinit." UNIQSEC)
+// Designate top-level assembler as 16bit only.
+# define ASM16(code) __ASM(code)
+// Designate top-level assembler as 32bit flat only.
+# define ASM32FLAT(code)
+// Compile time check for a given mode.
+# define ASSERT16() do { } while (0)
+# define ASSERT32SEG() __force_link_error__only_in_32bit_segmented()
+# define ASSERT32FLAT() __force_link_error__only_in_32bit_flat()
+#elif MODESEGMENT == 1
+# define VISIBLE16
+# define VISIBLE32FLAT
+# define VISIBLE32INIT
+# define VISIBLE32SEG __VISIBLE
+# define VAR16 __section(".discard.var16." UNIQSEC)
+# define VAR32SEG __section(".data32seg." UNIQSEC)
+# define VARLOW __section(".discard.varlow." UNIQSEC) __VISIBLE __weak
+# define VARFSEG __section(".discard.varfseg." UNIQSEC) __VISIBLE __weak
+# define VARFSEGFIXED(addr) __section(".discard.varfixed." UNIQSEC) __VISIBLE __weak
+# define VARVERIFY32INIT __section(".discard.varinit." UNIQSEC)
+# define ASM16(code)
+# define ASM32FLAT(code)
+# define ASSERT16() __force_link_error__only_in_16bit()
+# define ASSERT32SEG() do { } while (0)
+# define ASSERT32FLAT() __force_link_error__only_in_32bit_flat()
+#else
+# define VISIBLE16
+# define VISIBLE32FLAT __section(".text.runtime." UNIQSEC) __VISIBLE
+# define VISIBLE32INIT __section(".text.init." UNIQSEC) __VISIBLE
+# define VISIBLE32SEG
+# define VAR16 __section(".discard.var16." UNIQSEC)
+# define VAR32SEG __section(".discard.var32seg." UNIQSEC)
+# define VARLOW __section(".data.varlow." UNIQSEC) __VISIBLE __weak
+# define VARFSEG __section(".data.varfseg." UNIQSEC) __VISIBLE
+# define VARFSEGFIXED(addr) __section(".fixedaddr." __stringify(addr)) __VISIBLE __aligned(1)
+# define VARVERIFY32INIT __section(".data.varinit." UNIQSEC)
+# define ASM16(code)
+# define ASM32FLAT(code) __ASM(code)
+# define ASSERT16() __force_link_error__only_in_16bit()
+# define ASSERT32SEG() __force_link_error__only_in_32bit_segmented()
+# define ASSERT32FLAT() do { } while (0)
+#endif
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#define DIV_ROUND_CLOSEST(x, divisor)({ \
+ typeof(divisor) __divisor = divisor; \
+ (((x) + ((__divisor) / 2)) / (__divisor)); \
+ })
+#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
+#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
+#define ALIGN_DOWN(x,a) ((x) & ~((typeof(x))(a)-1))
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+#define container_of_or_null(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *___mptr = (ptr); \
+ ___mptr ? container_of(___mptr, type, member) : NULL; })
+
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+
+#define NULL ((void*)0)
+
+#define __weak __attribute__((weak))
+#define __section(S) __attribute__((section(S)))
+
+#define PACKED __attribute__((packed))
+#define __aligned(x) __attribute__((aligned(x)))
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+#define noinline __attribute__((noinline))
+#define __always_inline inline __attribute__((always_inline))
+#define __malloc __attribute__((__malloc__))
+#define __attribute_const __attribute__((__const__))
+
+#define __stringify_1(x) #x
+#define __stringify(x) __stringify_1(x)
+
+#endif // types.h
diff --git a/roms/seabios-hppa/src/util.h b/roms/seabios-hppa/src/util.h
new file mode 100644
index 000000000..0de35229d
--- /dev/null
+++ b/roms/seabios-hppa/src/util.h
@@ -0,0 +1,273 @@
+// Misc function and variable declarations.
+#ifndef __UTIL_H
+#define __UTIL_H
+
+#include "types.h" // u32
+
+// apm.c
+void apm_shutdown(void);
+struct bregs;
+void handle_1553(struct bregs *regs);
+
+// bmp.c
+struct bmp_decdata *bmp_alloc(void);
+int bmp_decode(struct bmp_decdata *bmp, unsigned char *data, int data_size);
+void bmp_get_info(struct bmp_decdata *bmp, int *width, int *height, int *bpp);
+int bmp_show(struct bmp_decdata *bmp, unsigned char *pic, int width
+ , int height, int depth, int bytes_per_line_dest);
+
+// boot.c
+void boot_init(void);
+void boot_add_bev(u16 seg, u16 bev, u16 desc, int prio);
+void boot_add_bcv(u16 seg, u16 ip, u16 desc, int prio);
+struct drive_s;
+void boot_add_floppy(struct drive_s *drive_g, const char *desc, int prio);
+void boot_add_hd(struct drive_s *drive_g, const char *desc, int prio);
+void boot_add_cd(struct drive_s *drive_g, const char *desc, int prio);
+void boot_add_cbfs(void *data, const char *desc, int prio);
+void interactive_bootmenu(void);
+void bcv_prepboot(void);
+u8 is_bootprio_strict(void);
+struct pci_device;
+int bootprio_find_pci_device(struct pci_device *pci);
+int bootprio_find_mmio_device(void *mmio);
+int bootprio_find_scsi_device(struct pci_device *pci, int target, int lun);
+int bootprio_find_scsi_mmio_device(void *mmio, int target, int lun);
+int bootprio_find_ata_device(struct pci_device *pci, int chanid, int slave);
+int bootprio_find_fdc_device(struct pci_device *pci, int port, int fdid);
+int bootprio_find_pci_rom(struct pci_device *pci, int instance);
+int bootprio_find_named_rom(const char *name, int instance);
+struct usbdevice_s;
+int bootprio_find_usb(struct usbdevice_s *usbdev, int lun);
+int get_keystroke_full(int msec);
+int get_keystroke(int msec);
+struct chs_s;
+int boot_lchs_find_pci_device(struct pci_device *pci, struct chs_s *chs);
+int boot_lchs_find_scsi_device(struct pci_device *pci, int target, int lun,
+ struct chs_s *chs);
+int boot_lchs_find_ata_device(struct pci_device *pci, int chanid, int slave,
+ struct chs_s *chs);
+
+// bootsplash.c
+void enable_vga_console(void);
+void enable_bootsplash(void);
+void disable_bootsplash(void);
+
+// cdrom.c
+extern struct eltorito_s CDEmu;
+extern struct drive_s *cdemu_drive_gf;
+struct disk_op_s;
+int cdemu_process_op(struct disk_op_s *op);
+void cdrom_prepboot(void);
+int cdrom_boot(struct drive_s *drive_g);
+char *cdrom_media_info(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);
+void handle_1586(struct bregs *regs);
+
+// fw/acpi.c
+void acpi_setup(void);
+
+// fw/biostable.c
+void copy_pir(void *pos);
+void copy_mptable(void *pos);
+extern struct pir_header *PirAddr;
+void copy_acpi_rsdp(void *pos);
+extern struct rsdp_descriptor *RsdpAddr;
+extern u32 acpi_pm1a_cnt;
+extern u16 acpi_pm_base;
+void *find_acpi_rsdp(void);
+void *find_acpi_table(u32 signature);
+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);
+void smbios_setup(void);
+
+// fw/dsdt_parser.c
+struct acpi_device;
+void acpi_dsdt_parse(void);
+struct acpi_device *acpi_dsdt_find_string(struct acpi_device *prev, const char *hid);
+struct acpi_device *acpi_dsdt_find_eisaid(struct acpi_device *prev, u16 eisaid);
+char *acpi_dsdt_name(struct acpi_device *dev);
+int acpi_dsdt_present_eisaid(u16 eisaid);
+int acpi_dsdt_find_io(struct acpi_device *dev, u64 *min, u64 *max);
+int acpi_dsdt_find_mem(struct acpi_device *dev, u64 *min, u64 *max);
+int acpi_dsdt_find_irq(struct acpi_device *dev, u64 *irq);
+
+// fw/coreboot.c
+extern const char *CBvendor, *CBpart;
+struct cbfs_file;
+void coreboot_debug_putc(char c);
+void cbfs_run_payload(struct cbfs_file *file);
+void coreboot_platform_setup(void);
+void cbfs_payload_setup(void);
+void coreboot_preinit(void);
+void coreboot_cbfs_init(void);
+struct cb_header;
+void *find_cb_subtable(struct cb_header *cbh, u32 tag);
+struct cb_header *find_cb_table(void);
+
+// fw/csm.c
+int csm_bootprio_fdc(struct pci_device *pci, int port, int fdid);
+int csm_bootprio_ata(struct pci_device *pci, int chanid, int slave);
+int csm_bootprio_pci(struct pci_device *pci);
+
+// fw/mptable.c
+void mptable_setup(void);
+
+// fw/mtrr.c
+void mtrr_setup(void);
+
+// fw/multiboot.c
+void multiboot_init(void);
+
+// fw/pciinit.c
+extern u64 pcimem_start, pcimem_end;
+extern u64 pcimem64_start, pcimem64_end;
+extern const u8 pci_irqs[4];
+void pci_setup(void);
+void pci_resume(void);
+
+// fw/pirtable.c
+void pirtable_setup(void);
+
+// fw/shadow.c
+void make_bios_writable(void);
+void make_bios_readonly(void);
+void qemu_reboot(void);
+
+// fw/smbios.c
+void smbios_legacy_setup(void);
+
+// fw/smm.c
+void smm_device_setup(void);
+void smm_setup(void);
+
+// fw/smp.c
+extern u32 MaxCountCPUs;
+void wrmsr_smp(u32 index, u64 val);
+void smp_setup(void);
+void smp_resume(void);
+int apic_id_is_present(u8 apic_id);
+
+// hw/dma.c
+int dma_floppy(u32 addr, int count, int isWrite);
+void dma_setup(void);
+
+// hw/floppy.c
+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 floppy_process_op(struct disk_op_s *op);
+void floppy_tick(void);
+
+// hw/ramdisk.c
+void ramdisk_setup(void);
+int ramdisk_process_op(struct disk_op_s *op);
+
+// hw/sdcard.c
+int sdcard_process_op(struct disk_op_s *op);
+void sdcard_setup(void);
+
+// hw/timer.c
+void timer_setup(void);
+void pmtimer_setup(u16 ioport);
+void tsctimer_setfreq(u32 khz, const char *src);
+u32 timer_calc(u32 msecs);
+u32 timer_calc_usec(u32 usecs);
+int timer_check(u32 end);
+void ndelay(u32 count);
+void udelay(u32 count);
+void mdelay(u32 count);
+void nsleep(u32 count);
+void usleep(u32 count);
+void msleep(u32 count);
+u32 ticks_to_ms(u32 ticks);
+u32 ticks_from_ms(u32 ms);
+void pit_setup(void);
+
+// jpeg.c
+struct jpeg_decdata *jpeg_alloc(void);
+int jpeg_decode(struct jpeg_decdata *jpeg, unsigned char *buf);
+void jpeg_get_size(struct jpeg_decdata *jpeg, int *width, int *height);
+int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic, int width
+ , int height, int depth, int bytes_per_line_dest);
+
+// kbd.c
+void kbd_init(void);
+void handle_15c2(struct bregs *regs);
+void process_key(u8 key);
+u8 enqueue_key(u16 keycode);
+u16 ascii_to_keycode(u8 ascii);
+
+// misc.c
+extern int HaveRunPost;
+extern struct bios_config_table_s BIOS_CONFIG_TABLE __aligned(1);
+extern struct floppy_dbt_s diskette_param_table __aligned(1);
+extern u8 BiosChecksum;
+int in_post(void);
+void mathcp_setup(void);
+
+// mouse.c
+void mouse_init(void);
+void process_mouse(u8 data);
+
+// optionroms.c
+struct rom_header;
+void callrom(struct rom_header *rom, u16 bdf);
+void call_bcv(u16 seg, u16 ip);
+int is_pci_vga(struct pci_device *pci);
+void optionrom_setup(void);
+void vgarom_setup(void);
+void s3_resume_vga(void);
+extern int ScreenAndDebug;
+
+// pcibios.c
+void handle_1ab1(struct bregs *regs);
+void bios32_init(void);
+
+// pmm.c
+void pmm_init(void);
+void pmm_prepboot(void);
+
+// pnpbios.c
+u16 get_pnp_offset(void);
+void pnp_init(void);
+
+// post.c
+void interface_init(void);
+void device_hardware_setup(void);
+void prepareboot(void);
+void startBoot(void);
+void reloc_preinit(void *f, void *arg);
+void code_mutable_preinit(void);
+
+// sercon.c
+void sercon_setup(void);
+void sercon_check_event(void);
+
+// serial.c
+void serial_setup(void);
+void lpt_setup(void);
+
+// version.c
+extern const char VERSION[], BUILDINFO[];
+
+// vgahooks.c
+void handle_155f(struct bregs *regs);
+void handle_157f(struct bregs *regs);
+void vgahook_setup(struct pci_device *pci);
+
+#endif // util.h
diff --git a/roms/seabios-hppa/src/version.c b/roms/seabios-hppa/src/version.c
new file mode 100644
index 000000000..5049e8d9d
--- /dev/null
+++ b/roms/seabios-hppa/src/version.c
@@ -0,0 +1,5 @@
+// Place build generated version into a C variable
+#include "autoversion.h"
+
+const char VERSION[] = BUILD_VERSION;
+const char BUILDINFO[] = BUILD_TOOLS;
diff --git a/roms/seabios-hppa/src/vgahooks.c b/roms/seabios-hppa/src/vgahooks.c
new file mode 100644
index 000000000..1f1495329
--- /dev/null
+++ b/roms/seabios-hppa/src/vgahooks.c
@@ -0,0 +1,355 @@
+// Hooks for via vgabios calls into main bios.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "bregs.h" // set_code_invalid
+#include "config.h" // CONFIG_*
+#include "hw/pci.h" // pci_config_readb
+#include "hw/pcidevice.h" // pci_find_device
+#include "hw/pci_ids.h" // PCI_VENDOR_ID_VIA
+#include "hw/pci_regs.h" // PCI_VENDOR_ID
+#include "output.h" // dprintf
+#include "string.h" // strcmp
+#include "util.h" // handle_155f, handle_157f
+
+#define VH_VIA 1
+#define VH_INTEL 2
+#define VH_SMI 3
+
+int VGAHookHandlerType VARFSEG;
+
+static void
+handle_155fXX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+static void
+handle_157fXX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+/****************************************************************
+ * Via hooks
+ ****************************************************************/
+
+int ViaFBsize VARFSEG, ViaRamSpeed VARFSEG;
+
+static void
+via_155f01(struct bregs *regs)
+{
+ regs->eax = 0x5f;
+ regs->cl = 2; // panel type = 2 = 1024 * 768
+ set_success(regs);
+ dprintf(1, "Warning: VGA panel type is hardcoded\n");
+}
+
+static void
+via_155f02(struct bregs *regs)
+{
+ regs->eax = 0x5f;
+ regs->bx = 2;
+ regs->cx = 0x401; // PAL + crt only
+ regs->dx = 0; // TV Layout - default
+ set_success(regs);
+ dprintf(1, "Warning: VGA TV/CRT output type is hardcoded\n");
+}
+
+static void
+via_155f18(struct bregs *regs)
+{
+ int fbsize = GET_GLOBAL(ViaFBsize), ramspeed = GET_GLOBAL(ViaRamSpeed);
+ if (fbsize < 0 || ramspeed < 0) {
+ set_code_invalid(regs, RET_EUNSUPPORTED);
+ return;
+ }
+ regs->eax = 0x5f;
+ regs->ebx = 0x500 | (ramspeed << 4) | fbsize;
+ regs->ecx = 0x060;
+ set_success(regs);
+}
+
+static void
+via_155f19(struct bregs *regs)
+{
+ set_invalid_silent(regs);
+}
+
+static void
+via_155f(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x01: via_155f01(regs); break;
+ case 0x02: via_155f02(regs); break;
+ case 0x18: via_155f18(regs); break;
+ case 0x19: via_155f19(regs); break;
+ default: handle_155fXX(regs); break;
+ }
+}
+
+static int
+getFBSize(struct pci_device *pci)
+{
+ /* FB config */
+ u8 reg = pci_config_readb(pci->bdf, 0xa1);
+
+ /* GFX disabled ? */
+ if (!(reg & 0x80))
+ return -1;
+
+ static u8 mem_power[] = {0, 3, 4, 5, 6, 7, 8, 9};
+ return mem_power[(reg >> 4) & 0x7];
+}
+
+static int
+getViaRamSpeed(struct pci_device *pci)
+{
+ return (pci_config_readb(pci->bdf, 0x90) & 0x07) + 3;
+}
+
+static int
+getAMDRamSpeed(void)
+{
+ struct pci_device *pci = pci_find_device(PCI_VENDOR_ID_AMD
+ , PCI_DEVICE_ID_AMD_K8_NB_MEMCTL);
+ if (!pci)
+ return -1;
+
+ /* mem clk 0 = DDR2 400 */
+ return (pci_config_readb(pci->bdf, 0x94) & 0x7) + 6;
+}
+
+/* int 0x15 - 5f18
+
+ ECX = unknown/don't care
+ EBX[3..0] Frame Buffer Size 2^N MiB
+ EBX[7..4] Memory speed:
+ 0: SDR 66Mhz
+ 1: SDR 100Mhz
+ 2: SDR 133Mhz
+ 3: DDR 100Mhz (PC1600 or DDR200)
+ 4: DDR 133Mhz (PC2100 or DDR266)
+ 5: DDR 166Mhz (PC2700 or DDR333)
+ 6: DDR 200Mhz (PC3200 or DDR400)
+ 7: DDR2 133Mhz (DDR2 533)
+ 8: DDR2 166Mhz (DDR2 667)
+ 9: DDR2 200Mhz (DDR2 800)
+ A: DDR2 233Mhz (DDR2 1066)
+ B: and above: Unknown
+ EBX[?..8] Total memory size?
+ EAX = 0x5f for success
+*/
+
+#define PCI_DEVICE_ID_VIA_K8M890CE_3 0x3336
+#define PCI_DEVICE_ID_VIA_VX855_MEMCTRL 0x3409
+
+static void
+via_setup(struct pci_device *pci)
+{
+ VGAHookHandlerType = VH_VIA;
+
+ struct pci_device *d = pci_find_device(PCI_VENDOR_ID_VIA
+ , PCI_DEVICE_ID_VIA_K8M890CE_3);
+ if (d) {
+ ViaFBsize = getFBSize(d);
+ ViaRamSpeed = getAMDRamSpeed();
+ return;
+ }
+ d = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855_MEMCTRL);
+ if (d) {
+ ViaFBsize = getFBSize(d);
+ ViaRamSpeed = getViaRamSpeed(d);
+ return;
+ }
+
+ dprintf(1, "Warning: VGA memory size and speed is hardcoded\n");
+ ViaFBsize = 5; // 32M frame buffer
+ ViaRamSpeed = 4; // MCLK = DDR266
+}
+
+
+/****************************************************************
+ * Intel VGA hooks
+ ****************************************************************/
+
+u8 IntelDisplayType VARFSEG, IntelDisplayId VARFSEG;
+
+static void
+intel_155f35(struct bregs *regs)
+{
+ regs->ax = 0x005f;
+ regs->cl = GET_GLOBAL(IntelDisplayType);
+ set_success(regs);
+}
+
+static void
+intel_155f40(struct bregs *regs)
+{
+ regs->ax = 0x005f;
+ regs->cl = GET_GLOBAL(IntelDisplayId);
+ set_success(regs);
+}
+
+static void
+intel_155f50(struct bregs *regs)
+{
+ /* Mandatory hook on some Dell laptops */
+ regs->ax = 0x005f;
+ set_success(regs);
+}
+
+static void
+intel_155f(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x35: intel_155f35(regs); break;
+ case 0x40: intel_155f40(regs); break;
+ case 0x50: intel_155f50(regs); break;
+ default: handle_155fXX(regs); break;
+ }
+}
+
+#define BOOT_DISPLAY_DEFAULT (0)
+#define BOOT_DISPLAY_CRT (1 << 0)
+#define BOOT_DISPLAY_TV (1 << 1)
+#define BOOT_DISPLAY_EFP (1 << 2)
+#define BOOT_DISPLAY_LCD (1 << 3)
+#define BOOT_DISPLAY_CRT2 (1 << 4)
+#define BOOT_DISPLAY_TV2 (1 << 5)
+#define BOOT_DISPLAY_EFP2 (1 << 6)
+#define BOOT_DISPLAY_LCD2 (1 << 7)
+
+static void
+intel_setup(struct pci_device *pci)
+{
+ VGAHookHandlerType = VH_INTEL;
+
+ IntelDisplayType = BOOT_DISPLAY_DEFAULT;
+ IntelDisplayId = 3;
+}
+
+static void
+roda_setup(struct pci_device *pci)
+{
+ VGAHookHandlerType = VH_INTEL;
+ // IntelDisplayType = BOOT_DISPLAY_DEFAULT;
+ IntelDisplayType = BOOT_DISPLAY_LCD;
+ // IntelDisplayId = inb(0x60f) & 0x0f; // Correct according to Crete
+ IntelDisplayId = 3; // Correct according to empirical studies
+}
+
+static void
+kontron_setup(struct pci_device *pci)
+{
+ VGAHookHandlerType = VH_INTEL;
+ IntelDisplayType = BOOT_DISPLAY_CRT;
+ IntelDisplayId = 3;
+}
+
+static void
+getac_setup(struct pci_device *pci)
+{
+}
+
+/****************************************************************
+ * Silicon Motion hooks
+ ****************************************************************/
+
+u8 SmiBootDisplay VARFSEG; // 1: LCD, 2: CRT, 3: Both */
+
+static void
+smi_157f02(struct bregs *regs)
+{
+ /* Boot Display Device Override */
+ regs->ax = 0x007f;
+ regs->bl = GET_GLOBAL(SmiBootDisplay);
+ set_success(regs);
+}
+
+static void
+smi_157f14(struct bregs *regs)
+{
+ /* ReduceOn support default status */
+ regs->ax = 0x007f;
+ regs->bl = 0x00;
+ set_success(regs);
+}
+
+static void
+smi_157f(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x02: smi_157f02(regs); break;
+ case 0x14: smi_157f14(regs); break;
+ default: handle_157fXX(regs); break;
+ }
+}
+
+static void
+winent_mb6047_setup(struct pci_device *pci)
+{
+ VGAHookHandlerType = VH_SMI;
+ SmiBootDisplay = 0x02;
+}
+
+/****************************************************************
+ * Entry and setup
+ ****************************************************************/
+
+// Main 16bit entry point
+void
+handle_155f(struct bregs *regs)
+{
+ if (!CONFIG_VGAHOOKS) {
+ handle_155fXX(regs);
+ return;
+ }
+
+ int htype = GET_GLOBAL(VGAHookHandlerType);
+ switch (htype) {
+ case VH_VIA: via_155f(regs); break;
+ case VH_INTEL: intel_155f(regs); break;
+ default: handle_155fXX(regs); break;
+ }
+}
+
+// Main 16bit entry point
+void
+handle_157f(struct bregs *regs)
+{
+ if (!CONFIG_VGAHOOKS) {
+ handle_157fXX(regs);
+ return;
+ }
+
+ int htype = GET_GLOBAL(VGAHookHandlerType);
+ switch (htype) {
+ case VH_SMI: smi_157f(regs); break;
+ default: handle_157fXX(regs); break;
+ }
+}
+
+// Setup
+void
+vgahook_setup(struct pci_device *pci)
+{
+ if (!CONFIG_VGAHOOKS)
+ return;
+
+ if (strcmp(CBvendor, "KONTRON") == 0 && strcmp(CBpart, "986LCD-M") == 0)
+ kontron_setup(pci);
+ else if (strcmp(CBvendor, "GETAC") == 0 && strcmp(CBpart, "P470") == 0)
+ getac_setup(pci);
+ else if (strcmp(CBvendor, "RODA") == 0 && strcmp(CBpart, "RK886EX") == 0)
+ roda_setup(pci);
+ else if (strcmp(CBvendor, "Win Enterprise") == 0 && strcmp(CBpart, "MB6047") == 0)
+ winent_mb6047_setup(pci);
+ else if (pci->vendor == PCI_VENDOR_ID_VIA)
+ via_setup(pci);
+ else if (pci->vendor == PCI_VENDOR_ID_INTEL)
+ intel_setup(pci);
+}
diff --git a/roms/seabios-hppa/src/x86.c b/roms/seabios-hppa/src/x86.c
new file mode 100644
index 000000000..0fdf86f9c
--- /dev/null
+++ b/roms/seabios-hppa/src/x86.c
@@ -0,0 +1,23 @@
+// X86 utility functions.
+//
+// Copyright (C) 2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "x86.h" // __cpuid
+
+void
+cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
+{
+ // Check for cpu id
+ u32 origflags = save_flags();
+ restore_flags(origflags ^ F_ID);
+ u32 newflags = save_flags();
+ restore_flags(origflags);
+
+ if (((origflags ^ newflags) & F_ID) != F_ID)
+ // no cpuid
+ *eax = *ebx = *ecx = *edx = 0;
+ else
+ __cpuid(index, eax, ebx, ecx, edx);
+}
diff --git a/roms/seabios-hppa/src/x86.h b/roms/seabios-hppa/src/x86.h
new file mode 100644
index 000000000..ee7beec31
--- /dev/null
+++ b/roms/seabios-hppa/src/x86.h
@@ -0,0 +1,290 @@
+// Basic x86 asm functions.
+#ifndef __X86_H
+#define __X86_H
+
+// CPU flag bitdefs
+#define F_CF (1<<0)
+#define F_ZF (1<<6)
+#define F_IF (1<<9)
+#define F_ID (1<<21)
+
+// CR0 flags
+#define CR0_PG (1<<31) // Paging
+#define CR0_CD (1<<30) // Cache disable
+#define CR0_NW (1<<29) // Not Write-through
+#define CR0_PE (1<<0) // Protection enable
+
+// PORT_A20 bitdefs
+#define PORT_A20 0x0092
+#define A20_ENABLE_BIT 0x02
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#ifndef __ASSEMBLY__
+
+#include "types.h" // u32
+
+static inline void irq_disable(void)
+{
+ asm volatile("cli": : :"memory");
+}
+
+static inline void irq_enable(void)
+{
+ asm volatile("sti": : :"memory");
+}
+
+static inline u32 save_flags(void)
+{
+ u32 flags;
+ asm volatile("pushfl ; popl %0" : "=rm" (flags));
+ return flags;
+}
+
+static inline void restore_flags(u32 flags)
+{
+ asm volatile("pushl %0 ; popfl" : : "g" (flags) : "memory", "cc");
+}
+
+static inline void cpu_relax(void)
+{
+ asm volatile("rep ; nop": : :"memory");
+}
+
+static inline void nop(void)
+{
+ asm volatile("nop");
+}
+
+static inline void hlt(void)
+{
+ asm volatile("hlt": : :"memory");
+}
+
+static inline void wbinvd(void)
+{
+ asm volatile("wbinvd": : :"memory");
+}
+
+#define CPUID_TSC (1 << 4)
+#define CPUID_MSR (1 << 5)
+#define CPUID_APIC (1 << 9)
+#define CPUID_MTRR (1 << 12)
+#define CPUID_X2APIC (1 << 21)
+static inline void __cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
+{
+ asm("cpuid"
+ : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
+ : "0" (index));
+}
+
+static inline u32 cr0_read(void) {
+ u32 cr0;
+ asm("movl %%cr0, %0" : "=r"(cr0));
+ return 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)
+{
+ u64 ret;
+ asm ("rdmsr" : "=A"(ret) : "c"(index));
+ return ret;
+}
+
+static inline void wrmsr(u32 index, u64 val)
+{
+ asm volatile ("wrmsr" : : "c"(index), "A"(val));
+}
+
+static inline u64 rdtscll(void)
+{
+ u64 val;
+ asm volatile("rdtsc" : "=A" (val));
+ return val;
+}
+
+static inline u32 __ffs(u32 word)
+{
+ asm("bsf %1,%0"
+ : "=r" (word)
+ : "rm" (word));
+ return word;
+}
+static inline u32 __fls(u32 word)
+{
+ asm("bsr %1,%0"
+ : "=r" (word)
+ : "rm" (word));
+ return word;
+}
+
+static inline u32 getesp(void) {
+ u32 esp;
+ asm("movl %%esp, %0" : "=rm"(esp));
+ 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 u32 ror(u32 val, u16 ror) {
+ u32 res;
+ asm volatile("rorl %%cl, %%eax"
+ : "=a" (res) : "a" (val), "c" (ror));
+ return res;
+}
+
+static inline void outb(u8 value, u16 port) {
+ __asm__ __volatile__("outb %b0, %w1" : : "a"(value), "Nd"(port));
+}
+static inline void outw(u16 value, u16 port) {
+ __asm__ __volatile__("outw %w0, %w1" : : "a"(value), "Nd"(port));
+}
+static inline void outl(u32 value, u16 port) {
+ __asm__ __volatile__("outl %0, %w1" : : "a"(value), "Nd"(port));
+}
+static inline u8 inb(u16 port) {
+ u8 value;
+ __asm__ __volatile__("inb %w1, %b0" : "=a"(value) : "Nd"(port));
+ return value;
+}
+static inline u16 inw(u16 port) {
+ u16 value;
+ __asm__ __volatile__("inw %w1, %w0" : "=a"(value) : "Nd"(port));
+ return value;
+}
+static inline u32 inl(u16 port) {
+ u32 value;
+ __asm__ __volatile__("inl %w1, %0" : "=a"(value) : "Nd"(port));
+ return value;
+}
+
+static inline void insb(u16 port, u8 *data, u32 count) {
+ asm volatile("rep insb (%%dx), %%es:(%%edi)"
+ : "+c"(count), "+D"(data) : "d"(port) : "memory");
+}
+static inline void insw(u16 port, u16 *data, u32 count) {
+ asm volatile("rep insw (%%dx), %%es:(%%edi)"
+ : "+c"(count), "+D"(data) : "d"(port) : "memory");
+}
+static inline void insl(u16 port, u32 *data, u32 count) {
+ asm volatile("rep insl (%%dx), %%es:(%%edi)"
+ : "+c"(count), "+D"(data) : "d"(port) : "memory");
+}
+// XXX - outs not limited to es segment
+static inline void outsb(u16 port, u8 *data, u32 count) {
+ asm volatile("rep outsb %%es:(%%esi), (%%dx)"
+ : "+c"(count), "+S"(data) : "d"(port) : "memory");
+}
+static inline void outsw(u16 port, u16 *data, u32 count) {
+ asm volatile("rep outsw %%es:(%%esi), (%%dx)"
+ : "+c"(count), "+S"(data) : "d"(port) : "memory");
+}
+static inline void outsl(u16 port, u32 *data, u32 count) {
+ asm volatile("rep outsl %%es:(%%esi), (%%dx)"
+ : "+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;
+}
+static inline void writew(void *addr, u16 val) {
+ barrier();
+ *(volatile u16 *)addr = val;
+}
+static inline void writeb(void *addr, u8 val) {
+ barrier();
+ *(volatile u8 *)addr = val;
+}
+static inline u64 readq(const void *addr) {
+ u64 val = *(volatile const u64 *)addr;
+ barrier();
+ return val;
+}
+static inline u32 readl(const void *addr) {
+ u32 val = *(volatile const u32 *)addr;
+ barrier();
+ return val;
+}
+static inline u16 readw(const void *addr) {
+ u16 val = *(volatile const u16 *)addr;
+ barrier();
+ return val;
+}
+static inline u8 readb(const void *addr) {
+ u8 val = *(volatile const u8 *)addr;
+ barrier();
+ return val;
+}
+
+// GDT bits
+#define GDT_CODE (0x9bULL << 40) // Code segment - P,R,A bits also set
+#define GDT_DATA (0x93ULL << 40) // Data segment - W,A bits also set
+#define GDT_B (0x1ULL << 54) // Big flag
+#define GDT_G (0x1ULL << 55) // Granularity flag
+// GDT bits for segment base
+#define GDT_BASE(v) ((((u64)(v) & 0xff000000) << 32) \
+ | (((u64)(v) & 0x00ffffff) << 16))
+// GDT bits for segment limit (0-1Meg)
+#define GDT_LIMIT(v) ((((u64)(v) & 0x000f0000) << 32) \
+ | (((u64)(v) & 0x0000ffff) << 0))
+// GDT bits for segment limit (0-4Gig in 4K chunks)
+#define GDT_GRANLIMIT(v) (GDT_G | GDT_LIMIT((v) >> 12))
+
+struct descloc_s {
+ u16 length;
+ u32 addr;
+} PACKED;
+
+static inline void sgdt(struct descloc_s *desc) {
+ asm("sgdtl %0" : "=m"(*desc));
+}
+static inline void lgdt(struct descloc_s *desc) {
+ asm("lgdtl %0" : : "m"(*desc) : "memory");
+}
+
+static inline u8 get_a20(void) {
+ return (inb(PORT_A20) & A20_ENABLE_BIT) != 0;
+}
+
+static inline u8 set_a20(u8 cond) {
+ u8 val = inb(PORT_A20), a20_enabled = (val & A20_ENABLE_BIT) != 0;
+ if (a20_enabled != !!cond)
+ outb(val ^ A20_ENABLE_BIT, PORT_A20);
+ return a20_enabled;
+}
+
+// x86.c
+void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx);
+
+#endif // !__ASSEMBLY__
+
+#elif defined(__hppa__)
+#include "parisc/hppa.h" /* replacement functions for parisc architecture */
+#endif
+
+#endif // x86.h