aboutsummaryrefslogtreecommitdiffstats
path: root/roms/seabios
diff options
context:
space:
mode:
authorfishsoupisgood <github@madingley.org>2019-04-29 01:17:54 +0100
committerfishsoupisgood <github@madingley.org>2019-05-27 03:43:43 +0100
commit3f2546b2ef55b661fd8dd69682b38992225e86f6 (patch)
tree65ca85f13617aee1dce474596800950f266a456c /roms/seabios
downloadqemu-3f2546b2ef55b661fd8dd69682b38992225e86f6.tar.gz
qemu-3f2546b2ef55b661fd8dd69682b38992225e86f6.tar.bz2
qemu-3f2546b2ef55b661fd8dd69682b38992225e86f6.zip
Initial import of qemu-2.4.1HEADmaster
Diffstat (limited to 'roms/seabios')
-rw-r--r--roms/seabios/.gitignore4
-rw-r--r--roms/seabios/.version1
-rw-r--r--roms/seabios/COPYING674
-rw-r--r--roms/seabios/COPYING.LESSER165
-rw-r--r--roms/seabios/Makefile280
-rw-r--r--roms/seabios/README17
-rw-r--r--roms/seabios/docs/Build_overview.md80
-rw-r--r--roms/seabios/docs/Debugging.md106
-rw-r--r--roms/seabios/docs/Developer_Documentation.md24
-rw-r--r--roms/seabios/docs/Developer_links.md86
-rw-r--r--roms/seabios/docs/Download.md25
-rw-r--r--roms/seabios/docs/Execution_and_code_flow.md178
-rw-r--r--roms/seabios/docs/Linking_overview.md166
-rw-r--r--roms/seabios/docs/Mailinglist.md8
-rw-r--r--roms/seabios/docs/Memory_Model.md253
-rw-r--r--roms/seabios/docs/README5
-rw-r--r--roms/seabios/docs/Releases.md377
-rw-r--r--roms/seabios/docs/SeaBIOS.md15
-rwxr-xr-xroms/seabios/scripts/acpi_extract.py354
-rwxr-xr-xroms/seabios/scripts/acpi_extract_preprocess.py41
-rwxr-xr-xroms/seabios/scripts/buildrom.py56
-rwxr-xr-xroms/seabios/scripts/buildversion.sh31
-rwxr-xr-xroms/seabios/scripts/checkrom.py95
-rwxr-xr-xroms/seabios/scripts/checkstack.py227
-rwxr-xr-xroms/seabios/scripts/checksum.py16
-rwxr-xr-xroms/seabios/scripts/encodeint.py21
-rwxr-xr-xroms/seabios/scripts/gen-offsets.sh17
-rw-r--r--roms/seabios/scripts/kconfig/.gitignore22
-rw-r--r--roms/seabios/scripts/kconfig/Makefile331
-rw-r--r--roms/seabios/scripts/kconfig/POTFILES.in12
-rwxr-xr-xroms/seabios/scripts/kconfig/check.sh13
-rw-r--r--roms/seabios/scripts/kconfig/conf.c718
-rw-r--r--roms/seabios/scripts/kconfig/confdata.c1250
-rw-r--r--roms/seabios/scripts/kconfig/expr.c1168
-rw-r--r--roms/seabios/scripts/kconfig/expr.h241
-rw-r--r--roms/seabios/scripts/kconfig/gconf.c1542
-rw-r--r--roms/seabios/scripts/kconfig/gconf.glade661
-rw-r--r--roms/seabios/scripts/kconfig/images.c326
-rw-r--r--roms/seabios/scripts/kconfig/kxgettext.c235
-rw-r--r--roms/seabios/scripts/kconfig/lex.zconf.c2430
-rw-r--r--roms/seabios/scripts/kconfig/list.h131
-rw-r--r--roms/seabios/scripts/kconfig/lkc.h200
-rw-r--r--roms/seabios/scripts/kconfig/lkc_proto.h57
-rw-r--r--roms/seabios/scripts/kconfig/lxdialog/.gitignore4
-rw-r--r--roms/seabios/scripts/kconfig/lxdialog/BIG.FAT.WARNING4
-rw-r--r--roms/seabios/scripts/kconfig/lxdialog/check-lxdialog.sh87
-rw-r--r--roms/seabios/scripts/kconfig/lxdialog/checklist.c332
-rw-r--r--roms/seabios/scripts/kconfig/lxdialog/dialog.h257
-rw-r--r--roms/seabios/scripts/kconfig/lxdialog/inputbox.c301
-rw-r--r--roms/seabios/scripts/kconfig/lxdialog/menubox.c437
-rw-r--r--roms/seabios/scripts/kconfig/lxdialog/textbox.c408
-rw-r--r--roms/seabios/scripts/kconfig/lxdialog/util.c713
-rw-r--r--roms/seabios/scripts/kconfig/lxdialog/yesno.c114
-rw-r--r--roms/seabios/scripts/kconfig/mconf.c1036
-rw-r--r--roms/seabios/scripts/kconfig/menu.c697
-rwxr-xr-xroms/seabios/scripts/kconfig/merge_config.sh150
-rw-r--r--roms/seabios/scripts/kconfig/nconf.c1556
-rw-r--r--roms/seabios/scripts/kconfig/nconf.gui.c656
-rw-r--r--roms/seabios/scripts/kconfig/nconf.h96
-rw-r--r--roms/seabios/scripts/kconfig/qconf.cc1795
-rw-r--r--roms/seabios/scripts/kconfig/qconf.h338
-rw-r--r--roms/seabios/scripts/kconfig/streamline_config.pl647
-rw-r--r--roms/seabios/scripts/kconfig/symbol.c1373
-rw-r--r--roms/seabios/scripts/kconfig/util.c157
-rw-r--r--roms/seabios/scripts/kconfig/zconf.gperf48
-rw-r--r--roms/seabios/scripts/kconfig/zconf.hash.c_shipped289
-rw-r--r--roms/seabios/scripts/kconfig/zconf.l363
-rw-r--r--roms/seabios/scripts/kconfig/zconf.lex.c_shipped2420
-rw-r--r--roms/seabios/scripts/kconfig/zconf.tab.c_shipped2538
-rw-r--r--roms/seabios/scripts/kconfig/zconf.y733
-rwxr-xr-xroms/seabios/scripts/layoutrom.py691
-rw-r--r--roms/seabios/scripts/python23compat.py14
-rwxr-xr-xroms/seabios/scripts/readserial.py190
-rwxr-xr-xroms/seabios/scripts/tarball.sh36
-rwxr-xr-xroms/seabios/scripts/test-build.sh103
-rwxr-xr-xroms/seabios/scripts/transdump.py53
-rw-r--r--roms/seabios/scripts/vgafixup.py96
-rw-r--r--roms/seabios/src/Kconfig516
-rw-r--r--roms/seabios/src/apm.c215
-rw-r--r--roms/seabios/src/asm-offsets.c23
-rw-r--r--roms/seabios/src/biosvar.h130
-rw-r--r--roms/seabios/src/block.c582
-rw-r--r--roms/seabios/src/block.h109
-rw-r--r--roms/seabios/src/bmp.c117
-rw-r--r--roms/seabios/src/boot.c756
-rw-r--r--roms/seabios/src/bootsplash.c254
-rw-r--r--roms/seabios/src/bregs.h80
-rw-r--r--roms/seabios/src/byteorder.h71
-rw-r--r--roms/seabios/src/cdrom.c281
-rw-r--r--roms/seabios/src/clock.c462
-rw-r--r--roms/seabios/src/code16gcc.s1
-rw-r--r--roms/seabios/src/config.h108
-rw-r--r--roms/seabios/src/disk.c748
-rw-r--r--roms/seabios/src/entryfuncs.S165
-rw-r--r--roms/seabios/src/farptr.h208
-rw-r--r--roms/seabios/src/font.c139
-rw-r--r--roms/seabios/src/fw/acpi-dsdt-cpu-hotplug.dsl78
-rw-r--r--roms/seabios/src/fw/acpi-dsdt-dbug.dsl26
-rw-r--r--roms/seabios/src/fw/acpi-dsdt-hpet.dsl36
-rw-r--r--roms/seabios/src/fw/acpi-dsdt-isa.dsl102
-rw-r--r--roms/seabios/src/fw/acpi-dsdt-pci-crs.dsl90
-rw-r--r--roms/seabios/src/fw/acpi-dsdt.dsl342
-rw-r--r--roms/seabios/src/fw/acpi.c685
-rw-r--r--roms/seabios/src/fw/biostables.c461
-rw-r--r--roms/seabios/src/fw/coreboot.c553
-rw-r--r--roms/seabios/src/fw/csm.c344
-rw-r--r--roms/seabios/src/fw/dev-piix.h29
-rw-r--r--roms/seabios/src/fw/dev-q35.h49
-rw-r--r--roms/seabios/src/fw/lzmadecode.c398
-rw-r--r--roms/seabios/src/fw/lzmadecode.h67
-rw-r--r--roms/seabios/src/fw/mptable.c196
-rw-r--r--roms/seabios/src/fw/mtrr.c106
-rw-r--r--roms/seabios/src/fw/paravirt.c448
-rw-r--r--roms/seabios/src/fw/paravirt.h37
-rw-r--r--roms/seabios/src/fw/pciinit.c954
-rw-r--r--roms/seabios/src/fw/pirtable.c103
-rw-r--r--roms/seabios/src/fw/q35-acpi-dsdt.dsl450
-rw-r--r--roms/seabios/src/fw/romfile_loader.c177
-rw-r--r--roms/seabios/src/fw/romfile_loader.h72
-rw-r--r--roms/seabios/src/fw/shadow.c171
-rw-r--r--roms/seabios/src/fw/smbios.c585
-rw-r--r--roms/seabios/src/fw/smm.c259
-rw-r--r--roms/seabios/src/fw/smp.c153
-rw-r--r--roms/seabios/src/fw/ssdt-misc.dsl104
-rw-r--r--roms/seabios/src/fw/ssdt-pcihp.dsl36
-rw-r--r--roms/seabios/src/fw/ssdt-proc.dsl48
-rw-r--r--roms/seabios/src/fw/xen.c147
-rw-r--r--roms/seabios/src/fw/xen.h125
-rw-r--r--roms/seabios/src/gen-defs.h19
-rw-r--r--roms/seabios/src/hw/ahci.c639
-rw-r--r--roms/seabios/src/hw/ahci.h202
-rw-r--r--roms/seabios/src/hw/ata.c1043
-rw-r--r--roms/seabios/src/hw/ata.h158
-rw-r--r--roms/seabios/src/hw/blockcmd.c319
-rw-r--r--roms/seabios/src/hw/blockcmd.h110
-rw-r--r--roms/seabios/src/hw/dma.c67
-rw-r--r--roms/seabios/src/hw/esp-scsi.c238
-rw-r--r--roms/seabios/src/hw/esp-scsi.h8
-rw-r--r--roms/seabios/src/hw/floppy.c673
-rw-r--r--roms/seabios/src/hw/lsi-scsi.c217
-rw-r--r--roms/seabios/src/hw/lsi-scsi.h8
-rw-r--r--roms/seabios/src/hw/megasas.c404
-rw-r--r--roms/seabios/src/hw/megasas.h8
-rw-r--r--roms/seabios/src/hw/pci.c277
-rw-r--r--roms/seabios/src/hw/pci.h131
-rw-r--r--roms/seabios/src/hw/pci_ids.h2623
-rw-r--r--roms/seabios/src/hw/pci_regs.h556
-rw-r--r--roms/seabios/src/hw/pic.c101
-rw-r--r--roms/seabios/src/hw/pic.h56
-rw-r--r--roms/seabios/src/hw/ps2port.c507
-rw-r--r--roms/seabios/src/hw/ps2port.h66
-rw-r--r--roms/seabios/src/hw/pvscsi.c354
-rw-r--r--roms/seabios/src/hw/pvscsi.h8
-rw-r--r--roms/seabios/src/hw/ramdisk.c111
-rw-r--r--roms/seabios/src/hw/rtc.c93
-rw-r--r--roms/seabios/src/hw/rtc.h75
-rw-r--r--roms/seabios/src/hw/sdcard.c321
-rw-r--r--roms/seabios/src/hw/serialio.c89
-rw-r--r--roms/seabios/src/hw/serialio.h29
-rw-r--r--roms/seabios/src/hw/timer.c257
-rw-r--r--roms/seabios/src/hw/usb-ehci.c648
-rw-r--r--roms/seabios/src/hw/usb-ehci.h176
-rw-r--r--roms/seabios/src/hw/usb-hid.c432
-rw-r--r--roms/seabios/src/hw/usb-hid.h29
-rw-r--r--roms/seabios/src/hw/usb-hub.c205
-rw-r--r--roms/seabios/src/hw/usb-hub.h64
-rw-r--r--roms/seabios/src/hw/usb-msc.c220
-rw-r--r--roms/seabios/src/hw/usb-msc.h10
-rw-r--r--roms/seabios/src/hw/usb-ohci.c569
-rw-r--r--roms/seabios/src/hw/usb-ohci.h144
-rw-r--r--roms/seabios/src/hw/usb-uas.c274
-rw-r--r--roms/seabios/src/hw/usb-uas.h9
-rw-r--r--roms/seabios/src/hw/usb-uhci.c567
-rw-r--r--roms/seabios/src/hw/usb-uhci.h128
-rw-r--r--roms/seabios/src/hw/usb-xhci.c1139
-rw-r--r--roms/seabios/src/hw/usb-xhci.h133
-rw-r--r--roms/seabios/src/hw/usb.c500
-rw-r--r--roms/seabios/src/hw/usb.h254
-rw-r--r--roms/seabios/src/hw/virtio-blk.c177
-rw-r--r--roms/seabios/src/hw/virtio-blk.h43
-rw-r--r--roms/seabios/src/hw/virtio-pci.c97
-rw-r--r--roms/seabios/src/hw/virtio-pci.h105
-rw-r--r--roms/seabios/src/hw/virtio-ring.c149
-rw-r--r--roms/seabios/src/hw/virtio-ring.h131
-rw-r--r--roms/seabios/src/hw/virtio-scsi.c187
-rw-r--r--roms/seabios/src/hw/virtio-scsi.h47
-rw-r--r--roms/seabios/src/jpeg.c1055
-rw-r--r--roms/seabios/src/kbd.c576
-rw-r--r--roms/seabios/src/list.h81
-rw-r--r--roms/seabios/src/malloc.c541
-rw-r--r--roms/seabios/src/malloc.h71
-rw-r--r--roms/seabios/src/memmap.c144
-rw-r--r--roms/seabios/src/memmap.h29
-rw-r--r--roms/seabios/src/misc.c203
-rw-r--r--roms/seabios/src/mouse.c343
-rw-r--r--roms/seabios/src/optionroms.c475
-rw-r--r--roms/seabios/src/output.c564
-rw-r--r--roms/seabios/src/output.h68
-rw-r--r--roms/seabios/src/pcibios.c240
-rw-r--r--roms/seabios/src/pmm.c163
-rw-r--r--roms/seabios/src/pnpbios.c88
-rw-r--r--roms/seabios/src/post.c336
-rw-r--r--roms/seabios/src/resume.c158
-rw-r--r--roms/seabios/src/romfile.c100
-rw-r--r--roms/seabios/src/romfile.h19
-rw-r--r--roms/seabios/src/romlayout.S659
-rw-r--r--roms/seabios/src/serial.c317
-rw-r--r--roms/seabios/src/stacks.c827
-rw-r--r--roms/seabios/src/stacks.h53
-rw-r--r--roms/seabios/src/std/LegacyBios.h985
-rw-r--r--roms/seabios/src/std/acpi.h297
-rw-r--r--roms/seabios/src/std/bda.h154
-rw-r--r--roms/seabios/src/std/disk.h175
-rw-r--r--roms/seabios/src/std/mptable.h77
-rw-r--r--roms/seabios/src/std/optionrom.h59
-rw-r--r--roms/seabios/src/std/pirtable.h35
-rw-r--r--roms/seabios/src/std/pmm.h19
-rw-r--r--roms/seabios/src/std/pnpbios.h24
-rw-r--r--roms/seabios/src/std/smbios.h165
-rw-r--r--roms/seabios/src/std/vbe.h156
-rw-r--r--roms/seabios/src/std/vga.h63
-rw-r--r--roms/seabios/src/string.c251
-rw-r--r--roms/seabios/src/string.h31
-rw-r--r--roms/seabios/src/system.c357
-rw-r--r--roms/seabios/src/types.h156
-rw-r--r--roms/seabios/src/util.h237
-rw-r--r--roms/seabios/src/vgahooks.c354
-rw-r--r--roms/seabios/src/x86.c23
-rw-r--r--roms/seabios/src/x86.h247
-rw-r--r--roms/seabios/vgasrc/Kconfig162
-rw-r--r--roms/seabios/vgasrc/bochsvga.c446
-rw-r--r--roms/seabios/vgasrc/bochsvga.h57
-rw-r--r--roms/seabios/vgasrc/cbvga.c193
-rw-r--r--roms/seabios/vgasrc/cbvga.h20
-rw-r--r--roms/seabios/vgasrc/clext.c627
-rw-r--r--roms/seabios/vgasrc/clext.h20
-rw-r--r--roms/seabios/vgasrc/geodevga.c433
-rw-r--r--roms/seabios/vgasrc/geodevga.h89
-rw-r--r--roms/seabios/vgasrc/stdvga.c479
-rw-r--r--roms/seabios/vgasrc/stdvga.h111
-rw-r--r--roms/seabios/vgasrc/stdvgaio.c185
-rw-r--r--roms/seabios/vgasrc/stdvgamodes.c523
-rw-r--r--roms/seabios/vgasrc/vbe.c426
-rw-r--r--roms/seabios/vgasrc/vgabios.c1176
-rw-r--r--roms/seabios/vgasrc/vgabios.h149
-rw-r--r--roms/seabios/vgasrc/vgaentry.S147
-rw-r--r--roms/seabios/vgasrc/vgafb.c702
-rw-r--r--roms/seabios/vgasrc/vgafonts.c785
-rw-r--r--roms/seabios/vgasrc/vgahw.h143
-rw-r--r--roms/seabios/vgasrc/vgainit.c195
-rw-r--r--roms/seabios/vgasrc/vgalayout.lds.S23
251 files changed, 78057 insertions, 0 deletions
diff --git a/roms/seabios/.gitignore b/roms/seabios/.gitignore
new file mode 100644
index 00000000..f9990feb
--- /dev/null
+++ b/roms/seabios/.gitignore
@@ -0,0 +1,4 @@
+out
+*.pyc
+.config
+.config.old
diff --git a/roms/seabios/.version b/roms/seabios/.version
new file mode 100644
index 00000000..a9633733
--- /dev/null
+++ b/roms/seabios/.version
@@ -0,0 +1 @@
+rel-1.8.2-0-g33fbe13
diff --git a/roms/seabios/COPYING b/roms/seabios/COPYING
new file mode 100644
index 00000000..94a9ed02
--- /dev/null
+++ b/roms/seabios/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/roms/seabios/COPYING.LESSER b/roms/seabios/COPYING.LESSER
new file mode 100644
index 00000000..fc8a5de7
--- /dev/null
+++ b/roms/seabios/COPYING.LESSER
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/roms/seabios/Makefile b/roms/seabios/Makefile
new file mode 100644
index 00000000..83cdff37
--- /dev/null
+++ b/roms/seabios/Makefile
@@ -0,0 +1,280 @@
+# SeaBIOS build system
+#
+# Copyright (C) 2008-2012 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU LGPLv3 license.
+
+# Output directory
+OUT=out/
+
+# Common command definitions
+export HOSTCC := $(CC)
+export CONFIG_SHELL := sh
+export KCONFIG_AUTOHEADER := autoconf.h
+export KCONFIG_CONFIG := $(CURDIR)/.config
+export LC_ALL := C
+CROSS_PREFIX=
+ifneq ($(CROSS_PREFIX),)
+CC=$(CROSS_PREFIX)gcc
+endif
+AS=$(CROSS_PREFIX)as
+LD=$(CROSS_PREFIX)ld
+OBJCOPY=$(CROSS_PREFIX)objcopy
+OBJDUMP=$(CROSS_PREFIX)objdump
+STRIP=$(CROSS_PREFIX)strip
+PYTHON=python
+CPP=cpp
+IASL:=iasl
+LD32BIT_FLAG:=-melf_i386
+
+# Source files
+SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \
+ system.c serial.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \
+ hw/pci.c hw/timer.c hw/rtc.c hw/dma.c hw/pic.c hw/ps2port.c hw/serialio.c \
+ hw/usb.c hw/usb-uhci.c hw/usb-ohci.c hw/usb-ehci.c \
+ hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \
+ hw/blockcmd.c hw/floppy.c hw/ata.c hw/ramdisk.c \
+ hw/virtio-ring.c hw/virtio-pci.c hw/virtio-blk.c hw/virtio-scsi.c \
+ hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c
+SRC16=$(SRCBOTH)
+SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c romfile.c x86.c optionroms.c \
+ pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c \
+ hw/ahci.c hw/pvscsi.c hw/usb-xhci.c hw/usb-hub.c hw/sdcard.c \
+ fw/coreboot.c fw/lzmadecode.c fw/csm.c fw/biostables.c \
+ fw/paravirt.c fw/shadow.c fw/pciinit.c fw/smm.c fw/smp.c fw/mtrr.c fw/xen.c \
+ fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c
+SRC32SEG=string.c output.c pcibios.c apm.c stacks.c hw/pci.c hw/serialio.c
+DIRS=src src/hw src/fw vgasrc
+
+# Default compiler flags
+cc-option=$(shell if test -z "`$(1) $(2) -S -o /dev/null -xc /dev/null 2>&1`" \
+ ; then echo "$(2)"; else echo "$(3)"; fi ;)
+
+CPPFLAGS = -P -MD -MT $@
+
+COMMONCFLAGS := -I$(OUT) -Isrc -Os -MD -g \
+ -Wall -Wno-strict-aliasing -Wold-style-definition \
+ $(call cc-option,$(CC),-Wtype-limits,) \
+ -m32 -march=i386 -mregparm=3 -mpreferred-stack-boundary=2 \
+ -minline-all-stringops -fomit-frame-pointer \
+ -freg-struct-return -ffreestanding -fno-delete-null-pointer-checks \
+ -ffunction-sections -fdata-sections -fno-common -fno-merge-constants
+COMMONCFLAGS += $(call cc-option,$(CC),-nopie,)
+COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
+COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
+COMMA := ,
+
+CFLAGS32FLAT := $(COMMONCFLAGS) -DMODE16=0 -DMODESEGMENT=0
+CFLAGSSEG := $(COMMONCFLAGS) -DMODESEGMENT=1 -fno-defer-pop \
+ $(call cc-option,$(CC),-fno-jump-tables,-DMANUAL_NO_JUMP_TABLE) \
+ $(call cc-option,$(CC),-fno-tree-switch-conversion,)
+CFLAGS32SEG := $(CFLAGSSEG) -DMODE16=0
+CFLAGS16 := $(CFLAGSSEG) -DMODE16=1 \
+ $(call cc-option,$(CC),-m16,-Wa$(COMMA)src/code16gcc.s) \
+ $(call cc-option,$(CC),--param large-stack-frame=4,-fno-inline)
+
+# Run with "make V=1" to see the actual compile commands
+ifdef V
+Q=
+else
+Q=@
+MAKEFLAGS += --no-print-directory
+endif
+
+# Default targets
+-include $(KCONFIG_CONFIG)
+
+target-y :=
+target-$(CONFIG_QEMU) += $(OUT)bios.bin
+target-$(CONFIG_CSM) += $(OUT)Csm16.bin
+target-$(CONFIG_COREBOOT) += $(OUT)bios.bin.elf
+target-$(CONFIG_BUILD_VGABIOS) += $(OUT)vgabios.bin
+
+all: $(target-y)
+
+# Make definitions
+.PHONY : all clean distclean FORCE
+.DELETE_ON_ERROR:
+
+
+################ Common build rules
+
+# Verify the build environment works.
+TESTGCC:=$(shell OUT="$(OUT)" CC="$(CC)" LD="$(LD)" IASL="$(IASL)" scripts/test-build.sh)
+ifeq "$(TESTGCC)" "-1"
+$(error "Please upgrade the build environment")
+endif
+
+ifeq "$(TESTGCC)" "0"
+# Use -fwhole-program
+CFLAGSWHOLE=-fwhole-program -DWHOLE_PROGRAM
+endif
+
+# Do a whole file compile by textually including all C code.
+define whole-compile
+@echo " Compiling whole program $3"
+$(Q)printf '$(foreach i,$2,#include "$i"\n)' > $3.tmp.c
+$(Q)$(CC) -I. $1 $(CFLAGSWHOLE) -c $3.tmp.c -o $3
+endef
+
+%.strip.o: %.o
+ @echo " Stripping $@"
+ $(Q)$(STRIP) $< -o $@
+
+$(OUT)%.s: %.c
+ @echo " Compiling to assembler $@"
+ $(Q)$(CC) $(CFLAGS16) -S -c $< -o $@
+
+$(OUT)%.o: %.c $(OUT)autoconf.h
+ @echo " Compile checking $@"
+ $(Q)$(CC) $(CFLAGS32FLAT) -c $< -o $@
+
+$(OUT)%.lds: %.lds.S
+ @echo " Precompiling $@"
+ $(Q)$(CPP) $(CPPFLAGS) -D__ASSEMBLY__ $< -o $@
+
+
+################ Main BIOS build rules
+
+$(OUT)asm-offsets.s: $(OUT)autoconf.h
+
+$(OUT)asm-offsets.h: $(OUT)src/asm-offsets.s
+ @echo " Generating offset file $@"
+ $(Q)./scripts/gen-offsets.sh $< $@
+
+$(OUT)ccode16.o: $(OUT)autoconf.h $(patsubst %.c, $(OUT)src/%.o,$(SRC16)) ; $(call whole-compile, $(CFLAGS16), $(addprefix src/, $(SRC16)),$@)
+
+$(OUT)code32seg.o: $(OUT)autoconf.h $(patsubst %.c, $(OUT)src/%.o,$(SRC32SEG)) ; $(call whole-compile, $(CFLAGS32SEG), $(addprefix src/, $(SRC32SEG)),$@)
+
+$(OUT)ccode32flat.o: $(OUT)autoconf.h $(patsubst %.c, $(OUT)src/%.o,$(SRC32FLAT)) ; $(call whole-compile, $(CFLAGS32FLAT), $(addprefix src/, $(SRC32FLAT)),$@)
+
+$(OUT)romlayout.o: src/romlayout.S $(OUT)autoconf.h $(OUT)asm-offsets.h
+ @echo " Compiling (16bit) $@"
+ $(Q)$(CC) $(CFLAGS16) -c -D__ASSEMBLY__ $< -o $@
+
+$(OUT)romlayout16.lds: $(OUT)ccode32flat.o $(OUT)code32seg.o $(OUT)ccode16.o $(OUT)romlayout.o scripts/layoutrom.py scripts/buildversion.sh
+ @echo " Building ld scripts"
+ $(Q)BUILD_VERSION="$(VERSION)" ./scripts/buildversion.sh $(OUT)version.c
+ $(Q)$(CC) $(CFLAGS32FLAT) -c $(OUT)version.c -o $(OUT)version.o
+ $(Q)$(LD) $(LD32BIT_FLAG) -r $(OUT)ccode32flat.o $(OUT)version.o -o $(OUT)code32flat.o
+ $(Q)$(LD) $(LD32BIT_FLAG) -r $(OUT)ccode16.o $(OUT)romlayout.o -o $(OUT)code16.o
+ $(Q)$(OBJDUMP) -thr $(OUT)code32flat.o > $(OUT)code32flat.o.objdump
+ $(Q)$(OBJDUMP) -thr $(OUT)code32seg.o > $(OUT)code32seg.o.objdump
+ $(Q)$(OBJDUMP) -thr $(OUT)code16.o > $(OUT)code16.o.objdump
+ $(Q)$(PYTHON) ./scripts/layoutrom.py $(OUT)code16.o.objdump $(OUT)code32seg.o.objdump $(OUT)code32flat.o.objdump $(OUT)$(KCONFIG_AUTOHEADER) $(OUT)romlayout16.lds $(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds
+
+# These are actually built by scripts/layoutrom.py above, but by pulling them
+# into an extra rule we prevent make -j from spawning layoutrom.py 4 times.
+$(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds $(OUT)code32flat.o $(OUT)code16.o: $(OUT)romlayout16.lds
+
+$(OUT)rom16.o: $(OUT)code16.o $(OUT)romlayout16.lds
+ @echo " Linking $@"
+ $(Q)$(LD) -T $(OUT)romlayout16.lds $< -o $@
+
+$(OUT)rom32seg.o: $(OUT)code32seg.o $(OUT)romlayout32seg.lds
+ @echo " Linking $@"
+ $(Q)$(LD) -T $(OUT)romlayout32seg.lds $< -o $@
+
+$(OUT)rom.o: $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o $(OUT)romlayout32flat.lds
+ @echo " Linking $@"
+ $(Q)$(LD) -T $(OUT)romlayout32flat.lds $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o -o $@
+
+$(OUT)bios.bin.prep: $(OUT)rom.o scripts/checkrom.py
+ @echo " Prepping $@"
+ $(Q)rm -f $(OUT)bios.bin $(OUT)Csm16.bin $(OUT)bios.bin.elf
+ $(Q)$(OBJDUMP) -thr $< > $<.objdump
+ $(Q)$(OBJCOPY) -O binary $< $(OUT)bios.bin.raw
+ $(Q)$(PYTHON) ./scripts/checkrom.py $<.objdump $(CONFIG_ROM_SIZE) $(OUT)bios.bin.raw $(OUT)bios.bin.prep
+
+$(OUT)bios.bin: $(OUT)bios.bin.prep
+ @echo " Creating $@"
+ $(Q)cp $< $@
+
+$(OUT)Csm16.bin: $(OUT)bios.bin.prep
+ @echo " Creating $@"
+ $(Q)cp $< $@
+
+$(OUT)bios.bin.elf: $(OUT)rom.o $(OUT)bios.bin.prep
+ @echo " Creating $@"
+ $(Q)$(STRIP) -R .comment $< -o $(OUT)bios.bin.elf
+
+
+################ VGA build rules
+
+# VGA src files
+SRCVGA=src/output.c src/string.c src/hw/pci.c src/hw/serialio.c \
+ vgasrc/vgainit.c vgasrc/vgabios.c vgasrc/vgafb.c \
+ vgasrc/vgafonts.c vgasrc/vbe.c \
+ vgasrc/stdvga.c vgasrc/stdvgamodes.c vgasrc/stdvgaio.c \
+ vgasrc/clext.c vgasrc/bochsvga.c vgasrc/geodevga.c \
+ src/fw/coreboot.c vgasrc/cbvga.c
+
+ifeq "$(CONFIG_VGA_FIXUP_ASM)" "y"
+$(OUT)vgaccode16.raw.s: $(OUT)autoconf.h $(patsubst %.c, $(OUT)%.o,$(SRCVGA)) ; $(call whole-compile, $(filter-out -fomit-frame-pointer,$(CFLAGS16)) -fno-omit-frame-pointer -S -Isrc, $(SRCVGA),$@)
+
+$(OUT)vgaccode16.o: $(OUT)vgaccode16.raw.s scripts/vgafixup.py
+ @echo " Fixup VGA rom assembler"
+ $(Q)$(PYTHON) ./scripts/vgafixup.py $< $(OUT)vgaccode16.s
+ $(Q)$(AS) --32 src/code16gcc.s $(OUT)vgaccode16.s -o $@
+else
+$(OUT)vgaccode16.o: $(OUT)autoconf.h $(patsubst %.c, $(OUT)%.o,$(SRCVGA)) ; $(call whole-compile, $(CFLAGS16) -Isrc, $(SRCVGA),$@)
+endif
+
+$(OUT)vgaentry.o: vgasrc/vgaentry.S $(OUT)autoconf.h $(OUT)asm-offsets.h
+ @echo " Compiling (16bit) $@"
+ $(Q)$(CC) $(CFLAGS16) -c -D__ASSEMBLY__ $< -o $@
+
+$(OUT)vgarom.o: $(OUT)vgaccode16.o $(OUT)vgaentry.o $(OUT)vgasrc/vgalayout.lds scripts/buildversion.sh
+ @echo " Linking $@"
+ $(Q)BUILD_VERSION="$(VERSION)" ./scripts/buildversion.sh $(OUT)vgaversion.c VAR16
+ $(Q)$(CC) $(CFLAGS16) -c $(OUT)vgaversion.c -o $(OUT)vgaversion.o
+ $(Q)$(LD) --gc-sections -T $(OUT)vgasrc/vgalayout.lds $(OUT)vgaccode16.o $(OUT)vgaentry.o $(OUT)vgaversion.o -o $@
+
+$(OUT)vgabios.bin.raw: $(OUT)vgarom.o
+ @echo " Extracting binary $@"
+ $(Q)$(OBJCOPY) -O binary $< $@
+
+$(OUT)vgabios.bin: $(OUT)vgabios.bin.raw scripts/buildrom.py
+ @echo " Finalizing rom $@"
+ $(Q)$(PYTHON) ./scripts/buildrom.py $< $@
+
+
+################ DSDT build rules
+
+iasl-option=$(shell if test -z "`$(1) $(2) 2>&1 > /dev/null`" \
+ ; then echo "$(2)"; else echo "$(3)"; fi ;)
+
+$(OUT)%.hex: %.dsl ./scripts/acpi_extract_preprocess.py ./scripts/acpi_extract.py
+ @echo " Compiling IASL $@"
+ $(Q)$(CPP) $(CPPFLAGS) $< -o $(OUT)$*.dsl.i.orig
+ $(Q)$(PYTHON) ./scripts/acpi_extract_preprocess.py $(OUT)$*.dsl.i.orig > $(OUT)$*.dsl.i
+ $(Q)$(IASL) $(call iasl-option,$(IASL),-Pn,) -vs -l -tc -p $(OUT)$* $(OUT)$*.dsl.i
+ $(Q)$(PYTHON) ./scripts/acpi_extract.py $(OUT)$*.lst > $(OUT)$*.off
+ $(Q)cat $(OUT)$*.off > $@
+
+$(OUT)src/fw/acpi.o: $(OUT)src/fw/acpi-dsdt.hex $(OUT)src/fw/ssdt-proc.hex $(OUT)src/fw/ssdt-pcihp.hex $(OUT)src/fw/ssdt-misc.hex $(OUT)src/fw/q35-acpi-dsdt.hex
+
+################ Kconfig rules
+
+define do-kconfig
+$(Q)mkdir -p $(OUT)/scripts/kconfig/lxdialog
+$(Q)mkdir -p $(OUT)/include/config
+$(Q)mkdir -p $(addprefix $(OUT), $(DIRS))
+$(Q)$(MAKE) -C $(OUT) -f $(CURDIR)/scripts/kconfig/Makefile srctree=$(CURDIR) src=scripts/kconfig obj=scripts/kconfig Q=$(Q) Kconfig=$(CURDIR)/src/Kconfig $1
+endef
+
+$(OUT)autoconf.h : $(KCONFIG_CONFIG) ; $(call do-kconfig, silentoldconfig)
+$(KCONFIG_CONFIG): src/Kconfig vgasrc/Kconfig ; $(call do-kconfig, olddefconfig)
+%onfig: ; $(call do-kconfig, $@)
+help: ; $(call do-kconfig, $@)
+
+
+################ Generic rules
+
+clean:
+ $(Q)rm -rf $(OUT)
+
+distclean: clean
+ $(Q)rm -f .config .config.old
+
+-include $(patsubst %,$(OUT)%/*.d,$(DIRS))
diff --git a/roms/seabios/README b/roms/seabios/README
new file mode 100644
index 00000000..e18be16f
--- /dev/null
+++ b/roms/seabios/README
@@ -0,0 +1,17 @@
+Welcome to the SeaBIOS project! This project implements an X86 legacy
+bios that is built with standard GNU tools.
+
+Please see build and developer information at:
+
+ http://seabios.org/Developer_Documentation
+
+For the impatient, SeaBIOS is built for QEMU and tested on QEMU with:
+
+ make
+ qemu -bios out/bios.bin
+
+SeaBIOS can be configured with kconfig. To change the default
+configuration one can run "make menuconfig" prior to running "make".
+
+For other types of builds, and for more detailed developer
+documentation, please see the online documentation listed above.
diff --git a/roms/seabios/docs/Build_overview.md b/roms/seabios/docs/Build_overview.md
new file mode 100644
index 00000000..26db2269
--- /dev/null
+++ b/roms/seabios/docs/Build_overview.md
@@ -0,0 +1,80 @@
+The SeaBIOS code can be built using standard GNU tools. A recent Linux
+distribution should be able to build SeaBIOS using the standard
+compiler tools.
+
+Building SeaBIOS
+================
+
+First, [obtain the code](Download). SeaBIOS can be compiled for
+several different build targets. It is also possible to configure
+additional compile time options - run **make menuconfig** to do this.
+
+Build for QEMU (along with KVM, Xen, and Bochs)
+-----------------------------------------------
+
+To build for QEMU (and similar), one should be able to run "make" in
+the main directory. The resulting file "out/bios.bin" contains the
+processed bios image.
+
+One can use the resulting binary with QEMU by using QEMU's "-bios"
+option. For example:
+
+`qemu -bios out/bios.bin -fda myfdimage.img`
+
+One can also use the resulting binary with Bochs. For example:
+
+`bochs -q 'floppya: 1_44=myfdimage.img' 'romimage: file=out/bios.bin'`
+
+Build for coreboot
+------------------
+
+To build for coreboot please see the coreboot build instructions at:
+<http://www.coreboot.org/SeaBIOS>
+
+Build as a UEFI Compatibility Support Module (CSM)
+--------------------------------------------------
+
+To build as a CSM, first run kconfig (make menuconfig) and enable
+CONFIG_CSM. Then build SeaBIOS (make) - the resulting binary will be
+in "out/Csm16.bin".
+
+This binary may be used with the OMVF/EDK-II UEFI firmware. It will
+provide "legacy" BIOS services for booting non-EFI operating systems
+and will also allow OVMF to display on otherwise unsupported video
+hardware by using the traditional VGA BIOS. (Windows 2008r2 is known
+to use INT 10h BIOS calls even when booted via EFI, and the presence
+of a CSM makes this work as expected too.)
+
+Having built SeaBIOS with CONFIG_CSM, one should be able to drop the
+result (out/Csm16.bin) into an OVMF build tree at
+OvmfPkg/Csm/Csm16/Csm16.bin and then build OVMF with 'build -D
+CSM_ENABLE'. The SeaBIOS binary will be included as a discrete file
+within the 'Flash Volume' which is created, and there are tools which
+will extract it and allow it to be replaced.
+
+Overview of files in the repository
+===================================
+
+The **src/** directory contains the main bios source code. The
+**src/hw/** directory contains source code specific to hardware
+drivers. The **src/fw/** directory contains source code for platform
+firmware initialization. The **src/std/** directory contains header
+files describing standard bios, firmware, and hardware interfaces.
+
+The **vgasrc/** directory contains code for VGA BIOS implementations.
+This code is separate from the main BIOS code in the src/ directory.
+When the build is configured to produce a VGA BIOS the resulting
+binary is found in out/vgabios.bin. The VGA BIOS code is always
+compiled in 16bit mode.
+
+The **scripts/** directory contains helper utilities for manipulating
+and building the final roms.
+
+The **out/** directory is created by the build process - it contains
+all intermediate and final files.
+
+When reading the C code be aware that code that runs in 16bit mode can
+not arbitrarily access non-stack memory - see [Memory Model](Memory
+Model) for more details. For information on the major C code functions
+and where code execution starts see [Execution and code
+flow](Execution and code flow).
diff --git a/roms/seabios/docs/Debugging.md b/roms/seabios/docs/Debugging.md
new file mode 100644
index 00000000..03567de4
--- /dev/null
+++ b/roms/seabios/docs/Debugging.md
@@ -0,0 +1,106 @@
+This page describes the process of obtaining diagnostic information
+from SeaBIOS and for reporting problems.
+
+Diagnostic information
+======================
+
+SeaBIOS has the ability to output diagnostic messages. This is
+implemented in the code via calls to the "dprintf()" C function.
+
+On QEMU these messages are written to a special debug port. One can
+view these messages by adding '-chardev stdio,id=seabios -device
+isa-debugcon,iobase=0x402,chardev=seabios' to the QEMU command line.
+Once this is done, one should see status messages on the console.
+
+On coreboot these messages are generally written to the "cbmem"
+console (CONFIG_DEBUG_COREBOOT). If SeaBIOS launches a Linux operating
+system, one can obtain the cbmem tool from the coreboot repository and
+run "cbmem -c" to view the SeaBIOS diagnostic messages.
+
+Additionally, if a serial port is available, one may compile SeaBIOS
+to send the diagnostic messages to the serial port. See the SeaBIOS
+CONFIG_DEBUG_SERIAL option.
+
+Trouble reporting
+=================
+
+If you are experiencing problems with SeaBIOS, it's useful to increase
+the debugging level. This is done by running "make menuconfig" and
+setting CONFIG_DEBUG_LEVEL to a higher value. A debug level of 8 will
+show a lot of diagnostic information without flooding the serial port
+(levels above 8 will frequently cause too much data).
+
+To report an issue, please collect the serial boot log with SeaBIOS
+set to a debug level of 8 and forward the full log along with a
+description of the problem to the SeaBIOS [mailing list](Mailinglist).
+
+Timing debug messages
+=====================
+
+The SeaBIOS repository has a tool (**scripts/readserial.py**) that can
+timestamp each diagnostic message produced. The timestamps can provide
+some additional information on how long internal processes take. It
+also provides a simple profiling mechanism.
+
+The tool can be used on coreboot builds that have diagnostic messages
+sent to a serial port. Make sure SeaBIOS is configured with
+CONFIG_DEBUG_SERIAL and run the following on the host receiving serial
+output:
+
+`/path/to/seabios/scripts/readserial.py /dev/ttyS0 115200`
+
+Update the above command with the appropriate serial device and baud
+rate.
+
+The tool can also timestamp the messages from the QEMU debug port. To
+use with QEMU run the following:
+
+`mkfifo qemudebugpipe`\
+`qemu -chardev pipe,path=qemudebugpipe,id=seabios -device isa-debugcon,iobase=0x402,chardev=seabios ...`
+
+and then in another session:
+
+`/path/to/seabios/scripts/readserial.py -nf qemudebugpipe`
+
+The mkfifo command only needs to be run once to create the pipe file.
+
+When readserial.py is running, it shows a timestamp with millisecond
+precision of the amount of time since the start of the log. If one
+presses the "enter" key in the readserial.py session it will add a
+blank line to the screen and also reset the time back to zero. The
+readserial.py program also keeps a log of all output in files that
+look like "seriallog-YYYYMMDD_HHMMSS.log".
+
+Debugging with gdb on QEMU
+==========================
+
+One can use gdb with QEMU to debug system images. To do this, add '-s
+-S' to the qemu command line. For example:
+
+`qemu -bios out/bios.bin -fda myfdimage.img -s -S`
+
+Then, in another session, run gdb with either out/rom16.o (to debug
+bios 16bit code) or out/rom.o (to debug bios 32bit code). For example:
+
+`gdb out/rom16.o`
+
+Once in gdb, use the command "target remote localhost:1234" to have
+gdb connect to QEMU. See the QEMU documentation for more information
+on using gdb and QEMU in this mode.
+
+When debugging 16bit code, also run the following commands in gdb:
+
+`set architecture i8086`\
+`add-symbol-file out/rom16.o 0xf0000`
+
+The second command loads the 16bit symbols a second time at an offset
+of 0xf0000, which helps gdb set and catch breakpoints correctly.
+
+To debug a VGA BIOS image, run "gdb out/vgarom.o" add use the gdb
+command "add-symbol-file out/vgarom.o 0xc0000" to load the 16bit VGA
+BIOS symbols twice.
+
+If debugging the 32bit SeaBIOS initialization code with gdb, note that
+SeaBIOS does self relocation by default. This relocation will alter
+the location of initialization code symbols. Disable
+CONFIG_RELOCATE_INIT to prevent SeaBIOS from doing this.
diff --git a/roms/seabios/docs/Developer_Documentation.md b/roms/seabios/docs/Developer_Documentation.md
new file mode 100644
index 00000000..d50455d3
--- /dev/null
+++ b/roms/seabios/docs/Developer_Documentation.md
@@ -0,0 +1,24 @@
+This page is intended for developers interested in understanding and
+enhancing SeaBIOS. Please also consider joining the [mailing
+list](Mailinglist).
+
+The SeaBIOS code can be obtained via the [download](Download)
+page. For specific information on building SeaBIOS for coreboot,
+please see the [coreboot SeaBIOS](http://www.coreboot.org/SeaBIOS)
+page.
+
+See details on [building SeaBIOS](Build overview).
+
+There is also information on the SeaBIOS [Memory Model](Memory Model).
+
+Along with information on SeaBIOS [Execution and code flow](Execution
+and code flow).
+
+A description of the process of linking the final SeaBIOS binary is
+available at [Linking overview](Linking overview).
+
+To debug SeaBIOS and report problems see SeaBIOS
+[debugging](Debugging).
+
+Useful links to specifications is available at [Developer
+links](Developer links).
diff --git a/roms/seabios/docs/Developer_links.md b/roms/seabios/docs/Developer_links.md
new file mode 100644
index 00000000..67a047e4
--- /dev/null
+++ b/roms/seabios/docs/Developer_links.md
@@ -0,0 +1,86 @@
+Links to pages with more information.
+
+BIOS interfaces
+===============
+
+Ralf Brown's interrupt list
+
+* <http://www.cs.cmu.edu/~ralf/files.html>
+
+Memory layout info
+
+* <http://stanislavs.org/helppc/bios_data_area.html>
+
+Old PNP BIOS spec
+
+* <ftp://download.intel.com/support/motherboards/desktop/sb/pnpbiosspecificationv10a.pdf>
+
+T13 BIOS Enhanced Disk Drive (drafts):
+
+* <http://www.t10.org/t13/#Project_drafts>
+
+Exported BIOS tables
+====================
+
+ACPI spec
+
+* <http://www.acpi.info/>
+
+PCI IRQ Routing Table Specification
+
+* <http://www.microsoft.com/whdc/archive/pciirq.mspx>
+
+MP configuration table
+
+* <http://www.intel.com/design/pentium/datashts/242016.htm>
+
+SM BIOS (aka DMI):
+
+* <http://www.dmtf.org/standards/smbios/>
+
+Hardware information
+====================
+
+info on PIC
+
+* <http://www.beyondlogic.org/interrupts/interupt.htm>
+
+info on kbd
+
+* <http://www.computer-engineering.org/ps2protocol/>
+
+info on vga
+
+* <http://www.osdever.net/FreeVGA/home.htm>
+
+info on lpt
+
+* <http://www.beyondlogic.org/spp/parallel.htm>
+
+info on floppy
+
+* <http://www.isdaman.com/alsos/hardware/fdc/floppy.htm>
+
+info on ata
+
+* <http://ata.wiki.kernel.org/index.php/Developer_Resources>
+* <http://www.t10.org/t13/#Project_drafts>
+
+info on serial
+
+* <http://www.national.com/ds/PC/PC16550D.pdf>
+
+General information
+===================
+
+Bochs tech document list
+
+* <http://bochs.sourceforge.net/techdata.html>
+
+Phoenix documents
+
+* <http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/PC+Industry+Specifications.htm>
+
+Dosemu information
+
+* <http://www.dosemu.org/docs/README-tech>
diff --git a/roms/seabios/docs/Download.md b/roms/seabios/docs/Download.md
new file mode 100644
index 00000000..a49c6fb7
--- /dev/null
+++ b/roms/seabios/docs/Download.md
@@ -0,0 +1,25 @@
+SeaBIOS may be distributed under the terms of the [GNU
+LGPLv3](http://www.gnu.org/licenses/lgpl-3.0-standalone.html) license.
+Both source code and binaries are available.
+
+Latest source code
+==================
+
+The SeaBIOS project uses the [git](http://git-scm.com/) revision
+control system. To download the latest source from revision control,
+run:
+
+`$ git clone git://git.seabios.org/seabios.git seabios`\
+`$ cd seabios`
+
+There's also a [website](http://git.seabios.org/) to browse the latest
+source code online.
+
+Released versions
+=================
+
+Released versions of the source code are available at:
+
+<http://code.coreboot.org/p/seabios/downloads/>
+
+Please see [releases](Releases) for information on each release.
diff --git a/roms/seabios/docs/Execution_and_code_flow.md b/roms/seabios/docs/Execution_and_code_flow.md
new file mode 100644
index 00000000..9396ecaa
--- /dev/null
+++ b/roms/seabios/docs/Execution_and_code_flow.md
@@ -0,0 +1,178 @@
+This page provides a high-level description of some of the major code
+phases that SeaBIOS transitions through and general information on
+overall code flow.
+
+SeaBIOS code phases
+===================
+
+The SeaBIOS code goes through a few distinct code phases during its
+execution lifecycle. Understanding these code phases can help when
+reading and enhancing the code.
+
+POST phase
+----------
+
+The Power On Self Test (POST) phase is the initialization phase of the
+BIOS. This phase is entered when SeaBIOS first starts execution. The
+goal of the phase is to initialize internal state, initialize external
+interfaces, detect and setup hardware, and to then start the boot
+phase.
+
+On emulators, this phase starts when the CPU starts execution in 16bit
+mode at 0xFFFF0000:FFF0. The emulators map the SeaBIOS binary to this
+address, and SeaBIOS arranges for romlayout.S:reset_vector() to be
+present there. This code calls romlayout.S:entry_post() which then
+calls post.c:handle_post() in 32bit mode.
+
+On coreboot, the build arranges for romlayout.S:entry_elf() to be
+called in 32bit mode. This then calls post.c:handle_post().
+
+On CSM, the build arranges for romlayout.S:entry_csm() to be called
+(in 16bit mode). This then calls csm.c:handle_csm() in 32bit mode.
+Unlike on the emulators and coreboot, the SeaBIOS CSM POST phase is
+orchastrated with UEFI and there are several calls back and forth
+between SeaBIOS and UEFI via handle_csm() throughout the POST
+process.
+
+The POST phase itself has several sub-phases.
+
+* The "preinit" sub-phase: code run prior to code relocation.
+* The "init" sub-phase: code to initialize internal variables and
+ interfaces.
+* The "setup" sub-phase: code to setup hardware and drivers.
+* The "prepboot" sub-phase: code to finalize interfaces and prepare
+ for the boot phase.
+
+At completion of the POST phase, SeaBIOS invokes an "int 0x19"
+software interrupt in 16bit mode which begins the boot phase.
+
+Boot phase
+----------
+
+The goal of the boot phase is to load the first portion of the
+operating system's boot loader into memory and start execution of that
+boot loader. This phase starts when a software interrupt ("int 0x19"
+or "int 0x18") is invoked. The code flow starts in 16bit mode in
+romlayout.S:entry_19() or romlayout.S:entry_18() which then
+transition to 32bit mode and call boot.c:handle_19() or
+boot.c:handle_18().
+
+The boot phase is technically also part of the "runtime" phase of
+SeaBIOS. It is typically invoked immiediately after the POST phase,
+but it can also be invoked by an operating system or be invoked
+multiple times in an attempt to find a valid boot media. Although the
+boot phase C code runs in 32bit mode it does not have write access to
+the 0x0f0000-0x100000 memory region and can not call the various
+malloc_X() calls. See [Memory Model](Memory Model) for
+more information.
+
+Main runtime phase
+------------------
+
+The main runtime phase occurs after the boot phase starts the
+operating system. Once in this phase, the SeaBIOS code may be invoked
+by the operating system using various 16bit and 32bit calls. The goal
+of this phase is to support these legacy calling interfaces and to
+provide compatibility with BIOS standards. There are multiple entry
+points for the BIOS - see the entry_XXX() assembler functions in
+romlayout.S.
+
+Callers use most of these legacy entry points by setting up a
+particular CPU register state, invoking the BIOS, and then inspecting
+the returned CPU register state. To handle this, SeaBIOS will backup
+the current register state into a "struct bregs" (see romlayout.S,
+entryfuncs.S, and bregs.h) on call entry and then pass this struct to
+the C code. The C code can then inspect the register state and modify
+it. The assembler entry functions will then restore the (possibly
+modified) register state from the "struct bregs" on return to the
+caller.
+
+Resume and reboot
+-----------------
+
+As noted above, on emulators SeaBIOS handles the 0xFFFF0000:FFF0
+machine startup execution vector. This vector is also called on
+machine faults and on some machine "resume" events. It can also be
+called (as 0xF0000:FFF0) by software as a request to reboot the
+machine (on emulators, coreboot, and CSM).
+
+The SeaBIOS "resume and reboot" code handles these calls and attempts
+to determine the desired action of the caller. Code flow starts in
+16bit mode in romlayout.S:reset_vector() which calls
+romlayout.S:entry_post() which calls romlayout.S:entry_resume() which
+calls resume.c:handle_resume(). Depending on the request the
+handle_resume() code may transition to 32bit mode.
+
+Technically this code is part of the "runtime" phase, so even though
+parts of it run in 32bit mode it still has the same limitations of the
+runtime phase.
+
+Threads
+=======
+
+Internally SeaBIOS implements a simple cooperative multi-tasking
+system. The system works by giving each "thread" its own stack, and
+the system round-robins between these stacks whenever a thread issues
+a yield() call. This "threading" system may be more appropriately
+described as [coroutines](http://en.wikipedia.org/wiki/Coroutine).
+These "threads" do not run on multiple CPUs and are not preempted, so
+atomic memory accesses and complex locking is not required.
+
+The goal of these threads is to reduce overall boot time by
+parallelizing hardware delays. (For example, by allowing the wait for
+an ATA harddrive to spinup and respond to commands to occur in
+parallel with the wait for a PS/2 keyboard to respond to a setup
+command.) These hardware setup threads are only available during the
+"setup" sub-phase of the [POST phase](#POST_phase).
+
+The code that implements threads is in stacks.c.
+
+Hardware interrupts
+===================
+
+The SeaBIOS C code always runs with hardware interrupts disabled. All
+of the C code entry points (see romlayout.S) are careful to explicitly
+disable hardware interrupts (via "cli"). Because running with
+interrupts disabled increases interrupt latency, any C code that could
+loop for a significant amount of time (more than about 1 ms) should
+periodically call yield(). The yield() call will briefly enable
+hardware interrupts to occur, then disable interrupts, and then resume
+execution of the C code.
+
+There are two main reasons why SeaBIOS always runs C code with
+interrupts disabled. The first reason is that external software may
+override the default SeaBIOS handlers that are called on a hardware
+interrupt event. Indeed, it is common for DOS based applications to do
+this. These legacy third party interrupt handlers may have
+undocumented expections (such as stack location and stack size) and
+may attempt to call back into the various SeaBIOS software services.
+Greater compatibility and more reproducible results can be achieved by
+only permitting hardware interrupts at specific points (via yield()
+calls). The second reason is that much of SeaBIOS runs in 32bit mode.
+Attempting to handle interrupts in both 16bit mode and 32bit mode and
+switching between modes to delegate those interrupts is an unneeded
+complexity. Although disabling interrupts can increase interrupt
+latency, this only impacts legacy systems where the small increase in
+interrupt latency is unlikely to be noticeable.
+
+Extra 16bit stack
+=================
+
+SeaBIOS implements 16bit real mode handlers for both hardware
+interrupts and software request "interrupts". In a traditional BIOS,
+these requests would use the caller's stack space. However, the
+minimum amount of space the caller must provide has not been
+standardized and very old DOS programs have been observed to allocate
+very small amounts of stack space (100 bytes or less).
+
+By default, SeaBIOS now switches to its own stack on most 16bit real
+mode entry points. This extra stack space is allocated in ["low
+memory"](Memory Model). It ensures SeaBIOS uses a minimal amount of a
+callers stack (typically no more than 16 bytes) for these legacy
+calls. (More recently defined BIOS interfaces such as those that
+support 16bit protected and 32bit protected mode calls standardize a
+minimum stack size with adequete space, and SeaBIOS generally will not
+use its extra stack in these cases.)
+
+The code to implement this stack "hopping" is in romlayout.S and in
+stacks.c.
diff --git a/roms/seabios/docs/Linking_overview.md b/roms/seabios/docs/Linking_overview.md
new file mode 100644
index 00000000..fb938b63
--- /dev/null
+++ b/roms/seabios/docs/Linking_overview.md
@@ -0,0 +1,166 @@
+This page describes the process that the SeaBIOS build uses to link
+the compiled code into the final binary objects.
+
+Unfortunately, the SeaBIOS linking phase is complex. This complexity
+is due to several unusual requirements:
+
+* Some BIOS entry points must reside at specific hardcoded memory
+ locations. The build must support positioning code and variables at
+ specific locations.
+* In order to support multiple [memory models](Memory Model) the same
+ C code can be complied in three modes (16bit mode, 32bit segmented
+ mode, and 32bit "flat" mode). Binary code from these three modes
+ must be able to co-exist and on occasion reference each other.
+* There is a finite amount of memory available to the BIOS. The build
+ will attempt to weed out unused code and variables from the final
+ binary. It also supports self-relocation of one-time initialization
+ code.
+
+Code layout
+===========
+
+To support the unusual build requirements, several
+[gcc](http://en.wikipedia.org/wiki/GNU_Compiler_Collection) compiler
+options are used. The "-ffunction-sections" and "-fdata-sections"
+flags instruct the compiler to place each variable and function into
+its own
+[ELF](http://en.wikipedia.org/wiki/Executable_and_Linkable_Format)
+section.
+
+The C code is compiled three times into three separate objects for
+each of the major supported [memory models](Memory Model):
+**code16.o**, **code32seg.o**, and **code32flat.o**. Information on
+the sections and symbols of these three objects are extracted (using
+**objdump**) and passed in to the **scripts/layoutrom.py** python
+script. This script analyzes this information and produces gnu
+[ld](http://en.wikipedia.org/wiki/GNU_linker) "linker scripts" which
+provide precise location information to the linker. These linker
+scripts are then used during the link phase which produces a **rom.o**
+object containing all the code.
+
+Fixed location entry points
+---------------------------
+
+The build supports placing code entry points and variables at fixed
+memory locations. This support is required in order to support the
+legacy BIOS standards. For example, a program might execute an "int
+0x15" to request system information from the BIOS, but another old
+program might use "ljmpw $0xf000, $0xf859" instead. Both must provide
+the same results and so the build must position the 0x15 interrupt
+entry point in physical memory at 0xff859.
+
+This support is accomplished by placing the given code/variables into
+ELF sections that have a name containing the substring
+".fixedaddr.0x1234" (where 0x1234 is the desired address). For
+variables in C code this is accomplished by marking the variables with
+the VARFSEGFIXED(0x1234) macro. For assembler entry points the ORG
+macro is used (see **romlayout.S**).
+
+During the build, the **layoutrom.py** script will detect sections
+that contain the ".fixedaddr." substring and will arrange for the
+final linker scripts to specify the desired address for the given
+section.
+
+Due to the sparse nature of these fixed address sections, the
+layoutrom.py script will also arrange to pack in other unrelated 16bit
+code into the free space between fixed address sections (see
+layoutrom.py:fitSections()). This maximizes the space available and
+reduces the overall size of the final binary.
+
+C code in three modes
+---------------------
+
+SeaBIOS must support multiple [memory models](Memory Model). This is
+accomplished by compiling the C code three separate times into three
+separate objects.
+
+The C code within a mode must not accidentally call a C function in
+another mode, but multiple modes must all access the same single copy
+of global variables. Further, it is occasionally necessary for the C
+code in one mode to obtain the address of C code in another mode.
+
+In order to use the same global variables between all modes, the
+layoutrom.py script will detect references to global variables and
+emit specific symbol definitions for those global variables in the
+linker scripts so that all references use the same physical memory
+address (see layoutrom.py:outXRefs()).
+
+To ensure C code does not accidentally call C code compiled in a
+different mode, the build will ensure the symbols for C code in each
+mode are isolated from each other during the linking stage. To support
+those situations where an address of a C function in another mode is
+required the build supports symbols with a special "\_cfuncX_"
+prefix. The layoutrom.py script detects these references and will emit
+a corresponding symbol definitions in the linker script that points to
+the C code of the specified mode. This is typically seen with code
+like:
+
+`extern void _cfunc32flat_process_op(void);`\
+`return call32(_cfunc32flat_process_op, 0, 0);`
+
+In the above example, when the build finds the symbol
+"\_cfunc32flat_process_op" it will emit that symbol with the physical
+address of the 32bit "flat" version of the process_op() C function.
+
+Build garbage collection
+------------------------
+
+To reduce the overall size of the final SeaBIOS binary the build
+supports automatically weeding out of unused code and variables. This
+is done with two separate processes: when supported the gcc
+"-fwhole-program" compilation flag is used, and the layoutrom.py
+script checks for unreferenced ELF sections. The layoutrom.py script
+builds the final linker scripts with only referenced ELF sections, and
+thus unreferenced sections are weeded out from the final objects.
+
+When writing C code, it is necessary to mark C functions with the
+VISIBLE16, VISIBLE32SEG, or VISIBLE32FLAT macros if the functions are
+ever referenced from assembler code. These macros ensure the
+corresponding C function is emitted by the C compiler when compiling
+for the given memory mode. These macros, however, do not affect the
+layoutrom.py reference check, so even a function decorated with one of
+the above macros can be weeded out from the final object if it is
+never referenced.
+
+Code relocation
+---------------
+
+To further reduce the runtime memory size of the BIOS, the build
+supports runtime self-relocation. Normally SeaBIOS is loaded into
+memory in the memory region at 0xC0000-0x100000. This is convenient
+for initial binary deployment, but the space competes with memory
+requirements for Option ROMs, BIOS tables, and runtime storage. By
+default, SeaBIOS will self-relocate its one-time initialization code
+to free up space in this region.
+
+To support this feature, the build attempts to automatically detect
+which C code is exclusively initialization phase code (see
+layoutrom.py:checkRuntime()). It does this by finding all functions
+decorated with the VISIBLE32INIT macro and all functions only
+reachable via functions with that macro. These "init only" functions
+are then grouped together and their location and size is stored in the
+binary for the runtime code to relocate (see post.c:reloc_preinit()).
+
+The build also locates all cross section code references along with
+all absolute memory addresses in the "init only" code. These addresses
+need to be modified with the new run-time address in order for the
+code to successfully run at a new address. The build finds the
+location of the addresses (see layoutrom.py:getRelocs()) and stores
+the information in the final binary.
+
+Final binary checks
+===================
+
+At the conclusion of the main linking stage, the code is contained in
+the file **rom.o**. This object file contains all of the assembler
+code, variables, and the C code from all three memory model modes.
+
+At this point the **scripts/checkrom.py** script is run to perform
+final checks on the code. The script performs some sanity checks, it
+may update some tables in the binary, and it reports some size
+information.
+
+After the checkrom.py script is run the final user visible binary is
+produced. The name of the final binary is either **bios.bin**,
+**Csm16.bin**, or **bios.bin.elf** depending on the SeaBIOS build
+requested.
diff --git a/roms/seabios/docs/Mailinglist.md b/roms/seabios/docs/Mailinglist.md
new file mode 100644
index 00000000..21e74a4b
--- /dev/null
+++ b/roms/seabios/docs/Mailinglist.md
@@ -0,0 +1,8 @@
+For questions and general information about SeaBIOS, please subscribe
+to the [SeaBIOS mailing
+list](http://www.seabios.org/mailman/listinfo/seabios). If you're not
+subscribed, your post will be held temporarily for moderator approval
+(to combat spam).
+
+A mailing list archive is available at
+<http://www.seabios.org/pipermail/seabios/>
diff --git a/roms/seabios/docs/Memory_Model.md b/roms/seabios/docs/Memory_Model.md
new file mode 100644
index 00000000..0668bd8f
--- /dev/null
+++ b/roms/seabios/docs/Memory_Model.md
@@ -0,0 +1,253 @@
+The SeaBIOS code is required to support multiple x86 CPU memory
+models. This requirement impacts the code layout and internal storage
+of SeaBIOS.
+
+x86 Memory Models
+=================
+
+The x86 line of CPUs has evolved over many years. The original 8086
+chip used 16bit pointers and could only address 1 megabyte of memory.
+The 80286 CPU still used 16bit pointers, but could address up to 16
+megabytes of memory. The 80386 chips could process 32bit instructions
+and could access up to 4 gigabyte of memory. The most recent x86 chips
+can process 64bit instructions and access 16 exabytes of ram.
+
+During the evolution of the x86 CPUs from the 8086 to the 80386 the
+BIOS was extended to handle calls in the various modes that the CPU
+implemented.
+
+This section outlines the five different x86 CPU execution and memory
+access models that SeaBIOS supports.
+
+16bit real mode
+---------------
+
+This mode is a
+[segmented](http://en.wikipedia.org/wiki/Memory_segmentation) memory
+mode invoked by callers. The CPU defaults to executing 16bit
+instructions. Callers typically invoke the BIOS by issuing an "int x"
+instruction which causes a software
+[interrupt](http://en.wikipedia.org/wiki/Interrupt) that is handled by
+the BIOS. The SeaBIOS code also handles hardware interrupts in this
+mode. SeaBIOS can only access the first 1 megabyte of memory in this
+mode, but it can access any part of that first megabyte.
+
+16bit bigreal mode
+------------------
+
+This mode is a segmented memory mode that is used for [option
+roms](http://en.wikipedia.org/wiki/Option_ROM). The CPU defaults to
+executing 16bit instructions and segmented memory accesses are still
+used. However, the segment limits are increased so that the entire
+first 4 gigabytes of memory is fully accessible. Callers can invoke
+all the [16bit real mode](#16bit_real_mode) functions while in this
+mode and can also invoke the Post Memory Manager (PMM) functions that
+are available during option rom execution.
+
+16bit protected mode
+--------------------
+
+CPU execution in this mode is similar to [16bit real
+mode](#16bit_real_mode). The CPU defaults to executing 16bit
+instructions. However, each segment register indexes a "descriptor
+table", and it is difficult or impossible to know what the physical
+address of each segment is. Generally speaking, the BIOS can only
+access code and data in the f-segment. The PCIBIOS, APM BIOS, and PNP
+BIOS all have documented 16bit protected mode entry points.
+
+Some old code may attempt to invoke the standard [16bit real
+mode](#16bit_real_mode) entry points while in 16bit protected
+mode. The PCI BIOS specification explicitly requires that the legacy
+"int 1a" real mode entry point support 16bit protected mode calls if
+they are for the PCI BIOS. Callers of other legacy entry points in
+protected mode have not been observed and SeaBIOS does not support
+them.
+
+32bit segmented mode
+--------------------
+
+In this mode the processor runs in 32bit mode, but the segment
+registers may have a limit and may have a non-zero offset. In effect,
+this mode has all of the limitations of [16bit protected
+mode](#16bit_protected_mode) - the main difference between the modes
+is that the processor defaults to executing 32bit instructions. In
+addition to these limitations, callers may also run the SeaBIOS code
+at varying virtual addresses and so the code must support code
+relocation. The PCI BIOS specification and APM BIOS specification
+define 32bit segmented mode interfaces.
+
+32bit flat mode
+---------------
+
+In this mode the processor defaults to executing 32bit instructions,
+and all segment registers have an offset of zero and allow access to
+the entire first 4 gigabytes of memory. This is the only "sane" mode
+for 32bit code - modern compilers and modern operating systems will
+generally only support this mode (when running 32bit code).
+Ironically, it's the only mode that is not strictly required for a
+BIOS to support. SeaBIOS uses this mode internally to support the POST
+and BOOT [phases of execution](Execution and code flow).
+
+code16gcc
+=========
+
+In order to produce code that can run when the processor is in a 16bit
+mode, SeaBIOS uses the
+[binutils](http://en.wikipedia.org/wiki/GNU_Binutils) ".code16gcc"
+assembler flag. This instructs the assembler to emit extra prefix
+opcodes so that the 32bit code produced by
+[gcc](http://en.wikipedia.org/wiki/GNU_Compiler_Collection) will run
+even when the processor is in 16bit mode. Note that gcc always
+produces 32bit code - it does not know about the ".code16gcc" flag and
+does not know that the code will run in a 16bit mode.
+
+SeaBIOS uses the same code for all of the 16bit modes ([16bit real
+mode](#16bit_real_mode), [16bit bigreal mode](#16bit_bigreal_mode),
+and [16bit protected mode](#16bit_protected_mode)) and that code is
+assembled using ".code16gcc". SeaBIOS is careful to use segment
+registers properly so that the same code can run in the different
+16bit modes that it needs to support.
+
+C code mode flags
+=================
+
+Two compile time flags are available to determine the memory model the
+code is intended for: MODE16 and MODESEGMENT. When compiling for the
+16 bit modes, MODE16 is true and MODESEGMENT is true. In 32bit
+segmented mode, MODE16 is false and MODESEGMENT is true. In 32bit flat
+mode both MODE16 and MODESEGMENT are false.
+
+Common memory used at run-time
+==============================
+
+There are several memory areas that the SeaBIOS "runtime"
+[phase](Execution and code flow) makes use of:
+
+* 0x000000-0x000400: Interrupt descriptor table (IDT). This area
+ defines 256 interrupt vectors as defined by the Intel CPU
+ specification for 16bit irq handlers. This area is read/writable at
+ runtime and can be accessed from 16bit real mode and 16bit bigreal
+ mode calls. SeaBIOS only uses this area to maintain compatibility
+ with legacy systems.
+
+* 0x000400-0x000500: BIOS Data Area (BDA). This area contains various
+ legacy flags and attributes. The area is read/writable at runtime
+ and can be accessed from 16bit real mode and 16bit bigreal mode
+ calls. SeaBIOS only uses this area to maintain compatibility with
+ legacy systems.
+
+* 0x09FC00-0x0A0000 (typical): Extended BIOS Data Area (EBDA). This
+ area contains a few legacy flags and attributes. The area is
+ typically located at 0x9FC00, but it can be moved by option roms, by
+ legacy operating systems, and by SeaBIOS if
+ CONFIG_MALLOC_UPPERMEMORY is not set. Its actual location is
+ determined by a pointer in the BDA. The area is read/writable at
+ runtime and can be accessed from 16bit real mode and 16bit bigreal
+ mode calls. SeaBIOS only uses this area to maintain compatibility
+ with legacy systems.
+
+* 0x0E0000-0x0F0000 (typical): "low" memory. This area is used for
+ custom read/writable storage internal to SeaBIOS. The area is
+ read/writable at runtime and can be accessed from 16bit real mode
+ and 16bit bigreal mode calls. The area is typically located at the
+ end of the e-segment, but the build may position it anywhere in the
+ 0x0C0000-0x0F0000 region. However, if CONFIG_MALLOC_UPPERMEMORY is
+ not set, then this region is between 0x090000-0x0A0000. Space is
+ allocated in this region by either marking a global variable with
+ the "VARLOW" flag or by calling malloc_low() during
+ initialization. The area can be grown dynamically (via malloc_low),
+ but it will never exceed 64K.
+
+* 0x0F0000-0x100000: The BIOS segment. This area is used for both
+ runtime code and static variables. Space is allocated in this region
+ by either marking a global variable with VAR16, one of the VARFSEG
+ flags, or by calling malloc_fseg() during initialization. The area
+ is read-only at runtime and can be accessed from 16bit real mode,
+ 16bit bigreal mode, 16bit protected mode, and 32bit segmented mode
+ calls.
+
+All of the above areas are also read/writable during the SeaBIOS
+initialization phase and are accessible when in 32bit flat mode.
+
+Segmented mode memory access
+============================
+
+The assembler entry functions for segmented mode calls (all modes
+except [32bit flat mode](#32bit_flat_mode)) will arrange
+to set the data segment (%ds) to be the same as the stack segment
+(%ss) before calling any C code. This permits all C variables located
+on the stack and C pointers to data located on the stack to work as
+normal.
+
+However, all code running in segmented mode must wrap non-stack memory
+accesses in special macros. These macros ensure the correct segment
+register is used. Failure to use the correct macro will result in an
+incorrect memory access that will likely cause hard to find errors.
+
+There are three low-level memory access macros:
+
+* GET_VAR / SET_VAR : Accesses a variable using the specified segment
+ register. This isn't typically used directly by C code.
+
+* GET_FARVAR / SET_FARVAR : Assigns the extra segment (%es) to the
+ given segment id and then performs the given memory access via %es.
+
+* GET_FLATVAR / SET_FLATVAR : These macros take a 32bit pointer,
+ construct a segment/offset pair valid in real mode, and then perform
+ the given access. These macros must not be used in 16bit protected
+ mode or 32bit segmented mode.
+
+Since most memory accesses are to [common memory used at
+run-time](#Common_memory_used_at_run-time), several helper
+macros are also available.
+
+* GET_IDT / SET_IDT : Access the interrupt descriptor table (IDT).
+
+* GET_BDA / SET_BDA : Access the BIOS Data Area (BDA).
+
+* GET_EBDA / SET_EBDA : Access the Extended BIOS Data Area (EBDA).
+
+* GET_LOW / SET_LOW : Access internal variables marked with
+ VARLOW. (There are also related macros GET_LOWFLAT / SET_LOWFLAT for
+ accessing storage allocated with malloc_low).
+
+* GET_GLOBAL : Access internal variables marked with the VAR16 or
+ VARFSEG flags. (There is also the related macro GET_GLOBALFLAT for
+ accessing storage allocated with malloc_fseg).
+
+Memory available during initialization
+======================================
+
+During the POST [phase](Execution and code flow) the code
+can fully access the first 4 gigabytes of memory. However, memory
+accesses are generally limited to the [common memory used at
+run-time](#Common_memory_used_at_run-time) and areas
+allocated at runtime via one of the malloc calls:
+
+* malloc_high : Permanent high-memory zone. This area is used for
+ custom read/writable storage internal to SeaBIOS. The area is
+ located at the top of the first 4 gigabytes of ram. It is commonly
+ used for storing standard tables accessed by the operating system at
+ runtime (ACPI, SMBIOS, and MPTable) and for DMA buffers used by
+ hardware drivers. The area is read/writable at runtime and an entry
+ in the e820 memory map is used to reserve it. When running on an
+ emulator that has only 1 megabyte of ram this zone will be empty.
+
+* malloc_tmphigh : Temporary high-memory zone. This area is used for
+ custom read/writable storage during the SeaBIOS initialization
+ phase. The area generally starts after the first 1 megabyte of ram
+ (0x100000) and ends prior to the Permanent high-memory zone. When
+ running on an emulator that has only 1 megabyte of ram this zone
+ will be empty. The area is not reserved from the operating system,
+ so it must not be accessed after the SeaBIOS initialization phase.
+
+* malloc_tmplow : Temporary low-memory zone. This area is used for
+ custom read/writable storage during the SeaBIOS initialization
+ phase. The area resides between 0x07000-0x90000. The area is not
+ reserved from the operating system and by specification it is
+ required to be zero'd at the end of the initialization phase.
+
+The "tmplow" and "tmphigh" regions are only available during the
+initialization phase. Any access (either read or write) after
+completion of the initialization phase can result in difficult to find
+errors.
diff --git a/roms/seabios/docs/README b/roms/seabios/docs/README
new file mode 100644
index 00000000..430e0fe4
--- /dev/null
+++ b/roms/seabios/docs/README
@@ -0,0 +1,5 @@
+This directory contains SeaBIOS documentation as found on the SeaBIOS
+wiki. All the files in this directory (with the exclusion of this
+README file) correspond to a page on the wiki.
+
+The documentation files use markdown syntax.
diff --git a/roms/seabios/docs/Releases.md b/roms/seabios/docs/Releases.md
new file mode 100644
index 00000000..6a1ecd56
--- /dev/null
+++ b/roms/seabios/docs/Releases.md
@@ -0,0 +1,377 @@
+History of SeaBIOS releases. Please see [download](Download) for
+information on obtaining these releases.
+
+SeaBIOS 1.8.0
+=============
+
+Available on 20150218. Major changes in this release:
+
+* Several USB timing fixes for USB controllers on real hardware
+* Initial support for USB3 hubs
+* Initial support for SD cards (on QEMU only)
+* Initial support for transitioning to 32bit mode using SMIs (on QEMU
+ TCG only)
+* SeaVGABIOS improvements
+ * Added cursor emulation to coreboot native init vgabios (cbvga)
+ * Added support for read character calls when in graphics mode
+* Developer documentation added to "docs/" directory in the code
+ repository and several documentation updates
+* Several bug fixes and code cleanups
+
+As of the 1.8.0 release, new feature releases will modify the first
+two release numbers (eg, 1.8) and stable releases will use three
+numbers (eg, 1.8.1). The prior behavior of using a forth number
+(eg, 1.7.5.1) for stable releases will no longer be used.
+
+SeaBIOS 1.7.5
+=============
+
+Available on 20140528. Major changes in this release:
+
+* Support for obtaining SMBIOS tables directly from QEMU.
+* XHCI USB controller fixes for real hardware (now tested on several
+ boards)
+* SeaVGABIOS improvements
+ * New driver for "coreboot native vga" support
+ * Improved detection of older x86emu versions with incorrect
+ emulation.
+* Several bug fixes and code cleanups
+
+SeaBIOS 1.7.5.1
+---------------
+
+Available on 20141113. Stable release containing only bug fixes.
+
+SeaBIOS 1.7.5.2
+---------------
+
+Available on 20150112. Stable release containing only bug fixes.
+
+SeaBIOS 1.7.4
+=============
+
+Available on 20131223. Major changes in this release:
+
+* Support for obtaining ACPI tables directly from QEMU.
+* Initial support for XHCI USB controllers (initially for QEMU only).
+* Support for booting from "pvscsi" devices on QEMU.
+* Enhanced floppy driver - improved support for real hardware.
+* coreboot cbmem console support.
+* Optional support for using the 9-segment instead of the e-segment
+ for local variables.
+* Improved internal timer code and accuracy.
+* SeaVGABIOS improvements
+ * Better support for legacy X.org releases with incomplete x86emu
+ emulation.
+ * Support for using an internal stack to reduce caller's stack
+ usage.
+ * Back port of new "bochs dispi" interface video modes.
+* Several bug fixes and code cleanups
+ * Source code separated out into additional hardware and firmware
+ directories.
+ * Update to latest version of Kconfig
+
+SeaBIOS 1.7.3
+=============
+
+Available on 20130707. Major changes in this release:
+
+* Initial support for using SeaBIOS as a UEFI Compatibility Support
+ Module (CSM)
+* Support for detecting and using ACPI reboot ports.
+* By default, all 16bit entry points now use an internal stack to
+ reduce stack footprint.
+* Floppy controller code has been rewritten to improve
+ compatibility. Non-standard floppy sizes now work again with recent
+ QEMU versions.
+* Several bug fixes and code cleanups
+
+SeaBIOS 1.7.2
+=============
+
+Available on 20130118. Major changes in this release:
+
+* Support for ICH9 host chipset ("q35") on emulators
+* Support for booting from LSI MegaRAID SAS controllers
+* Support for using the ACPI PM timer on emulators
+* Improved Geode VGA BIOS support.
+* Several bug fixes
+
+SeaBIOS 1.7.2.1
+---------------
+
+Available on 20130227. Stable release containing only bug fixes.
+
+SeaBIOS 1.7.2.2
+---------------
+
+Available on 20130527. Stable release containing only bug fixes.
+
+SeaBIOS 1.7.1
+=============
+
+Available on 20120831. Major changes in this release:
+
+* Initial support for booting from USB attached scsi (USB UAS) drives
+* USB EHCI 64bit controller support
+* USB MSC multi-LUN device support
+* Support for booting from LSI SCSI controllers on emulators
+* Support for booting from AMD PCscsi controllers on emulators
+* New PCI allocation code on emulators. Support 64bit PCI bars and
+ mapping them above 4G.
+* Support for non-linear APIC ids on emulators.
+* Stack switching for 16bit real mode irq handlers to reduce stack
+ footprint.
+* Support for custom storage in the memory at 0xc0000-0xf0000. No
+ longer reserve memory for custom storage in first 640k.
+* Improved code generation for 16bit segment register loads
+* Boot code will now (by default) reboot after 60 seconds if no boot
+ device found
+* CBFS and FWCFG "files" are now only scanned one time
+* Several bug fixes
+
+SeaBIOS 1.7.0
+=============
+
+Available on 20120414. Major changes in this release:
+
+* Many enhancements to VGA BIOS code - it should now be feature
+ complete with LGPL vgabios.
+* Support for virtio-scsi.
+* Improved USB drive (usb-msc) support.
+* Several USB controller bug fixes and improvements.
+* Runtime ACPI AML PCI hotplug construction.
+* Support for running on i386 and i486 CPUs.
+* Enhancements to PCI init when running on emulators.
+* Several bug fixes
+
+SeaBIOS 1.6.3
+=============
+
+Available on 20111004. Major changes in this release:
+
+* Initial support for Xen
+* PCI init (on emulators) uses a two-phase initialization
+* Fixes for AHCI so it can work on real hardware. AHCI is now enabled
+ by default.
+* Bootsplash support for BMP files
+* Several configuration options can now be configured at runtime via
+ CBFS files (eg, "etc/boot-menu-wait")
+* PCI device scan is cached during POST phase
+* Several bug fixes
+
+The SeaBIOS 1.6.3 release was an incremental feature release. The
+first release number (1) was incremented as the project was no longer
+in a beta stage, and the third release number (3) was also incremented
+to indicate the release was a regular feature release.
+
+SeaBIOS 1.6.3.1
+---------------
+
+Available on 20111124. Stable release containing only bug fixes.
+
+SeaBIOS 1.6.3.2
+---------------
+
+Available on 20120311. Stable release containing only bug fixes.
+
+SeaBIOS 0.6.2
+=============
+
+Available on 20110228. Major changes in this release:
+
+* Setup code can relocate to high-memory to save space in c-f segments
+* Build now configured via Kconfig
+* Experimental support for AHCI controllers
+* Support for run-time configuration of the boot order (via
+ CBFS/fw_cfg "bootorder" file)
+* Support T13 EDD3.0 spec
+* Improved bounds checking on PCI memory allocation
+* Several bug fixes
+
+SeaBIOS 0.6.1
+=============
+
+Available on 20100913. Major changes in this release:
+
+* Support for virtio drives
+* Add ACPI definitions for cpu hotplug support
+* Support for a graphical bootsplash screen
+* USB mouse support
+* The PCI support for emulators is less dependent on i440 chipset
+* New malloc implementation which improves memalign and free
+* The build system no longer double links objects
+* Several bug fixes
+
+SeaBIOS 0.6.1.1
+---------------
+
+Available on 20101031. Stable release containing only bug fixes.
+
+SeaBIOS 0.6.1.2
+---------------
+
+Available on 20101113. Stable release containing only bug fixes.
+
+SeaBIOS 0.6.1.3
+---------------
+
+Available on 20101226. Stable release containing only bug fixes.
+
+SeaBIOS 0.6.0
+=============
+
+Available on 20100326. Major changes in this release:
+
+* USB hub support
+* USB drive booting support
+* USB keyboard auto-repeat support
+* USB EHCI controller support
+* Several improvements to compatibility of PS2 port handlers for old
+ code
+* Support for qemu e820 interface
+* Several bug fixes and code cleanups
+
+SeaBIOS 0.5.1
+=============
+
+Available on 20100108. Major changes in this release:
+
+* Support for 32bit PCI BIOS calls
+* Support for int1589 calls
+* MPTable fixes for OpenBSD
+* ATA DMA and bus-mastering support
+* Several bug fixes and code cleanups
+
+SeaBIOS 0.5.0
+=============
+
+Available on 20091218. Major changes in this release:
+
+* Several enhancements ported from the Bochs BIOS derived code in qemu
+ and kvm
+* Support for parallel hardware initialization to reduce bootup times
+* Enable PCI option rom support by default (Bochs users must now
+ enable CONFIG_OPTIONROMS_DEPLOYED in src/config.h). Support added
+ for extracting option roms from qemu "fw_cfg".
+* Support USB UHCI and OHCI controllers
+* Initial support for USB keyboards
+* SeaBIOS can now be greater than 64K
+* Support for permanent low memory allocations
+* APIC "local interrupts" now enabled in SeaBIOS (on emulators)
+* Several bug fixes and code cleanups
+
+SeaBIOS 0.4.2
+=============
+
+Available on 20090909. Major changes in this release:
+
+* Implement Post Memory Manager (PMM) support. Use equivalent "malloc"
+ functions for internal allocations as well.
+* Refactor disk "block" interface for greater expandability
+* Support CBFS based floppy images
+* Allow boot menu to select either floppy to boot from
+* Increase ebda size to store a CDROM harddrive/floppy emulation
+ buffer
+* Support systems with multiple vga cards (only the card with the
+ legacy IO ranges mapped will have its option rom executed)
+* Make option rom memory be writable during option rom execution (on
+ emulators)
+* Compile version number into code and report on each boot
+* Several bug fixes and code cleanups
+
+SeaBIOS 0.4.1
+=============
+
+Available on 20090714. Major changes in this release:
+
+* Support older versions of gcc that predate "-fwhole-program" (eg,
+ v3.x)
+* Add initial port of "LGPL vga bios" code into tree in "vgasrc/"
+ directory
+* Handle ATA drives still "spinning up" during SeaBIOS drive detect
+* Add support for option rom Boot Connection Vectors (BCV)
+* Enhance boot menu to support booting from any drive or any cdrom
+* Support flash based Coreboot File System (CBFS)
+* Support booting from a CBFS "payload"
+* Support coreboot table forwarder
+* Support compile time definitions for multiple root PCI buses
+* New tools/readserial.py tool
+* Several bug fixes and code cleanups
+
+SeaBIOS 0.4.0
+=============
+
+Available on 20090206. Major changes in this release:
+
+* Add Bios Boot Specification (BBS) calls; add PnP call stubs
+* Support option roms stored in PCI rom BAR
+* Support rebooting on ctrl+alt+delete key press
+* Scan PCI devices for ATA adapters (don't assume legacy ISA ATA ports
+ are valid)
+* Attempt to automatically determine gcc capabilities/bugs during
+ build
+* Add script to layout 16bit sections at fixed offsets and in
+ compacted space
+* Introduce timestamp counter based delays
+* Support POST calls that are really a resume
+* Use new stack in EBDA for int13 disk calls to reduce stack usage
+* Support the EBDA being relocated by option roms
+* Move many variables from EBDA to global variables (stored in
+ f-segment)
+* Support for PCI bridges when iterating through PCI device list
+* Initial port of several KVM specific features from their Bochs BIOS
+ derived code
+* Access BDA using segment 0x40 and IVT using segment 0x00 (which
+ could be important for 16bit protected mode callers)
+* Several bug fixes and code cleanups
+
+SeaBIOS 0.3.0
+=============
+
+Available on 20080817. Major changes in this release:
+
+* Run boot code (int18/19) in 32bit mode
+* Rewrite of PS2 port handling - new code is more compatible with real
+ hardware
+* Initial support for int155f VGA option rom calls
+* Several bug fixes and code cleanups
+
+SeaBIOS 0.2.3
+=============
+
+Available on 20080702. Major changes in this release:
+
+* Initial support for running on real hardware with coreboot
+* Support parsing coreboot tables
+* Support relocating bios tables from high memory when running under
+ coreboot
+* Dynamic e820 map generation
+* Serial debug support
+* New tools/checkstack.py tool
+* Several bug fixes and code cleanups
+
+SeaBIOS 0.2.2
+=============
+
+Formerly known as "legacybios". Available on 20080501. Major changes
+in this release:
+
+* Several bug fixes and code cleanups
+
+SeaBIOS 0.2.1
+=============
+
+Formerly known as "legacybios". Available on 20080406. Major changes
+in this release:
+
+* Port of boot menu code from Bochs BIOS
+* Several bug fixes and code cleanups
+
+SeaBIOS 0.2.0
+=============
+
+Formerly known as "legacybios". Available on 20080330. Major changes
+in this release:
+
+* Completion of initial port of Bochs BIOS code to gcc.
diff --git a/roms/seabios/docs/SeaBIOS.md b/roms/seabios/docs/SeaBIOS.md
new file mode 100644
index 00000000..831bfced
--- /dev/null
+++ b/roms/seabios/docs/SeaBIOS.md
@@ -0,0 +1,15 @@
+SeaBIOS is an open source implementation of a 16bit X86 BIOS. SeaBIOS
+can run in an emulator or it can run natively on X86 hardware with the
+use of [coreboot](http://www.coreboot.org/).
+
+SeaBIOS is the default BIOS for [qemu](http://www.qemu.org/) and
+[kvm](http://www.linux-kvm.org/).
+
+The [coreboot SeaBIOS](http://www.coreboot.org/SeaBIOS) page has
+information on using SeaBIOS in coreboot. Please see the
+[releases](Releases) page for information on recent releases. See the
+[download](Download) page to obtain SeaBIOS.
+
+Please join the [mailing list](Mailinglist) to contribute to
+SeaBIOS. Information on the internals of SeaBIOS is available on the
+[Developer Documentation](Developer Documentation) page.
diff --git a/roms/seabios/scripts/acpi_extract.py b/roms/seabios/scripts/acpi_extract.py
new file mode 100755
index 00000000..60bbac3c
--- /dev/null
+++ b/roms/seabios/scripts/acpi_extract.py
@@ -0,0 +1,354 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Process mixed ASL/AML listing (.lst file) produced by iasl -l
+# Locate and execute ACPI_EXTRACT directives, output offset info
+#
+# Documentation of ACPI_EXTRACT_* directive tags:
+#
+# These directive tags output offset information from AML for BIOS runtime
+# table generation.
+# Each directive is of the form:
+# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
+# and causes the extractor to create an array
+# named <array_name> with offset, in the generated AML,
+# of an object of a given type in the following <Operator>.
+#
+# A directive must fit on a single code line.
+#
+# Object type in AML is verified, a mismatch causes a build failure.
+#
+# Directives and operators currently supported are:
+# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
+# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
+# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
+# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
+# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
+# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
+# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
+# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
+# ACPI_EXTRACT_DEVICE_START - start of Device() block
+# ACPI_EXTRACT_DEVICE_STRING - extract a NameString from Device()
+# ACPI_EXTRACT_DEVICE_END - offset at last byte of Device() + 1
+# ACPI_EXTRACT_PKG_START - start of Package block
+#
+# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
+#
+# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
+
+import re
+import sys
+import fileinput
+
+aml = []
+asl = []
+output = {}
+debug = ""
+
+class asl_line:
+ line = None
+ lineno = None
+ aml_offset = None
+
+def die(diag):
+ sys.stderr.write("Error: %s; %s\n" % (diag, debug))
+ sys.exit(1)
+
+#Store an ASL command, matching AML offset, and input line (for debugging)
+def add_asl(lineno, line):
+ l = asl_line()
+ l.line = line
+ l.lineno = lineno
+ l.aml_offset = len(aml)
+ asl.append(l)
+
+#Store an AML byte sequence
+#Verify that offset output by iasl matches # of bytes so far
+def add_aml(offset, line):
+ o = int(offset, 16)
+ # Sanity check: offset must match size of code so far
+ if (o != len(aml)):
+ die("Offset 0x%x != 0x%x" % (o, len(aml)))
+ # Strip any trailing dots and ASCII dump after "
+ line = re.sub(r'\s*\.*\s*".*$', "", line)
+ # Strip traling whitespace
+ line = re.sub(r'\s+$', "", line)
+ # Strip leading whitespace
+ line = re.sub(r'^\s+', "", line)
+ # Split on whitespace
+ code = re.split(r'\s+', line)
+ for c in code:
+ # Require a legal hex number, two digits
+ if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
+ die("Unexpected octet %s" % c)
+ aml.append(int(c, 16))
+
+# Process aml bytecode array, decoding AML
+def aml_pkglen_bytes(offset):
+ # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
+ pkglenbytes = aml[offset] >> 6
+ return pkglenbytes + 1
+
+def aml_pkglen(offset):
+ pkgstart = offset
+ pkglenbytes = aml_pkglen_bytes(offset)
+ pkglen = aml[offset] & 0x3F
+ # If multibyte, first nibble only uses bits 0-3
+ if ((pkglenbytes > 1) and (pkglen & 0x30)):
+ die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
+ (pkglen, pkglen))
+ offset += 1
+ pkglenbytes -= 1
+ for i in range(pkglenbytes):
+ pkglen |= aml[offset + i] << (i * 8 + 4)
+ if (len(aml) < pkgstart + pkglen):
+ die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
+ (pkglen, offset, len(aml)))
+ return pkglen
+
+# Given method offset, find its NameString offset
+def aml_method_string(offset):
+ #0x14 MethodOp PkgLength NameString MethodFlags TermList
+ if (aml[offset] != 0x14):
+ die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
+ (offset, aml[offset]))
+ offset += 1
+ pkglenbytes = aml_pkglen_bytes(offset)
+ offset += pkglenbytes
+ return offset
+
+# Given name offset, find its NameString offset
+def aml_name_string(offset):
+ #0x08 NameOp NameString DataRef
+ if (aml[offset] != 0x08):
+ die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
+ (offset, aml[offset]))
+ offset += 1
+ # Block Name Modifier. Skip it.
+ if (aml[offset] == 0x5c or aml[offset] == 0x5e):
+ offset += 1
+ return offset
+
+# Given data offset, find 8 byte buffer offset
+def aml_data_buffer8(offset):
+ #0x08 NameOp NameString DataRef
+ expect = [0x11, 0x0B, 0x0A, 0x08]
+ if (aml[offset:offset+4] != expect):
+ die( "Name offset 0x%x: expected %s actual %s" %
+ (offset, aml[offset:offset+4], expect))
+ return offset + len(expect)
+
+# Given data offset, find dword const offset
+def aml_data_dword_const(offset):
+ #0x08 NameOp NameString DataRef
+ if (aml[offset] != 0x0C):
+ die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
+ (offset, aml[offset]))
+ return offset + 1
+
+# Given data offset, find word const offset
+def aml_data_word_const(offset):
+ #0x08 NameOp NameString DataRef
+ if (aml[offset] != 0x0B):
+ die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
+ (offset, aml[offset]))
+ return offset + 1
+
+# Given data offset, find byte const offset
+def aml_data_byte_const(offset):
+ #0x08 NameOp NameString DataRef
+ if (aml[offset] != 0x0A):
+ die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
+ (offset, aml[offset]))
+ return offset + 1
+
+# Find name'd buffer8
+def aml_name_buffer8(offset):
+ return aml_data_buffer8(aml_name_string(offset) + 4)
+
+# Given name offset, find dword const offset
+def aml_name_dword_const(offset):
+ return aml_data_dword_const(aml_name_string(offset) + 4)
+
+# Given name offset, find word const offset
+def aml_name_word_const(offset):
+ return aml_data_word_const(aml_name_string(offset) + 4)
+
+# Given name offset, find byte const offset
+def aml_name_byte_const(offset):
+ return aml_data_byte_const(aml_name_string(offset) + 4)
+
+def aml_device_start(offset):
+ #0x5B 0x82 DeviceOp PkgLength NameString
+ if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x82)):
+ die( "Name offset 0x%x: expected 0x5B 0x82 actual 0x%x 0x%x" %
+ (offset, aml[offset], aml[offset + 1]))
+ return offset
+
+def aml_device_string(offset):
+ #0x5B 0x82 DeviceOp PkgLength NameString
+ start = aml_device_start(offset)
+ offset += 2
+ pkglenbytes = aml_pkglen_bytes(offset)
+ offset += pkglenbytes
+ return offset
+
+def aml_device_end(offset):
+ start = aml_device_start(offset)
+ offset += 2
+ pkglenbytes = aml_pkglen_bytes(offset)
+ pkglen = aml_pkglen(offset)
+ return offset + pkglen
+
+def aml_processor_start(offset):
+ #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+ if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
+ die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
+ (offset, aml[offset], aml[offset + 1]))
+ return offset
+
+def aml_processor_string(offset):
+ #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+ start = aml_processor_start(offset)
+ offset += 2
+ pkglenbytes = aml_pkglen_bytes(offset)
+ offset += pkglenbytes
+ return offset
+
+def aml_processor_end(offset):
+ start = aml_processor_start(offset)
+ offset += 2
+ pkglenbytes = aml_pkglen_bytes(offset)
+ pkglen = aml_pkglen(offset)
+ return offset + pkglen
+
+def aml_package_start(offset):
+ offset = aml_name_string(offset) + 4
+ # 0x12 PkgLength NumElements PackageElementList
+ if (aml[offset] != 0x12):
+ die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
+ (offset, aml[offset]))
+ offset += 1
+ return offset + aml_pkglen_bytes(offset) + 1
+
+lineno = 0
+for line in fileinput.input():
+ # Strip trailing newline
+ line = line.rstrip()
+ # line number and debug string to output in case of errors
+ lineno = lineno + 1
+ debug = "input line %d: %s" % (lineno, line)
+ #ASL listing: space, then line#, then ...., then code
+ pasl = re.compile('^\s+([0-9]+)(:\s\s|\.\.\.\.)\s*')
+ m = pasl.search(line)
+ if (m):
+ add_asl(lineno, pasl.sub("", line))
+ # AML listing: offset in hex, then ...., then code
+ paml = re.compile('^([0-9A-Fa-f]+)(:\s\s|\.\.\.\.)\s*')
+ m = paml.search(line)
+ if (m):
+ add_aml(m.group(1), paml.sub("", line))
+
+# Now go over code
+# Track AML offset of a previous non-empty ASL command
+prev_aml_offset = -1
+for i in range(len(asl)):
+ debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
+
+ l = asl[i].line
+
+ # skip if not an extract directive
+ a = len(re.findall(r'ACPI_EXTRACT', l))
+ if (not a):
+ # If not empty, store AML offset. Will be used for sanity checks
+ # IASL seems to put {}. at random places in the listing.
+ # Ignore any non-words for the purpose of this test.
+ m = re.search(r'\w+', l)
+ if (m):
+ prev_aml_offset = asl[i].aml_offset
+ continue
+
+ if (a > 1):
+ die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
+
+ mext = re.search(r'''
+ ^\s* # leading whitespace
+ /\*\s* # start C comment
+ (ACPI_EXTRACT_\w+) # directive: group(1)
+ \s+ # whitspace separates directive from array name
+ (\w+) # array name: group(2)
+ \s*\*/ # end of C comment
+ \s*$ # trailing whitespace
+ ''', l, re.VERBOSE)
+ if (not mext):
+ die("Stray ACPI_EXTRACT in input")
+
+ # previous command must have produced some AML,
+ # otherwise we are in a middle of a block
+ if (prev_aml_offset == asl[i].aml_offset):
+ die("ACPI_EXTRACT directive in the middle of a block")
+
+ directive = mext.group(1)
+ array = mext.group(2)
+ offset = asl[i].aml_offset
+
+ if (directive == "ACPI_EXTRACT_ALL_CODE"):
+ if array in output:
+ die("%s directive used more than once" % directive)
+ output[array] = aml
+ continue
+ if (directive == "ACPI_EXTRACT_NAME_BUFFER8"):
+ offset = aml_name_buffer8(offset)
+ elif (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
+ offset = aml_name_dword_const(offset)
+ elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
+ offset = aml_name_word_const(offset)
+ elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
+ offset = aml_name_byte_const(offset)
+ elif (directive == "ACPI_EXTRACT_NAME_STRING"):
+ offset = aml_name_string(offset)
+ elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
+ offset = aml_method_string(offset)
+ elif (directive == "ACPI_EXTRACT_DEVICE_START"):
+ offset = aml_device_start(offset)
+ elif (directive == "ACPI_EXTRACT_DEVICE_STRING"):
+ offset = aml_device_string(offset)
+ elif (directive == "ACPI_EXTRACT_DEVICE_END"):
+ offset = aml_device_end(offset)
+ elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
+ offset = aml_processor_start(offset)
+ elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
+ offset = aml_processor_string(offset)
+ elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
+ offset = aml_processor_end(offset)
+ elif (directive == "ACPI_EXTRACT_PKG_START"):
+ offset = aml_package_start(offset)
+ else:
+ die("Unsupported directive %s" % directive)
+
+ if array not in output:
+ output[array] = []
+ output[array].append(offset)
+
+debug = "at end of file"
+
+def get_value_type(maxvalue):
+ #Use type large enough to fit the table
+ if (maxvalue >= 0x10000):
+ return "int"
+ elif (maxvalue >= 0x100):
+ return "short"
+ else:
+ return "char"
+
+# Pretty print output
+for array in output.keys():
+ otype = get_value_type(max(output[array]))
+ odata = []
+ for value in output[array]:
+ odata.append("0x%x" % value)
+ sys.stdout.write("static unsigned %s %s[] = {\n" % (otype, array))
+ sys.stdout.write(",\n".join(odata))
+ sys.stdout.write('\n};\n')
diff --git a/roms/seabios/scripts/acpi_extract_preprocess.py b/roms/seabios/scripts/acpi_extract_preprocess.py
new file mode 100755
index 00000000..26981184
--- /dev/null
+++ b/roms/seabios/scripts/acpi_extract_preprocess.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Read a preprocessed ASL listing and put each ACPI_EXTRACT
+# directive in a comment, to make iasl skip it.
+# We also put each directive on a new line, the machinery
+# in scripts/acpi_extract.py requires this.
+
+import re
+import sys
+import fileinput
+
+def die(diag):
+ sys.stderr.write("Error: %s\n" % (diag))
+ sys.exit(1)
+
+# Note: () around pattern make split return matched string as part of list
+psplit = re.compile(r''' (
+ \b # At word boundary
+ ACPI_EXTRACT_\w+ # directive
+ \s+ # some whitespace
+ \w+ # array name
+ )''', re.VERBOSE)
+
+lineno = 0
+for line in fileinput.input():
+ # line number and debug string to output in case of errors
+ lineno = lineno + 1
+ debug = "input line %d: %s" % (lineno, line.rstrip())
+
+ s = psplit.split(line)
+ # The way split works, each odd item is the matching ACPI_EXTRACT directive.
+ # Put each in a comment, and on a line by itself.
+ for i in range(len(s)):
+ if (i % 2):
+ sys.stdout.write("\n/* %s */\n" % s[i])
+ else:
+ sys.stdout.write(s[i])
+
diff --git a/roms/seabios/scripts/buildrom.py b/roms/seabios/scripts/buildrom.py
new file mode 100755
index 00000000..0499049c
--- /dev/null
+++ b/roms/seabios/scripts/buildrom.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# Fill in checksum/size of an option rom, and pad it to proper length.
+#
+# Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys, struct
+
+from python23compat import as_bytes
+
+def alignpos(pos, alignbytes):
+ mask = alignbytes - 1
+ return (pos + mask) & ~mask
+
+def checksum(data):
+ if (sys.version_info > (3, 0)):
+ cksum = sum(data)
+ else:
+ cksum = sum(map(ord, data))
+ return struct.pack('<B', (0x100 - cksum) & 0xff)
+
+def main():
+ inname = sys.argv[1]
+ outname = sys.argv[2]
+
+ # Read data in
+ f = open(inname, 'rb')
+ data = f.read()
+ f.close()
+ count = len(data)
+
+ # Pad to a 512 byte boundary
+ data += as_bytes("\0") * (alignpos(count, 512) - count)
+ count = len(data)
+
+ # Check if a pci header is present
+ pcidata = ord(data[24:25]) + (ord(data[25:26]) << 8)
+ if pcidata != 0:
+ blocks = struct.pack('<H', int(count/512))
+ data = data[:pcidata + 16] + blocks + data[pcidata + 18:]
+
+ # Fill in size field; clear checksum field
+ blocks = struct.pack('<B', int(count/512))
+ data = data[:2] + blocks + data[3:6] + as_bytes("\0") + data[7:]
+
+ # Checksum rom
+ data = data[:6] + checksum(data) + data[7:]
+
+ # Write new rom
+ f = open(outname, 'wb')
+ f.write(data)
+ f.close()
+
+if __name__ == '__main__':
+ main()
diff --git a/roms/seabios/scripts/buildversion.sh b/roms/seabios/scripts/buildversion.sh
new file mode 100755
index 00000000..516aff5b
--- /dev/null
+++ b/roms/seabios/scripts/buildversion.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Script to generate a C file with version information.
+OUTFILE="$1"
+VAR16MODE="$2"
+
+# Extract version info
+if [ -z "$BUILD_VERSION" ]; then
+ if [ -d .git -o -f .git ]; then
+ VERSION="`git describe --tags --long --dirty`"
+ elif [ -f .version ]; then
+ VERSION="`cat .version`"
+ else
+ VERSION="?"
+ fi
+ VERSION="${VERSION}-`date +"%Y%m%d_%H%M%S"`-`hostname`"
+else
+ VERSION="$BUILD_VERSION"
+fi
+echo "Version: ${VERSION}"
+
+# Build header file
+if [ "$VAR16MODE" = "VAR16" ]; then
+ cat > ${OUTFILE} <<EOF
+#include "types.h"
+char VERSION[] VAR16 = "${VERSION}";
+EOF
+else
+ cat > ${OUTFILE} <<EOF
+char VERSION[] = "${VERSION}";
+EOF
+fi
diff --git a/roms/seabios/scripts/checkrom.py b/roms/seabios/scripts/checkrom.py
new file mode 100755
index 00000000..377277db
--- /dev/null
+++ b/roms/seabios/scripts/checkrom.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+# Script to check a bios image and report info on it.
+#
+# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys, struct
+import layoutrom, buildrom
+
+from python23compat import as_bytes
+
+def subst(data, offset, new):
+ return data[:offset] + new + data[offset + len(new):]
+
+def checksum(data, start, size, csum):
+ sumbyte = buildrom.checksum(data[start:start+size])
+ return subst(data, start+csum, sumbyte)
+
+def main():
+ # Get args
+ objinfo, finalsize, rawfile, outfile = sys.argv[1:]
+
+ # Read in symbols
+ objinfofile = open(objinfo, 'r')
+ symbols = layoutrom.parseObjDump(objinfofile, 'in')[1]
+
+ # Read in raw file
+ f = open(rawfile, 'rb')
+ rawdata = f.read()
+ f.close()
+ datasize = len(rawdata)
+ finalsize = int(finalsize) * 1024
+ if finalsize == 0:
+ finalsize = 64*1024
+ if datasize > 64*1024:
+ finalsize = 128*1024
+ if datasize > 128*1024:
+ finalsize = 256*1024
+ if datasize > finalsize:
+ print("Error! ROM doesn't fit (%d > %d)" % (datasize, finalsize))
+ print(" You have to either increate the size (CONFIG_ROM_SIZE)")
+ print(" or turn off some features (such as hardware support not")
+ print(" needed) to make it fit. Trying a more recent gcc version")
+ print(" might work too.")
+ sys.exit(1)
+
+ # Sanity checks
+ start = symbols['code32flat_start'].offset
+ end = symbols['code32flat_end'].offset
+ expend = layoutrom.BUILD_BIOS_ADDR + layoutrom.BUILD_BIOS_SIZE
+ if end != expend:
+ print("Error! Code does not end at 0x%x (got 0x%x)" % (
+ expend, end))
+ sys.exit(1)
+ if datasize > finalsize:
+ print("Error! Code is too big (0x%x vs 0x%x)" % (
+ datasize, finalsize))
+ sys.exit(1)
+ expdatasize = end - start
+ if datasize != expdatasize:
+ print("Error! Unknown extra data (0x%x vs 0x%x)" % (
+ datasize, expdatasize))
+ sys.exit(1)
+
+ # Fix up CSM Compatibility16 table
+ if 'csm_compat_table' in symbols and 'entry_csm' in symbols:
+ # Field offsets within EFI_COMPATIBILITY16_TABLE
+ ENTRY_FIELD_OFS = 14 # Compatibility16CallOffset (UINT16)
+ SIZE_FIELD_OFS = 5 # TableLength (UINT8)
+ CSUM_FIELD_OFS = 4 # TableChecksum (UINT8)
+
+ tableofs = symbols['csm_compat_table'].offset - symbols['code32flat_start'].offset
+ entry_addr = symbols['entry_csm'].offset - layoutrom.BUILD_BIOS_ADDR
+ entry_addr = struct.pack('<H', entry_addr)
+ rawdata = subst(rawdata, tableofs+ENTRY_FIELD_OFS, entry_addr)
+
+ tsfield = tableofs+SIZE_FIELD_OFS
+ tablesize = ord(rawdata[tsfield:tsfield+1])
+ rawdata = checksum(rawdata, tableofs, tablesize, CSUM_FIELD_OFS)
+
+ # Print statistics
+ runtimesize = end - symbols['code32init_end'].offset
+ print("Total size: %d Fixed: %d Free: %d (used %.1f%% of %dKiB rom)" % (
+ datasize, runtimesize, finalsize - datasize
+ , (datasize / float(finalsize)) * 100.0
+ , int(finalsize / 1024)))
+
+ # Write final file
+ f = open(outfile, 'wb')
+ f.write((as_bytes("\0") * (finalsize - datasize)) + rawdata)
+ f.close()
+
+if __name__ == '__main__':
+ main()
diff --git a/roms/seabios/scripts/checkstack.py b/roms/seabios/scripts/checkstack.py
new file mode 100755
index 00000000..b49b6c8c
--- /dev/null
+++ b/roms/seabios/scripts/checkstack.py
@@ -0,0 +1,227 @@
+#!/usr/bin/env python
+# Script that tries to find how much stack space each function in an
+# object is using.
+#
+# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Usage:
+# objdump -m i386 -M i8086 -M suffix -d out/rom16.o | scripts/checkstack.py
+
+import sys
+import re
+
+# Functions that change stacks
+STACKHOP = ['stack_hop', 'stack_hop_back']
+# List of functions we can assume are never called.
+#IGNORE = ['panic', '__dprintf']
+IGNORE = ['panic']
+
+OUTPUTDESC = """
+#funcname1[preamble_stack_usage,max_usage_with_callers]:
+# insn_addr:called_function [usage_at_call_point+caller_preamble,total_usage]
+#
+#funcname2[p,m,max_usage_to_yield_point]:
+# insn_addr:called_function [u+c,t,usage_to_yield_point]
+"""
+
+# Find out maximum stack usage for a function
+def calcmaxstack(funcs, funcaddr):
+ info = funcs[funcaddr]
+ # Find max of all nested calls.
+ maxusage = info[1]
+ maxyieldusage = doesyield = 0
+ if info[3] is not None:
+ maxyieldusage = info[3]
+ doesyield = 1
+ info[2] = maxusage
+ info[4] = info[3]
+ seenbefore = {}
+ totcalls = 0
+ for insnaddr, calladdr, usage in info[6]:
+ callinfo = funcs.get(calladdr)
+ if callinfo is None:
+ continue
+ if callinfo[2] is None:
+ calcmaxstack(funcs, calladdr)
+ if callinfo[0] not in seenbefore:
+ seenbefore[callinfo[0]] = 1
+ totcalls += 1 + callinfo[5]
+ funcnameroot = callinfo[0].split('.')[0]
+ if funcnameroot in IGNORE:
+ # This called function is ignored - don't contribute it to
+ # the max stack.
+ continue
+ if funcnameroot in STACKHOP:
+ if usage > maxusage:
+ maxusage = usage
+ if callinfo[4] is not None:
+ doesyield = 1
+ if usage > maxyieldusage:
+ maxyieldusage = usage
+ continue
+ totusage = usage + callinfo[2]
+ if totusage > maxusage:
+ maxusage = totusage
+ if callinfo[4] is not None:
+ doesyield = 1
+ totyieldusage = usage + callinfo[4]
+ if totyieldusage > maxyieldusage:
+ maxyieldusage = totyieldusage
+ info[2] = maxusage
+ if doesyield:
+ info[4] = maxyieldusage
+ info[5] = totcalls
+
+# Try to arrange output so that functions that call each other are
+# near each other.
+def orderfuncs(funcaddrs, availfuncs):
+ l = [(availfuncs[funcaddr][5], availfuncs[funcaddr][0], funcaddr)
+ for funcaddr in funcaddrs if funcaddr in availfuncs]
+ l.sort()
+ l.reverse()
+ out = []
+ while l:
+ count, name, funcaddr = l.pop(0)
+ if funcaddr not in availfuncs:
+ continue
+ calladdrs = [calls[1] for calls in availfuncs[funcaddr][6]]
+ del availfuncs[funcaddr]
+ out = out + orderfuncs(calladdrs, availfuncs) + [funcaddr]
+ return out
+
+# Update function info with a found "yield" point.
+def noteYield(info, stackusage):
+ prevyield = info[3]
+ if prevyield is None or prevyield < stackusage:
+ info[3] = stackusage
+
+# Update function info with a found "call" point.
+def noteCall(info, subfuncs, insnaddr, calladdr, stackusage):
+ if (calladdr, stackusage) in subfuncs:
+ # Already noted a nearly identical call - ignore this one.
+ return
+ info[6].append((insnaddr, calladdr, stackusage))
+ subfuncs[(calladdr, stackusage)] = 1
+
+hex_s = r'[0-9a-f]+'
+re_func = re.compile(r'^(?P<funcaddr>' + hex_s + r') <(?P<func>.*)>:$')
+re_asm = re.compile(
+ r'^[ ]*(?P<insnaddr>' + hex_s
+ + r'):\t.*\t(addr32 )?(?P<insn>.+?)[ ]*((?P<calladdr>' + hex_s
+ + r') <(?P<ref>.*)>)?$')
+re_usestack = re.compile(
+ r'^(push[f]?[lw])|(sub.* [$](?P<num>0x' + hex_s + r'),%esp)$')
+
+def calc():
+ # funcs[funcaddr] = [funcname, basicstackusage, maxstackusage
+ # , yieldusage, maxyieldusage, totalcalls
+ # , [(insnaddr, calladdr, stackusage), ...]]
+ funcs = {-1: ['<indirect>', 0, 0, None, None, 0, []]}
+ cur = None
+ atstart = 0
+ stackusage = 0
+
+ # Parse input lines
+ for line in sys.stdin.readlines():
+ m = re_func.match(line)
+ if m is not None:
+ # Found function
+ funcaddr = int(m.group('funcaddr'), 16)
+ funcs[funcaddr] = cur = [m.group('func'), 0, None, None, None, 0, []]
+ stackusage = 0
+ atstart = 1
+ subfuncs = {}
+ continue
+ m = re_asm.match(line)
+ if m is not None:
+ insn = m.group('insn')
+
+ im = re_usestack.match(insn)
+ if im is not None:
+ if insn.startswith('pushl') or insn.startswith('pushfl'):
+ stackusage += 4
+ continue
+ elif insn.startswith('pushw') or insn.startswith('pushfw'):
+ stackusage += 2
+ continue
+ stackusage += int(im.group('num'), 16)
+
+ if atstart:
+ if '%esp' in insn or insn.startswith('leal'):
+ # Still part of initial header
+ continue
+ cur[1] = stackusage
+ atstart = 0
+
+ insnaddr = m.group('insnaddr')
+ calladdr = m.group('calladdr')
+ if calladdr is None:
+ if insn.startswith('lcallw'):
+ noteCall(cur, subfuncs, insnaddr, -1, stackusage + 4)
+ noteYield(cur, stackusage + 4)
+ elif insn.startswith('int'):
+ noteCall(cur, subfuncs, insnaddr, -1, stackusage + 6)
+ noteYield(cur, stackusage + 6)
+ elif insn.startswith('sti'):
+ noteYield(cur, stackusage)
+ else:
+ # misc instruction
+ continue
+ else:
+ # Jump or call insn
+ calladdr = int(calladdr, 16)
+ ref = m.group('ref')
+ if '+' in ref:
+ # Inter-function jump.
+ pass
+ elif insn.startswith('j'):
+ # Tail call
+ noteCall(cur, subfuncs, insnaddr, calladdr, 0)
+ elif insn.startswith('calll'):
+ noteCall(cur, subfuncs, insnaddr, calladdr, stackusage + 4)
+ elif insn.startswith('callw'):
+ noteCall(cur, subfuncs, insnaddr, calladdr, stackusage + 2)
+ else:
+ print("unknown call", ref)
+ noteCall(cur, subfuncs, insnaddr, calladdr, stackusage)
+ # Reset stack usage to preamble usage
+ stackusage = cur[1]
+
+ #print("other", repr(line))
+
+ # Calculate maxstackusage
+ for funcaddr, info in funcs.items():
+ if info[2] is not None:
+ continue
+ calcmaxstack(funcs, funcaddr)
+
+ # Sort functions for output
+ funcaddrs = orderfuncs(funcs.keys(), funcs.copy())
+
+ # Show all functions
+ print(OUTPUTDESC)
+ for funcaddr in funcaddrs:
+ name, basicusage, maxusage, yieldusage, maxyieldusage, count, calls = \
+ funcs[funcaddr]
+ if maxusage == 0 and maxyieldusage is None:
+ continue
+ yieldstr = ""
+ if maxyieldusage is not None:
+ yieldstr = ",%d" % maxyieldusage
+ print("\n%s[%d,%d%s]:" % (name, basicusage, maxusage, yieldstr))
+ for insnaddr, calladdr, stackusage in calls:
+ callinfo = funcs.get(calladdr, ("<unknown>", 0, 0, 0, None))
+ yieldstr = ""
+ if callinfo[4] is not None:
+ yieldstr = ",%d" % (stackusage + callinfo[4])
+ print(" %04s:%-40s [%d+%d,%d%s]" % (
+ insnaddr, callinfo[0], stackusage, callinfo[1]
+ , stackusage+callinfo[2], yieldstr))
+
+def main():
+ calc()
+
+if __name__ == '__main__':
+ main()
diff --git a/roms/seabios/scripts/checksum.py b/roms/seabios/scripts/checksum.py
new file mode 100755
index 00000000..773fa7aa
--- /dev/null
+++ b/roms/seabios/scripts/checksum.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+# Script to report the checksum of a file.
+#
+# Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+
+def main():
+ data = sys.stdin.read()
+ ords = map(ord, data)
+ print("sum=%x\n" % sum(ords))
+
+if __name__ == '__main__':
+ main()
diff --git a/roms/seabios/scripts/encodeint.py b/roms/seabios/scripts/encodeint.py
new file mode 100755
index 00000000..0d34aee0
--- /dev/null
+++ b/roms/seabios/scripts/encodeint.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# Encode an integer in little endian format in a file.
+#
+# Copyright (C) 2011 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+import struct
+
+def main():
+ filename = sys.argv[1]
+ value = int(sys.argv[2], 0)
+
+ outval = struct.pack('<Q', value)
+ f = open(filename, 'wb')
+ f.write(outval)
+ f.close()
+
+if __name__ == '__main__':
+ main()
diff --git a/roms/seabios/scripts/gen-offsets.sh b/roms/seabios/scripts/gen-offsets.sh
new file mode 100755
index 00000000..73dede82
--- /dev/null
+++ b/roms/seabios/scripts/gen-offsets.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+# Extract definitions from an assembler file. This is based on code
+# from the Linux Kernel.
+INFILE=$1
+OUTFILE=$2
+cat > "$OUTFILE" <<EOF
+// This is an auto-generated file. DO NOT EDIT!
+// Generated with "$0 $@"
+#ifndef __ASM_OFFSETS_H
+#define __ASM_OFFSETS_H
+EOF
+sed -ne "/^->/{s:->#\(.*\):/* \1 */:; \
+ s:^->\([^ ]*\) [\$\#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
+ s:->::; p;}" < "$INFILE" >> "$OUTFILE"
+cat >> "$OUTFILE" <<EOF
+#endif // asm-offsets.h
+EOF
diff --git a/roms/seabios/scripts/kconfig/.gitignore b/roms/seabios/scripts/kconfig/.gitignore
new file mode 100644
index 00000000..be603c4f
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/.gitignore
@@ -0,0 +1,22 @@
+#
+# Generated files
+#
+config*
+*.lex.c
+*.tab.c
+*.tab.h
+zconf.hash.c
+*.moc
+gconf.glade.h
+*.pot
+*.mo
+
+#
+# configuration programs
+#
+conf
+mconf
+nconf
+qconf
+gconf
+kxgettext
diff --git a/roms/seabios/scripts/kconfig/Makefile b/roms/seabios/scripts/kconfig/Makefile
new file mode 100644
index 00000000..1c129361
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/Makefile
@@ -0,0 +1,331 @@
+# ===========================================================================
+# Kernel configuration targets
+# These targets are used from top-level makefile
+
+PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config \
+ localmodconfig localyesconfig
+
+ifdef KBUILD_KCONFIG
+Kconfig := $(KBUILD_KCONFIG)
+else
+Kconfig := Kconfig
+endif
+
+# We need this, in case the user has it in its environment
+unexport CONFIG_
+
+xconfig: $(obj)/qconf
+ $< $(Kconfig)
+
+gconfig: $(obj)/gconf
+ $< $(Kconfig)
+
+menuconfig: $(obj)/mconf
+ $< $(Kconfig)
+
+config: $(obj)/conf
+ $< --oldaskconfig $(Kconfig)
+
+nconfig: $(obj)/nconf
+ $< $(Kconfig)
+
+oldconfig: $(obj)/conf
+ $< --$@ $(Kconfig)
+
+silentoldconfig: $(obj)/conf
+ @echo " Build Kconfig config file"
+ $(Q)mkdir -p include/config include/generated
+ $(Q)$< --$@ $(Kconfig)
+
+localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
+ $(Q)mkdir -p include/config include/generated
+ $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config
+ $(Q)if [ -f .config ]; then \
+ cmp -s .tmp.config .config || \
+ (mv -f .config .config.old.1; \
+ mv -f .tmp.config .config; \
+ $(obj)/conf --silentoldconfig $(Kconfig); \
+ mv -f .config.old.1 .config.old) \
+ else \
+ mv -f .tmp.config .config; \
+ $(obj)/conf --silentoldconfig $(Kconfig); \
+ fi
+ $(Q)rm -f .tmp.config
+
+# Create new linux.pot file
+# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files
+update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
+ $(Q)echo " GEN config.pot"
+ $(Q)xgettext --default-domain=linux \
+ --add-comments --keyword=_ --keyword=N_ \
+ --from-code=UTF-8 \
+ --files-from=$(srctree)/scripts/kconfig/POTFILES.in \
+ --directory=$(srctree) --directory=$(objtree) \
+ --output $(obj)/config.pot
+ $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
+ $(Q)(for i in `ls $(srctree)/arch/*/Kconfig \
+ $(srctree)/arch/*/um/Kconfig`; \
+ do \
+ echo " GEN $$i"; \
+ $(obj)/kxgettext $$i \
+ >> $(obj)/config.pot; \
+ done )
+ $(Q)echo " GEN linux.pot"
+ $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
+ --output $(obj)/linux.pot
+ $(Q)rm -f $(obj)/config.pot
+
+PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig
+
+allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf
+ $< --$@ $(Kconfig)
+
+PHONY += listnewconfig olddefconfig oldnoconfig savedefconfig defconfig
+
+listnewconfig olddefconfig: $(obj)/conf
+ $< --$@ $(Kconfig)
+
+# oldnoconfig is an alias of olddefconfig, because people already are dependent
+# on its behavior(sets new symbols to their default value but not 'n') with the
+# counter-intuitive name.
+oldnoconfig: $(obj)/conf
+ $< --olddefconfig $(Kconfig)
+
+savedefconfig: $(obj)/conf
+ $< --$@=defconfig $(Kconfig)
+
+defconfig: $(obj)/conf
+ @echo " Build default config"
+ $(Q)$< --defconfig=/dev/null $(Kconfig)
+
+%_defconfig: $(obj)/conf
+ $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
+
+# Help text used by make help
+help:
+ @echo ' config - Update current config utilising a line-oriented program'
+ @echo ' nconfig - Update current config utilising a ncurses menu based program'
+ @echo ' menuconfig - Update current config utilising a menu based program'
+ @echo ' xconfig - Update current config utilising a QT based front-end'
+ @echo ' gconfig - Update current config utilising a GTK based front-end'
+ @echo ' oldconfig - Update current config utilising a provided .config as base'
+ @echo ' localmodconfig - Update current config disabling modules not loaded'
+ @echo ' localyesconfig - Update current config converting local mods to core'
+ @echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps'
+ @echo ' defconfig - New config with default from ARCH supplied defconfig'
+ @echo ' savedefconfig - Save current config as ./defconfig (minimal config)'
+ @echo ' allnoconfig - New config where all options are answered with no'
+ @echo ' allyesconfig - New config where all options are accepted with yes'
+ @echo ' allmodconfig - New config selecting modules when possible'
+ @echo ' alldefconfig - New config with all symbols set to default'
+ @echo ' randconfig - New config with random answer to all options'
+ @echo ' listnewconfig - List new options'
+ @echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their default value'
+
+# lxdialog stuff
+check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
+
+# Use recursively expanded variables so we do not call gcc unless
+# we really need to do so. (Do not call gcc as part of make mrproper)
+HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \
+ -DLOCALE
+
+# ===========================================================================
+# Shared Makefile for the various kconfig executables:
+# conf: Used for defconfig, oldconfig and related targets
+# nconf: Used for the nconfig target.
+# Utilizes ncurses
+# mconf: Used for the menuconfig target
+# Utilizes the lxdialog package
+# qconf: Used for the xconfig target
+# Based on QT which needs to be installed to compile it
+# gconf: Used for the gconfig target
+# Based on GTK which needs to be installed to compile it
+# object files used by all kconfig flavours
+
+lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
+lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
+
+conf-objs := conf.o zconf.tab.o
+mconf-objs := mconf.o zconf.tab.o $(lxdialog)
+nconf-objs := nconf.o zconf.tab.o nconf.gui.o
+kxgettext-objs := kxgettext.o zconf.tab.o
+qconf-cxxobjs := qconf.o
+qconf-objs := zconf.tab.o
+gconf-objs := gconf.o zconf.tab.o
+
+hostprogs-y := conf
+
+ifeq ($(MAKECMDGOALS),nconfig)
+ hostprogs-y += nconf
+endif
+
+ifeq ($(MAKECMDGOALS),menuconfig)
+ hostprogs-y += mconf
+endif
+
+ifeq ($(MAKECMDGOALS),update-po-config)
+ hostprogs-y += kxgettext
+endif
+
+ifeq ($(MAKECMDGOALS),xconfig)
+ qconf-target := 1
+endif
+ifeq ($(MAKECMDGOALS),gconfig)
+ gconf-target := 1
+endif
+
+
+ifeq ($(qconf-target),1)
+ hostprogs-y += qconf
+endif
+
+ifeq ($(gconf-target),1)
+ hostprogs-y += gconf
+endif
+
+clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck
+clean-files += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h
+clean-files += mconf qconf gconf nconf
+clean-files += config.pot linux.pot
+
+# Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
+PHONY += $(obj)/dochecklxdialog
+$(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog
+$(obj)/dochecklxdialog:
+ $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf)
+
+always := dochecklxdialog
+
+# Add environment specific flags
+HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS))
+
+# generated files seem to need this to find local include files
+HOSTCFLAGS_zconf.lex.o := -I$(src)
+HOSTCFLAGS_zconf.tab.o := -I$(src)
+
+LEX_PREFIX_zconf := zconf
+YACC_PREFIX_zconf := zconf
+
+HOSTLOADLIBES_qconf = $(KC_QT_LIBS)
+HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS)
+
+HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0`
+HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
+ -Wno-missing-prototypes
+
+HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
+
+HOSTLOADLIBES_nconf = $(shell \
+ pkg-config --libs menu panel ncurses 2>/dev/null \
+ || echo "-lmenu -lpanel -lncurses" )
+$(obj)/qconf.o: $(obj)/.tmp_qtcheck
+
+ifeq ($(qconf-target),1)
+$(obj)/.tmp_qtcheck: $(src)/Makefile
+-include $(obj)/.tmp_qtcheck
+
+# QT needs some extra effort...
+$(obj)/.tmp_qtcheck:
+ @set -e; echo " CHECK qt"; dir=""; pkg=""; \
+ if ! pkg-config --exists QtCore 2> /dev/null; then \
+ echo "* Unable to find the QT4 tool qmake. Trying to use QT3"; \
+ pkg-config --exists qt 2> /dev/null && pkg=qt; \
+ pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \
+ if [ -n "$$pkg" ]; then \
+ cflags="\$$(shell pkg-config $$pkg --cflags)"; \
+ libs="\$$(shell pkg-config $$pkg --libs)"; \
+ moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \
+ dir="$$(pkg-config $$pkg --variable=prefix)"; \
+ else \
+ for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \
+ if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \
+ done; \
+ if [ -z "$$dir" ]; then \
+ echo >&2 "*"; \
+ echo >&2 "* Unable to find any QT installation. Please make sure that"; \
+ echo >&2 "* the QT4 or QT3 development package is correctly installed and"; \
+ echo >&2 "* either qmake can be found or install pkg-config or set"; \
+ echo >&2 "* the QTDIR environment variable to the correct location."; \
+ echo >&2 "*"; \
+ false; \
+ fi; \
+ libpath=$$dir/lib; lib=qt; osdir=""; \
+ $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \
+ osdir=x$$($(HOSTCXX) -print-multi-os-directory); \
+ test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \
+ test -f $$libpath/libqt-mt.so && lib=qt-mt; \
+ cflags="-I$$dir/include"; \
+ libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \
+ moc="$$dir/bin/moc"; \
+ fi; \
+ if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \
+ echo "*"; \
+ echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \
+ echo "*"; \
+ moc="/usr/bin/moc"; \
+ fi; \
+ else \
+ cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \
+ libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \
+ moc="\$$(shell pkg-config QtCore --variable=moc_location)"; \
+ [ -n "$$moc" ] || moc="\$$(shell pkg-config QtCore --variable=prefix)/bin/moc"; \
+ fi; \
+ echo "KC_QT_CFLAGS=$$cflags" > $@; \
+ echo "KC_QT_LIBS=$$libs" >> $@; \
+ echo "KC_QT_MOC=$$moc" >> $@
+endif
+
+$(obj)/gconf.o: $(obj)/.tmp_gtkcheck
+
+ifeq ($(gconf-target),1)
+-include $(obj)/.tmp_gtkcheck
+
+# GTK needs some extra effort, too...
+$(obj)/.tmp_gtkcheck:
+ @if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then \
+ if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then \
+ touch $@; \
+ else \
+ echo >&2 "*"; \
+ echo >&2 "* GTK+ is present but version >= 2.0.0 is required."; \
+ echo >&2 "*"; \
+ false; \
+ fi \
+ else \
+ echo >&2 "*"; \
+ echo >&2 "* Unable to find the GTK+ installation. Please make sure that"; \
+ echo >&2 "* the GTK+ 2.0 development package is correctly installed..."; \
+ echo >&2 "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; \
+ echo >&2 "*"; \
+ false; \
+ fi
+endif
+
+$(obj)/zconf.tab.o: $(obj)/zconf.lex.c $(obj)/zconf.hash.c
+
+$(obj)/qconf.o: $(obj)/qconf.moc
+
+quiet_cmd_moc = MOC $@
+ cmd_moc = $(KC_QT_MOC) -i $< -o $@
+
+$(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck
+ $(call cmd,moc)
+
+# Extract gconf menu items for I18N support
+$(obj)/gconf.glade.h: $(obj)/gconf.glade
+ $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \
+ $(obj)/gconf.glade
+
+VPATH := $(srctree)
+
+$(obj)/%:: $(src)/%_shipped
+ $(Q)cat $< > $@
+
+host-cobjs := $(sort $(foreach m,$(hostprogs-y),$($(m)-objs)))
+host-cobjs := $(addprefix $(obj)/,$(host-cobjs))
+hostprogs-y := $(addprefix $(obj)/,$(hostprogs-y))
+$(host-cobjs) : $(obj)/%.o : $(src)/%.c
+ $(Q)$(HOSTCC) -I$(obj) -I$(srctree)/$(src) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) $(HOST_EXTRACFLAGS) -c -o $@ $<
+$(hostprogs-y) : $(obj)/% : $(host-cobjs)
+ $(Q)$(HOSTCC) $(HOSTLDFLAGS) -o $@ $(addprefix $(obj)/,$($(@F)-objs)) $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
diff --git a/roms/seabios/scripts/kconfig/POTFILES.in b/roms/seabios/scripts/kconfig/POTFILES.in
new file mode 100644
index 00000000..96745739
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/POTFILES.in
@@ -0,0 +1,12 @@
+scripts/kconfig/lxdialog/checklist.c
+scripts/kconfig/lxdialog/inputbox.c
+scripts/kconfig/lxdialog/menubox.c
+scripts/kconfig/lxdialog/textbox.c
+scripts/kconfig/lxdialog/util.c
+scripts/kconfig/lxdialog/yesno.c
+scripts/kconfig/mconf.c
+scripts/kconfig/conf.c
+scripts/kconfig/confdata.c
+scripts/kconfig/gconf.c
+scripts/kconfig/gconf.glade.h
+scripts/kconfig/qconf.cc
diff --git a/roms/seabios/scripts/kconfig/check.sh b/roms/seabios/scripts/kconfig/check.sh
new file mode 100755
index 00000000..55b79ba1
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/check.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Needed for systems without gettext
+$* -x c -o /dev/null - > /dev/null 2>&1 << EOF
+#include <libintl.h>
+int main()
+{
+ gettext("");
+ return 0;
+}
+EOF
+if [ ! "$?" -eq "0" ]; then
+ echo -DKBUILD_NO_NLS;
+fi
diff --git a/roms/seabios/scripts/kconfig/conf.c b/roms/seabios/scripts/kconfig/conf.c
new file mode 100644
index 00000000..fef75fc7
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/conf.c
@@ -0,0 +1,718 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <locale.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+static void xfgets(char *str, int size, FILE *in);
+
+enum input_mode {
+ oldaskconfig,
+ silentoldconfig,
+ oldconfig,
+ allnoconfig,
+ allyesconfig,
+ allmodconfig,
+ alldefconfig,
+ randconfig,
+ defconfig,
+ savedefconfig,
+ listnewconfig,
+ olddefconfig,
+} input_mode = oldaskconfig;
+
+static int indent = 1;
+static int tty_stdio;
+static int valid_stdin = 1;
+static int sync_kconfig;
+static int conf_cnt;
+static char line[128];
+static struct menu *rootEntry;
+
+static void print_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+
+ menu_get_ext_help(menu, &help);
+
+ printf("\n%s\n", str_get(&help));
+ str_free(&help);
+}
+
+static void strip(char *str)
+{
+ char *p = str;
+ int l;
+
+ while ((isspace(*p)))
+ p++;
+ l = strlen(p);
+ if (p != str)
+ memmove(str, p, l + 1);
+ if (!l)
+ return;
+ p = str + l - 1;
+ while ((isspace(*p)))
+ *p-- = 0;
+}
+
+static void check_stdin(void)
+{
+ if (!valid_stdin) {
+ printf(_("aborted!\n\n"));
+ printf(_("Console input/output is redirected. "));
+ printf(_("Run 'make oldconfig' to update configuration.\n\n"));
+ exit(1);
+ }
+}
+
+static int conf_askvalue(struct symbol *sym, const char *def)
+{
+ enum symbol_type type = sym_get_type(sym);
+
+ if (!sym_has_value(sym))
+ printf(_("(NEW) "));
+
+ line[0] = '\n';
+ line[1] = 0;
+
+ if (!sym_is_changable(sym)) {
+ printf("%s\n", def);
+ line[0] = '\n';
+ line[1] = 0;
+ return 0;
+ }
+
+ switch (input_mode) {
+ case oldconfig:
+ case silentoldconfig:
+ if (sym_has_value(sym)) {
+ printf("%s\n", def);
+ return 0;
+ }
+ check_stdin();
+ /* fall through */
+ case oldaskconfig:
+ fflush(stdout);
+ xfgets(line, 128, stdin);
+ if (!tty_stdio)
+ printf("\n");
+ return 1;
+ default:
+ break;
+ }
+
+ switch (type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ printf("%s\n", def);
+ return 1;
+ default:
+ ;
+ }
+ printf("%s", line);
+ return 1;
+}
+
+static int conf_string(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ const char *def;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+ printf("(%s) ", sym->name);
+ def = sym_get_string_value(sym);
+ if (sym_get_string_value(sym))
+ printf("[%s] ", def);
+ if (!conf_askvalue(sym, def))
+ return 0;
+ switch (line[0]) {
+ case '\n':
+ break;
+ case '?':
+ /* print help */
+ if (line[1] == '\n') {
+ print_help(menu);
+ def = NULL;
+ break;
+ }
+ /* fall through */
+ default:
+ line[strlen(line)-1] = 0;
+ def = line;
+ }
+ if (def && sym_set_string_value(sym, def))
+ return 0;
+ }
+}
+
+static int conf_sym(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ tristate oldval, newval;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+ if (sym->name)
+ printf("(%s) ", sym->name);
+ putchar('[');
+ oldval = sym_get_tristate_value(sym);
+ switch (oldval) {
+ case no:
+ putchar('N');
+ break;
+ case mod:
+ putchar('M');
+ break;
+ case yes:
+ putchar('Y');
+ break;
+ }
+ if (oldval != no && sym_tristate_within_range(sym, no))
+ printf("/n");
+ if (oldval != mod && sym_tristate_within_range(sym, mod))
+ printf("/m");
+ if (oldval != yes && sym_tristate_within_range(sym, yes))
+ printf("/y");
+ if (menu_has_help(menu))
+ printf("/?");
+ printf("] ");
+ if (!conf_askvalue(sym, sym_get_string_value(sym)))
+ return 0;
+ strip(line);
+
+ switch (line[0]) {
+ case 'n':
+ case 'N':
+ newval = no;
+ if (!line[1] || !strcmp(&line[1], "o"))
+ break;
+ continue;
+ case 'm':
+ case 'M':
+ newval = mod;
+ if (!line[1])
+ break;
+ continue;
+ case 'y':
+ case 'Y':
+ newval = yes;
+ if (!line[1] || !strcmp(&line[1], "es"))
+ break;
+ continue;
+ case 0:
+ newval = oldval;
+ break;
+ case '?':
+ goto help;
+ default:
+ continue;
+ }
+ if (sym_set_tristate_value(sym, newval))
+ return 0;
+help:
+ print_help(menu);
+ }
+}
+
+static int conf_choice(struct menu *menu)
+{
+ struct symbol *sym, *def_sym;
+ struct menu *child;
+ bool is_new;
+
+ sym = menu->sym;
+ is_new = !sym_has_value(sym);
+ if (sym_is_changable(sym)) {
+ conf_sym(menu);
+ sym_calc_value(sym);
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ return 0;
+ case yes:
+ break;
+ }
+ } else {
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+ return 0;
+ case yes:
+ break;
+ }
+ }
+
+ while (1) {
+ int cnt, def;
+
+ printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+ def_sym = sym_get_choice_value(sym);
+ cnt = def = 0;
+ line[0] = 0;
+ for (child = menu->list; child; child = child->next) {
+ if (!menu_is_visible(child))
+ continue;
+ if (!child->sym) {
+ printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
+ continue;
+ }
+ cnt++;
+ if (child->sym == def_sym) {
+ def = cnt;
+ printf("%*c", indent, '>');
+ } else
+ printf("%*c", indent, ' ');
+ printf(" %d. %s", cnt, _(menu_get_prompt(child)));
+ if (child->sym->name)
+ printf(" (%s)", child->sym->name);
+ if (!sym_has_value(child->sym))
+ printf(_(" (NEW)"));
+ printf("\n");
+ }
+ printf(_("%*schoice"), indent - 1, "");
+ if (cnt == 1) {
+ printf("[1]: 1\n");
+ goto conf_childs;
+ }
+ printf("[1-%d", cnt);
+ if (menu_has_help(menu))
+ printf("?");
+ printf("]: ");
+ switch (input_mode) {
+ case oldconfig:
+ case silentoldconfig:
+ if (!is_new) {
+ cnt = def;
+ printf("%d\n", cnt);
+ break;
+ }
+ check_stdin();
+ /* fall through */
+ case oldaskconfig:
+ fflush(stdout);
+ xfgets(line, 128, stdin);
+ strip(line);
+ if (line[0] == '?') {
+ print_help(menu);
+ continue;
+ }
+ if (!line[0])
+ cnt = def;
+ else if (isdigit(line[0]))
+ cnt = atoi(line);
+ else
+ continue;
+ break;
+ default:
+ break;
+ }
+
+ conf_childs:
+ for (child = menu->list; child; child = child->next) {
+ if (!child->sym || !menu_is_visible(child))
+ continue;
+ if (!--cnt)
+ break;
+ }
+ if (!child)
+ continue;
+ if (line[0] && line[strlen(line) - 1] == '?') {
+ print_help(child);
+ continue;
+ }
+ sym_set_choice_value(sym, child->sym);
+ for (child = child->list; child; child = child->next) {
+ indent += 2;
+ conf(child);
+ indent -= 2;
+ }
+ return 1;
+ }
+}
+
+static void conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (prop) {
+ const char *prompt;
+
+ switch (prop->type) {
+ case P_MENU:
+ if ((input_mode == silentoldconfig ||
+ input_mode == listnewconfig ||
+ input_mode == olddefconfig) &&
+ rootEntry != menu) {
+ check_conf(menu);
+ return;
+ }
+ /* fall through */
+ case P_COMMENT:
+ prompt = menu_get_prompt(menu);
+ if (prompt)
+ printf("%*c\n%*c %s\n%*c\n",
+ indent, '*',
+ indent, '*', _(prompt),
+ indent, '*');
+ default:
+ ;
+ }
+ }
+
+ if (!sym)
+ goto conf_childs;
+
+ if (sym_is_choice(sym)) {
+ conf_choice(menu);
+ if (sym->curr.tri != mod)
+ return;
+ goto conf_childs;
+ }
+
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ conf_string(menu);
+ break;
+ default:
+ conf_sym(menu);
+ break;
+ }
+
+conf_childs:
+ if (sym)
+ indent += 2;
+ for (child = menu->list; child; child = child->next)
+ conf(child);
+ if (sym)
+ indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ if (sym && !sym_has_value(sym)) {
+ if (sym_is_changable(sym) ||
+ (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
+ if (input_mode == listnewconfig) {
+ if (sym->name && !sym_is_choice_value(sym)) {
+ printf("%s%s\n", CONFIG_, sym->name);
+ }
+ } else if (input_mode != olddefconfig) {
+ if (!conf_cnt++)
+ printf(_("*\n* Restart config...\n*\n"));
+ rootEntry = menu_get_parent_menu(menu);
+ conf(rootEntry);
+ }
+ }
+ }
+
+ for (child = menu->list; child; child = child->next)
+ check_conf(child);
+}
+
+static struct option long_opts[] = {
+ {"oldaskconfig", no_argument, NULL, oldaskconfig},
+ {"oldconfig", no_argument, NULL, oldconfig},
+ {"silentoldconfig", no_argument, NULL, silentoldconfig},
+ {"defconfig", optional_argument, NULL, defconfig},
+ {"savedefconfig", required_argument, NULL, savedefconfig},
+ {"allnoconfig", no_argument, NULL, allnoconfig},
+ {"allyesconfig", no_argument, NULL, allyesconfig},
+ {"allmodconfig", no_argument, NULL, allmodconfig},
+ {"alldefconfig", no_argument, NULL, alldefconfig},
+ {"randconfig", no_argument, NULL, randconfig},
+ {"listnewconfig", no_argument, NULL, listnewconfig},
+ {"olddefconfig", no_argument, NULL, olddefconfig},
+ /*
+ * oldnoconfig is an alias of olddefconfig, because people already
+ * are dependent on its behavior(sets new symbols to their default
+ * value but not 'n') with the counter-intuitive name.
+ */
+ {"oldnoconfig", no_argument, NULL, olddefconfig},
+ {NULL, 0, NULL, 0}
+};
+
+static void conf_usage(const char *progname)
+{
+
+ printf("Usage: %s [option] <kconfig-file>\n", progname);
+ printf("[option] is _one_ of the following:\n");
+ printf(" --listnewconfig List new options\n");
+ printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
+ printf(" --oldconfig Update a configuration using a provided .config as base\n");
+ printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n");
+ printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n");
+ printf(" --oldnoconfig An alias of olddefconfig\n");
+ printf(" --defconfig <file> New config with default defined in <file>\n");
+ printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
+ printf(" --allnoconfig New config where all options are answered with no\n");
+ printf(" --allyesconfig New config where all options are answered with yes\n");
+ printf(" --allmodconfig New config where all options are answered with mod\n");
+ printf(" --alldefconfig New config with all symbols set to default\n");
+ printf(" --randconfig New config with random answer to all options\n");
+}
+
+int main(int ac, char **av)
+{
+ const char *progname = av[0];
+ int opt;
+ const char *name, *defconfig_file = NULL /* gcc uninit */;
+ struct stat tmpstat;
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ tty_stdio = isatty(0) && isatty(1) && isatty(2);
+
+ while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) {
+ input_mode = (enum input_mode)opt;
+ switch (opt) {
+ case silentoldconfig:
+ sync_kconfig = 1;
+ break;
+ case defconfig:
+ case savedefconfig:
+ defconfig_file = optarg;
+ break;
+ case randconfig:
+ {
+ struct timeval now;
+ unsigned int seed;
+ char *seed_env;
+
+ /*
+ * Use microseconds derived seed,
+ * compensate for systems where it may be zero
+ */
+ gettimeofday(&now, NULL);
+ seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
+
+ seed_env = getenv("KCONFIG_SEED");
+ if( seed_env && *seed_env ) {
+ char *endp;
+ int tmp = (int)strtol(seed_env, &endp, 0);
+ if (*endp == '\0') {
+ seed = tmp;
+ }
+ }
+ fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed );
+ srand(seed);
+ break;
+ }
+ case oldaskconfig:
+ case oldconfig:
+ case allnoconfig:
+ case allyesconfig:
+ case allmodconfig:
+ case alldefconfig:
+ case listnewconfig:
+ case olddefconfig:
+ break;
+ case '?':
+ conf_usage(progname);
+ exit(1);
+ break;
+ }
+ }
+ if (ac == optind) {
+ printf(_("%s: Kconfig file missing\n"), av[0]);
+ conf_usage(progname);
+ exit(1);
+ }
+ name = av[optind];
+ conf_parse(name);
+ //zconfdump(stdout);
+ if (sync_kconfig) {
+ name = conf_get_configname();
+ if (stat(name, &tmpstat)) {
+ fprintf(stderr, _("***\n"
+ "*** Configuration file \"%s\" not found!\n"
+ "***\n"
+ "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
+ "*** \"make menuconfig\" or \"make xconfig\").\n"
+ "***\n"), name);
+ exit(1);
+ }
+ }
+
+ switch (input_mode) {
+ case defconfig:
+ if (!defconfig_file)
+ defconfig_file = conf_get_default_confname();
+ if (conf_read(defconfig_file)) {
+ printf(_("***\n"
+ "*** Can't find default configuration \"%s\"!\n"
+ "***\n"), defconfig_file);
+ exit(1);
+ }
+ break;
+ case savedefconfig:
+ case silentoldconfig:
+ case oldaskconfig:
+ case oldconfig:
+ case listnewconfig:
+ case olddefconfig:
+ conf_read(NULL);
+ break;
+ case allnoconfig:
+ case allyesconfig:
+ case allmodconfig:
+ case alldefconfig:
+ case randconfig:
+ name = getenv("KCONFIG_ALLCONFIG");
+ if (!name)
+ break;
+ if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
+ if (conf_read_simple(name, S_DEF_USER)) {
+ fprintf(stderr,
+ _("*** Can't read seed configuration \"%s\"!\n"),
+ name);
+ exit(1);
+ }
+ break;
+ }
+ switch (input_mode) {
+ case allnoconfig: name = "allno.config"; break;
+ case allyesconfig: name = "allyes.config"; break;
+ case allmodconfig: name = "allmod.config"; break;
+ case alldefconfig: name = "alldef.config"; break;
+ case randconfig: name = "allrandom.config"; break;
+ default: break;
+ }
+ if (conf_read_simple(name, S_DEF_USER) &&
+ conf_read_simple("all.config", S_DEF_USER)) {
+ fprintf(stderr,
+ _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"),
+ name);
+ exit(1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (sync_kconfig) {
+ if (conf_get_changed()) {
+ name = getenv("KCONFIG_NOSILENTUPDATE");
+ if (name && *name) {
+ fprintf(stderr,
+ _("\n*** The configuration requires explicit update.\n\n"));
+ return 1;
+ }
+ }
+ valid_stdin = tty_stdio;
+ }
+
+ switch (input_mode) {
+ case allnoconfig:
+ conf_set_all_new_symbols(def_no);
+ break;
+ case allyesconfig:
+ conf_set_all_new_symbols(def_yes);
+ break;
+ case allmodconfig:
+ conf_set_all_new_symbols(def_mod);
+ break;
+ case alldefconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case randconfig:
+ /* Really nothing to do in this loop */
+ while (conf_set_all_new_symbols(def_random)) ;
+ break;
+ case defconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case savedefconfig:
+ break;
+ case oldaskconfig:
+ rootEntry = &rootmenu;
+ conf(&rootmenu);
+ input_mode = silentoldconfig;
+ /* fall through */
+ case oldconfig:
+ case listnewconfig:
+ case olddefconfig:
+ case silentoldconfig:
+ /* Update until a loop caused no more changes */
+ do {
+ conf_cnt = 0;
+ check_conf(&rootmenu);
+ } while (conf_cnt &&
+ (input_mode != listnewconfig &&
+ input_mode != olddefconfig));
+ break;
+ }
+
+ if (sync_kconfig) {
+ /* silentoldconfig is used during the build so we shall update autoconf.
+ * All other commands are only used to generate a config.
+ */
+ if (conf_get_changed() && conf_write(NULL)) {
+ fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+ exit(1);
+ }
+ if (conf_write_autoconf()) {
+ fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
+ return 1;
+ }
+ } else if (input_mode == savedefconfig) {
+ if (conf_write_defconfig(defconfig_file)) {
+ fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
+ defconfig_file);
+ return 1;
+ }
+ } else if (input_mode != listnewconfig) {
+ if (conf_write(NULL)) {
+ fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+ exit(1);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Helper function to facilitate fgets() by Jean Sacren.
+ */
+void xfgets(char *str, int size, FILE *in)
+{
+ if (fgets(str, size, in) == NULL)
+ fprintf(stderr, "\nError in reading or end of file.\n");
+}
diff --git a/roms/seabios/scripts/kconfig/confdata.c b/roms/seabios/scripts/kconfig/confdata.c
new file mode 100644
index 00000000..08e75599
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/confdata.c
@@ -0,0 +1,1250 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "lkc.h"
+
+static void conf_warning(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static void conf_message(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings, conf_unsaved;
+
+const char conf_defname[] = "arch/$ARCH/defconfig";
+
+static void conf_warning(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ conf_warnings++;
+}
+
+static void conf_default_message_callback(const char *fmt, va_list ap)
+{
+ printf("#\n# ");
+ vprintf(fmt, ap);
+ printf("\n#\n");
+}
+
+static void (*conf_message_callback) (const char *fmt, va_list ap) =
+ conf_default_message_callback;
+void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap))
+{
+ conf_message_callback = fn;
+}
+
+static void conf_message(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (conf_message_callback)
+ conf_message_callback(fmt, ap);
+}
+
+const char *conf_get_configname(void)
+{
+ char *name = getenv("KCONFIG_CONFIG");
+
+ return name ? name : ".config";
+}
+
+const char *conf_get_autoconfig_name(void)
+{
+ char *name = getenv("KCONFIG_AUTOCONFIG");
+
+ return name ? name : "include/config/auto.conf";
+}
+
+static char *conf_expand_value(const char *in)
+{
+ struct symbol *sym;
+ const char *src;
+ static char res_value[SYMBOL_MAXLENGTH];
+ char *dst, name[SYMBOL_MAXLENGTH];
+
+ res_value[0] = 0;
+ dst = name;
+ while ((src = strchr(in, '$'))) {
+ strncat(res_value, in, src - in);
+ src++;
+ dst = name;
+ while (isalnum(*src) || *src == '_')
+ *dst++ = *src++;
+ *dst = 0;
+ sym = sym_lookup(name, 0);
+ sym_calc_value(sym);
+ strcat(res_value, sym_get_string_value(sym));
+ in = src;
+ }
+ strcat(res_value, in);
+
+ return res_value;
+}
+
+char *conf_get_default_confname(void)
+{
+ struct stat buf;
+ static char fullname[PATH_MAX+1];
+ char *env, *name;
+
+ name = conf_expand_value(conf_defname);
+ env = getenv(SRCTREE);
+ if (env) {
+ sprintf(fullname, "%s/%s", env, name);
+ if (!stat(fullname, &buf))
+ return fullname;
+ }
+ return name;
+}
+
+static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
+{
+ char *p2;
+
+ switch (sym->type) {
+ case S_TRISTATE:
+ if (p[0] == 'm') {
+ sym->def[def].tri = mod;
+ sym->flags |= def_flags;
+ break;
+ }
+ /* fall through */
+ case S_BOOLEAN:
+ if (p[0] == 'y') {
+ sym->def[def].tri = yes;
+ sym->flags |= def_flags;
+ break;
+ }
+ if (p[0] == 'n') {
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ }
+ if (def != S_DEF_AUTO)
+ conf_warning("symbol value '%s' invalid for %s",
+ p, sym->name);
+ return 1;
+ case S_OTHER:
+ if (*p != '"') {
+ for (p2 = p; *p2 && !isspace(*p2); p2++)
+ ;
+ sym->type = S_STRING;
+ goto done;
+ }
+ /* fall through */
+ case S_STRING:
+ if (*p++ != '"')
+ break;
+ for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+ if (*p2 == '"') {
+ *p2 = 0;
+ break;
+ }
+ memmove(p2, p2 + 1, strlen(p2));
+ }
+ if (!p2) {
+ if (def != S_DEF_AUTO)
+ conf_warning("invalid string found");
+ return 1;
+ }
+ /* fall through */
+ case S_INT:
+ case S_HEX:
+ done:
+ if (sym_string_valid(sym, p)) {
+ sym->def[def].val = strdup(p);
+ sym->flags |= def_flags;
+ } else {
+ if (def != S_DEF_AUTO)
+ conf_warning("symbol value '%s' invalid for %s",
+ p, sym->name);
+ return 1;
+ }
+ break;
+ default:
+ ;
+ }
+ return 0;
+}
+
+#define LINE_GROWTH 16
+static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
+{
+ char *nline;
+ size_t new_size = slen + 1;
+ if (new_size > *n) {
+ new_size += LINE_GROWTH - 1;
+ new_size *= 2;
+ nline = realloc(*lineptr, new_size);
+ if (!nline)
+ return -1;
+
+ *lineptr = nline;
+ *n = new_size;
+ }
+
+ (*lineptr)[slen] = c;
+
+ return 0;
+}
+
+static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
+{
+ char *line = *lineptr;
+ size_t slen = 0;
+
+ for (;;) {
+ int c = getc(stream);
+
+ switch (c) {
+ case '\n':
+ if (add_byte(c, &line, slen, n) < 0)
+ goto e_out;
+ slen++;
+ /* fall through */
+ case EOF:
+ if (add_byte('\0', &line, slen, n) < 0)
+ goto e_out;
+ *lineptr = line;
+ if (slen == 0)
+ return -1;
+ return slen;
+ default:
+ if (add_byte(c, &line, slen, n) < 0)
+ goto e_out;
+ slen++;
+ }
+ }
+
+e_out:
+ line[slen-1] = '\0';
+ *lineptr = line;
+ return -1;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+ FILE *in = NULL;
+ char *line = NULL;
+ size_t line_asize = 0;
+ char *p, *p2;
+ struct symbol *sym;
+ int i, def_flags;
+
+ if (name) {
+ in = zconf_fopen(name);
+ } else {
+ struct property *prop;
+
+ name = conf_get_configname();
+ in = zconf_fopen(name);
+ if (in)
+ goto load;
+ sym_add_change_count(1);
+ if (!sym_defconfig_list) {
+ if (modules_sym)
+ sym_calc_value(modules_sym);
+ return 1;
+ }
+
+ for_all_defaults(sym_defconfig_list, prop) {
+ if (expr_calc_value(prop->visible.expr) == no ||
+ prop->expr->type != E_SYMBOL)
+ continue;
+ name = conf_expand_value(prop->expr->left.sym->name);
+ in = zconf_fopen(name);
+ if (in) {
+ conf_message(_("using defaults found in %s"),
+ name);
+ goto load;
+ }
+ }
+ }
+ if (!in)
+ return 1;
+
+load:
+ conf_filename = name;
+ conf_lineno = 0;
+ conf_warnings = 0;
+ conf_unsaved = 0;
+
+ def_flags = SYMBOL_DEF << def;
+ for_all_symbols(i, sym) {
+ sym->flags |= SYMBOL_CHANGED;
+ sym->flags &= ~(def_flags|SYMBOL_VALID);
+ if (sym_is_choice(sym))
+ sym->flags |= def_flags;
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ if (sym->def[def].val)
+ free(sym->def[def].val);
+ /* fall through */
+ default:
+ sym->def[def].val = NULL;
+ sym->def[def].tri = no;
+ }
+ }
+
+ while (compat_getline(&line, &line_asize, in) != -1) {
+ conf_lineno++;
+ sym = NULL;
+ if (line[0] == '#') {
+ if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
+ continue;
+ p = strchr(line + 2 + strlen(CONFIG_), ' ');
+ if (!p)
+ continue;
+ *p++ = 0;
+ if (strncmp(p, "is not set", 10))
+ continue;
+ if (def == S_DEF_USER) {
+ sym = sym_find(line + 2 + strlen(CONFIG_));
+ if (!sym) {
+ sym_add_change_count(1);
+ goto setsym;
+ }
+ } else {
+ sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
+ if (sym->type == S_UNKNOWN)
+ sym->type = S_BOOLEAN;
+ }
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ default:
+ ;
+ }
+ } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
+ p = strchr(line + strlen(CONFIG_), '=');
+ if (!p)
+ continue;
+ *p++ = 0;
+ p2 = strchr(p, '\n');
+ if (p2) {
+ *p2-- = 0;
+ if (*p2 == '\r')
+ *p2 = 0;
+ }
+ if (def == S_DEF_USER) {
+ sym = sym_find(line + strlen(CONFIG_));
+ if (!sym) {
+ sym_add_change_count(1);
+ goto setsym;
+ }
+ } else {
+ sym = sym_lookup(line + strlen(CONFIG_), 0);
+ if (sym->type == S_UNKNOWN)
+ sym->type = S_OTHER;
+ }
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ if (conf_set_sym_val(sym, def, def_flags, p))
+ continue;
+ } else {
+ if (line[0] != '\r' && line[0] != '\n')
+ conf_warning("unexpected data");
+ continue;
+ }
+setsym:
+ if (sym && sym_is_choice_value(sym)) {
+ struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+ switch (sym->def[def].tri) {
+ case no:
+ break;
+ case mod:
+ if (cs->def[def].tri == yes) {
+ conf_warning("%s creates inconsistent choice state", sym->name);
+ cs->flags &= ~def_flags;
+ }
+ break;
+ case yes:
+ if (cs->def[def].tri != no)
+ conf_warning("override: %s changes choice state", sym->name);
+ cs->def[def].val = sym;
+ break;
+ }
+ cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
+ }
+ }
+ free(line);
+ fclose(in);
+
+ if (modules_sym)
+ sym_calc_value(modules_sym);
+ return 0;
+}
+
+int conf_read(const char *name)
+{
+ struct symbol *sym;
+ int i;
+
+ sym_set_change_count(0);
+
+ if (conf_read_simple(name, S_DEF_USER))
+ return 1;
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
+ continue;
+ if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+ /* check that calculated value agrees with saved value */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
+ break;
+ if (!sym_is_choice(sym))
+ continue;
+ /* fall through */
+ default:
+ if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+ continue;
+ break;
+ }
+ } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+ /* no previous value and not saved */
+ continue;
+ conf_unsaved++;
+ /* maybe print value in verbose mode... */
+ }
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+ /* Reset values of generates values, so they'll appear
+ * as new, if they should become visible, but that
+ * doesn't quite work if the Kconfig and the saved
+ * configuration disagree.
+ */
+ if (sym->visible == no && !conf_unsaved)
+ sym->flags &= ~SYMBOL_DEF_USER;
+ switch (sym->type) {
+ case S_STRING:
+ case S_INT:
+ case S_HEX:
+ /* Reset a string value if it's out of range */
+ if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+ break;
+ sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+ conf_unsaved++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ sym_add_change_count(conf_warnings || conf_unsaved);
+
+ return 0;
+}
+
+/*
+ * Kconfig configuration printer
+ *
+ * This printer is used when generating the resulting configuration after
+ * kconfig invocation and `defconfig' files. Unset symbol might be omitted by
+ * passing a non-NULL argument to the printer.
+ *
+ */
+static void
+kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (*value == 'n') {
+ bool skip_unset = (arg != NULL);
+
+ if (!skip_unset)
+ fprintf(fp, "# %s%s is not set\n",
+ CONFIG_, sym->name);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
+}
+
+static void
+kconfig_print_comment(FILE *fp, const char *value, void *arg)
+{
+ const char *p = value;
+ size_t l;
+
+ for (;;) {
+ l = strcspn(p, "\n");
+ fprintf(fp, "#");
+ if (l) {
+ fprintf(fp, " ");
+ xfwrite(p, l, 1, fp);
+ p += l;
+ }
+ fprintf(fp, "\n");
+ if (*p++ == '\0')
+ break;
+ }
+}
+
+static struct conf_printer kconfig_printer_cb =
+{
+ .print_symbol = kconfig_print_symbol,
+ .print_comment = kconfig_print_comment,
+};
+
+/*
+ * Header printer
+ *
+ * This printer is used when generating the `include/generated/autoconf.h' file.
+ */
+static void
+header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE: {
+ const char *suffix = "";
+
+ switch (*value) {
+ case 'n':
+ fprintf(fp, "#define %s%s%s 0\n",
+ CONFIG_, sym->name, suffix);
+ break;
+ case 'm':
+ suffix = "_MODULE";
+ /* fall through */
+ default:
+ fprintf(fp, "#define %s%s%s 1\n",
+ CONFIG_, sym->name, suffix);
+ }
+ break;
+ }
+ case S_HEX: {
+ const char *prefix = "";
+
+ if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
+ prefix = "0x";
+ if (!value[0])
+ prefix = "0";
+ fprintf(fp, "#define %s%s %s%s\n",
+ CONFIG_, sym->name, prefix, value);
+ break;
+ }
+ case S_STRING:
+ case S_INT:
+ fprintf(fp, "#define %s%s %s\n",
+ CONFIG_, sym->name, value);
+ break;
+ default:
+ break;
+ }
+
+}
+
+static void
+header_print_comment(FILE *fp, const char *value, void *arg)
+{
+ const char *p = value;
+ size_t l;
+
+ fprintf(fp, "/*\n");
+ for (;;) {
+ l = strcspn(p, "\n");
+ fprintf(fp, " *");
+ if (l) {
+ fprintf(fp, " ");
+ xfwrite(p, l, 1, fp);
+ p += l;
+ }
+ fprintf(fp, "\n");
+ if (*p++ == '\0')
+ break;
+ }
+ fprintf(fp, " */\n");
+}
+
+static struct conf_printer header_printer_cb =
+{
+ .print_symbol = header_print_symbol,
+ .print_comment = header_print_comment,
+};
+
+/*
+ * Tristate printer
+ *
+ * This printer is used when generating the `include/config/tristate.conf' file.
+ */
+static void
+tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+ if (sym->type == S_TRISTATE && *value != 'n')
+ fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value));
+}
+
+static struct conf_printer tristate_printer_cb =
+{
+ .print_symbol = tristate_print_symbol,
+ .print_comment = kconfig_print_comment,
+};
+
+static void conf_write_symbol(FILE *fp, struct symbol *sym,
+ struct conf_printer *printer, void *printer_arg)
+{
+ const char *str;
+
+ switch (sym->type) {
+ case S_OTHER:
+ case S_UNKNOWN:
+ break;
+ case S_STRING:
+ str = sym_get_string_value(sym);
+ str = sym_escape_string_value(str);
+ printer->print_symbol(fp, sym, str, printer_arg);
+ free((void *)str);
+ break;
+ default:
+ str = sym_get_string_value(sym);
+ printer->print_symbol(fp, sym, str, printer_arg);
+ }
+}
+
+static void
+conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
+{
+ char buf[256];
+
+ snprintf(buf, sizeof(buf),
+ "\n"
+ "Automatically generated file; DO NOT EDIT.\n"
+ "%s\n",
+ rootmenu.prompt->text);
+
+ printer->print_comment(fp, buf, printer_arg);
+}
+
+/*
+ * Write out a minimal config.
+ * All values that has default values are skipped as this is redundant.
+ */
+int conf_write_defconfig(const char *filename)
+{
+ struct symbol *sym;
+ struct menu *menu;
+ FILE *out;
+
+ out = fopen(filename, "w");
+ if (!out)
+ return 1;
+
+ sym_clear_all_valid();
+
+ /* Traverse all menus to find all relevant symbols */
+ menu = rootmenu.list;
+
+ while (menu != NULL)
+ {
+ sym = menu->sym;
+ if (sym == NULL) {
+ if (!menu_is_visible(menu))
+ goto next_menu;
+ } else if (!sym_is_choice(sym)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next_menu;
+ sym->flags &= ~SYMBOL_WRITE;
+ /* If we cannot change the symbol - skip */
+ if (!sym_is_changable(sym))
+ goto next_menu;
+ /* If symbol equals to default value - skip */
+ if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
+ goto next_menu;
+
+ /*
+ * If symbol is a choice value and equals to the
+ * default for a choice - skip.
+ * But only if value is bool and equal to "y" and
+ * choice is not "optional".
+ * (If choice is "optional" then all values can be "n")
+ */
+ if (sym_is_choice_value(sym)) {
+ struct symbol *cs;
+ struct symbol *ds;
+
+ cs = prop_get_symbol(sym_get_choice_prop(sym));
+ ds = sym_choice_default(cs);
+ if (!sym_is_optional(cs) && sym == ds) {
+ if ((sym->type == S_BOOLEAN) &&
+ sym_get_tristate_value(sym) == yes)
+ goto next_menu;
+ }
+ }
+ conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
+ }
+next_menu:
+ if (menu->list != NULL) {
+ menu = menu->list;
+ }
+ else if (menu->next != NULL) {
+ menu = menu->next;
+ } else {
+ while ((menu = menu->parent)) {
+ if (menu->next != NULL) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+ }
+ fclose(out);
+ return 0;
+}
+
+int conf_write(const char *name)
+{
+ FILE *out;
+ struct symbol *sym;
+ struct menu *menu;
+ const char *basename;
+ const char *str;
+ char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
+ char *env;
+
+ dirname[0] = 0;
+ if (name && name[0]) {
+ struct stat st;
+ char *slash;
+
+ if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
+ strcpy(dirname, name);
+ strcat(dirname, "/");
+ basename = conf_get_configname();
+ } else if ((slash = strrchr(name, '/'))) {
+ int size = slash - name + 1;
+ memcpy(dirname, name, size);
+ dirname[size] = 0;
+ if (slash[1])
+ basename = slash + 1;
+ else
+ basename = conf_get_configname();
+ } else
+ basename = name;
+ } else
+ basename = conf_get_configname();
+
+ sprintf(newname, "%s%s", dirname, basename);
+ env = getenv("KCONFIG_OVERWRITECONFIG");
+ if (!env || !*env) {
+ sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
+ out = fopen(tmpname, "w");
+ } else {
+ *tmpname = 0;
+ out = fopen(newname, "w");
+ }
+ if (!out)
+ return 1;
+
+ conf_write_heading(out, &kconfig_printer_cb, NULL);
+
+ if (!conf_get_changed())
+ sym_clear_all_valid();
+
+ menu = rootmenu.list;
+ while (menu) {
+ sym = menu->sym;
+ if (!sym) {
+ if (!menu_is_visible(menu))
+ goto next;
+ str = menu_get_prompt(menu);
+ fprintf(out, "\n"
+ "#\n"
+ "# %s\n"
+ "#\n", str);
+ } else if (!(sym->flags & SYMBOL_CHOICE)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next;
+ sym->flags &= ~SYMBOL_WRITE;
+
+ conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
+ }
+
+next:
+ if (menu->list) {
+ menu = menu->list;
+ continue;
+ }
+ if (menu->next)
+ menu = menu->next;
+ else while ((menu = menu->parent)) {
+ if (menu->next) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+ fclose(out);
+
+ if (*tmpname) {
+ strcat(dirname, basename);
+ strcat(dirname, ".old");
+ rename(newname, dirname);
+ if (rename(tmpname, newname))
+ return 1;
+ }
+
+ conf_message(_("configuration written to %s"), newname);
+
+ sym_set_change_count(0);
+
+ return 0;
+}
+
+static int conf_split_config(void)
+{
+ const char *name;
+ char path[PATH_MAX+1];
+ char *s, *d, c;
+ struct symbol *sym;
+ struct stat sb;
+ int res, i, fd;
+
+ name = conf_get_autoconfig_name();
+ conf_read_simple(name, S_DEF_AUTO);
+
+ if (chdir("include/config"))
+ return 1;
+
+ res = 0;
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if ((sym->flags & SYMBOL_AUTO) || !sym->name)
+ continue;
+ if (sym->flags & SYMBOL_WRITE) {
+ if (sym->flags & SYMBOL_DEF_AUTO) {
+ /*
+ * symbol has old and new value,
+ * so compare them...
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) ==
+ sym->def[S_DEF_AUTO].tri)
+ continue;
+ break;
+ case S_STRING:
+ case S_HEX:
+ case S_INT:
+ if (!strcmp(sym_get_string_value(sym),
+ sym->def[S_DEF_AUTO].val))
+ continue;
+ break;
+ default:
+ break;
+ }
+ } else {
+ /*
+ * If there is no old value, only 'no' (unset)
+ * is allowed as new value.
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) == no)
+ continue;
+ break;
+ default:
+ break;
+ }
+ }
+ } else if (!(sym->flags & SYMBOL_DEF_AUTO))
+ /* There is neither an old nor a new value. */
+ continue;
+ /* else
+ * There is an old value, but no new value ('no' (unset)
+ * isn't saved in auto.conf, so the old value is always
+ * different from 'no').
+ */
+
+ /* Replace all '_' and append ".h" */
+ s = sym->name;
+ d = path;
+ while ((c = *s++)) {
+ c = tolower(c);
+ *d++ = (c == '_') ? '/' : c;
+ }
+ strcpy(d, ".h");
+
+ /* Assume directory path already exists. */
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1) {
+ if (errno != ENOENT) {
+ res = 1;
+ break;
+ }
+ /*
+ * Create directory components,
+ * unless they exist already.
+ */
+ d = path;
+ while ((d = strchr(d, '/'))) {
+ *d = 0;
+ if (stat(path, &sb) && mkdir(path, 0755)) {
+ res = 1;
+ goto out;
+ }
+ *d++ = '/';
+ }
+ /* Try it again. */
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1) {
+ res = 1;
+ break;
+ }
+ }
+ close(fd);
+ }
+out:
+ if (chdir("../.."))
+ return 1;
+
+ return res;
+}
+
+int conf_write_autoconf(void)
+{
+ struct symbol *sym;
+ const char *name;
+ FILE *out, *tristate, *out_h;
+ int i;
+
+ sym_clear_all_valid();
+
+ file_write_dep("include/config/auto.conf.cmd");
+
+ if (conf_split_config())
+ return 1;
+
+ out = fopen(".tmpconfig", "w");
+ if (!out)
+ return 1;
+
+ tristate = fopen(".tmpconfig_tristate", "w");
+ if (!tristate) {
+ fclose(out);
+ return 1;
+ }
+
+ out_h = fopen(".tmpconfig.h", "w");
+ if (!out_h) {
+ fclose(out);
+ fclose(tristate);
+ return 1;
+ }
+
+ conf_write_heading(out, &kconfig_printer_cb, NULL);
+
+ conf_write_heading(tristate, &tristate_printer_cb, NULL);
+
+ conf_write_heading(out_h, &header_printer_cb, NULL);
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if (!sym->name)
+ continue;
+ if (!(sym->flags & SYMBOL_WRITE)) {
+ conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
+ continue;
+ }
+
+ /* write symbol to auto.conf, tristate and header files */
+ conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
+
+ conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1);
+
+ conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
+ }
+ fclose(out);
+ fclose(tristate);
+ fclose(out_h);
+
+ name = getenv("KCONFIG_AUTOHEADER");
+ if (!name)
+ name = "include/generated/autoconf.h";
+ if (rename(".tmpconfig.h", name))
+ return 1;
+ name = getenv("KCONFIG_TRISTATE");
+ if (!name)
+ name = "include/config/tristate.conf";
+ if (rename(".tmpconfig_tristate", name))
+ return 1;
+ name = conf_get_autoconfig_name();
+ /*
+ * This must be the last step, kbuild has a dependency on auto.conf
+ * and this marks the successful completion of the previous steps.
+ */
+ if (rename(".tmpconfig", name))
+ return 1;
+
+ return 0;
+}
+
+static int sym_change_count;
+static void (*conf_changed_callback)(void);
+
+void sym_set_change_count(int count)
+{
+ int _sym_change_count = sym_change_count;
+ sym_change_count = count;
+ if (conf_changed_callback &&
+ (bool)_sym_change_count != (bool)count)
+ conf_changed_callback();
+}
+
+void sym_add_change_count(int count)
+{
+ sym_set_change_count(count + sym_change_count);
+}
+
+bool conf_get_changed(void)
+{
+ return sym_change_count;
+}
+
+void conf_set_changed_callback(void (*fn)(void))
+{
+ conf_changed_callback = fn;
+}
+
+static bool randomize_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+ int cnt, def;
+
+ /*
+ * If choice is mod then we may have more items selected
+ * and if no then no-one.
+ * In both cases stop.
+ */
+ if (csym->curr.tri != yes)
+ return false;
+
+ prop = sym_get_choice_prop(csym);
+
+ /* count entries in choice block */
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym)
+ cnt++;
+
+ /*
+ * find a random value and set it to yes,
+ * set the rest to no so we have only one set
+ */
+ def = (rand() % cnt);
+
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (def == cnt++) {
+ sym->def[S_DEF_USER].tri = yes;
+ csym->def[S_DEF_USER].val = sym;
+ }
+ else {
+ sym->def[S_DEF_USER].tri = no;
+ }
+ sym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ sym->flags &= ~SYMBOL_VALID;
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~(SYMBOL_VALID);
+
+ return true;
+}
+
+void set_all_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+
+ prop = sym_get_choice_prop(csym);
+
+ /*
+ * Set all non-assinged choice values to no
+ */
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (!sym_has_value(sym))
+ sym->def[S_DEF_USER].tri = no;
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
+}
+
+bool conf_set_all_new_symbols(enum conf_def_mode mode)
+{
+ struct symbol *sym, *csym;
+ int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y
+ * pty: probability of tristate = y
+ * ptm: probability of tristate = m
+ */
+
+ pby = 50; pty = ptm = 33; /* can't go as the default in switch-case
+ * below, otherwise gcc whines about
+ * -Wmaybe-uninitialized */
+ if (mode == def_random) {
+ int n, p[3];
+ char *env = getenv("KCONFIG_PROBABILITY");
+ n = 0;
+ while( env && *env ) {
+ char *endp;
+ int tmp = strtol( env, &endp, 10 );
+ if( tmp >= 0 && tmp <= 100 ) {
+ p[n++] = tmp;
+ } else {
+ errno = ERANGE;
+ perror( "KCONFIG_PROBABILITY" );
+ exit( 1 );
+ }
+ env = (*endp == ':') ? endp+1 : endp;
+ if( n >=3 ) {
+ break;
+ }
+ }
+ switch( n ) {
+ case 1:
+ pby = p[0]; ptm = pby/2; pty = pby-ptm;
+ break;
+ case 2:
+ pty = p[0]; ptm = p[1]; pby = pty + ptm;
+ break;
+ case 3:
+ pby = p[0]; pty = p[1]; ptm = p[2];
+ break;
+ }
+
+ if( pty+ptm > 100 ) {
+ errno = ERANGE;
+ perror( "KCONFIG_PROBABILITY" );
+ exit( 1 );
+ }
+ }
+ bool has_changed = false;
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID))
+ continue;
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ has_changed = true;
+ switch (mode) {
+ case def_yes:
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ case def_mod:
+ sym->def[S_DEF_USER].tri = mod;
+ break;
+ case def_no:
+ if (sym->flags & SYMBOL_ALLNOCONFIG_Y)
+ sym->def[S_DEF_USER].tri = yes;
+ else
+ sym->def[S_DEF_USER].tri = no;
+ break;
+ case def_random:
+ sym->def[S_DEF_USER].tri = no;
+ cnt = rand() % 100;
+ if (sym->type == S_TRISTATE) {
+ if (cnt < pty)
+ sym->def[S_DEF_USER].tri = yes;
+ else if (cnt < (pty+ptm))
+ sym->def[S_DEF_USER].tri = mod;
+ } else if (cnt < pby)
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ default:
+ continue;
+ }
+ if (!(sym_is_choice(sym) && mode == def_random))
+ sym->flags |= SYMBOL_DEF_USER;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ sym_clear_all_valid();
+
+ /*
+ * We have different type of choice blocks.
+ * If curr.tri equals to mod then we can select several
+ * choice symbols in one block.
+ * In this case we do nothing.
+ * If curr.tri equals yes then only one symbol can be
+ * selected in a choice block and we set it to yes,
+ * and the rest to no.
+ */
+ if (mode != def_random) {
+ for_all_symbols(i, csym) {
+ if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
+ sym_is_choice_value(csym))
+ csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
+ }
+ }
+
+ for_all_symbols(i, csym) {
+ if (sym_has_value(csym) || !sym_is_choice(csym))
+ continue;
+
+ sym_calc_value(csym);
+ if (mode == def_random)
+ has_changed = randomize_choice_values(csym);
+ else {
+ set_all_choice_values(csym);
+ has_changed = true;
+ }
+ }
+
+ return has_changed;
+}
diff --git a/roms/seabios/scripts/kconfig/expr.c b/roms/seabios/scripts/kconfig/expr.c
new file mode 100644
index 00000000..d6626521
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/expr.c
@@ -0,0 +1,1168 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lkc.h"
+
+#define DEBUG_EXPR 0
+
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+ struct expr *e = xcalloc(1, sizeof(*e));
+ e->type = E_SYMBOL;
+ e->left.sym = sym;
+ return e;
+}
+
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
+{
+ struct expr *e = xcalloc(1, sizeof(*e));
+ e->type = type;
+ e->left.expr = ce;
+ return e;
+}
+
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
+{
+ struct expr *e = xcalloc(1, sizeof(*e));
+ e->type = type;
+ e->left.expr = e1;
+ e->right.expr = e2;
+ return e;
+}
+
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
+{
+ struct expr *e = xcalloc(1, sizeof(*e));
+ e->type = type;
+ e->left.sym = s1;
+ e->right.sym = s2;
+ return e;
+}
+
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
+{
+ if (!e1)
+ return e2;
+ return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
+}
+
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
+{
+ if (!e1)
+ return e2;
+ return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
+}
+
+struct expr *expr_copy(const struct expr *org)
+{
+ struct expr *e;
+
+ if (!org)
+ return NULL;
+
+ e = xmalloc(sizeof(*org));
+ memcpy(e, org, sizeof(*org));
+ switch (org->type) {
+ case E_SYMBOL:
+ e->left = org->left;
+ break;
+ case E_NOT:
+ e->left.expr = expr_copy(org->left.expr);
+ break;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ e->left.sym = org->left.sym;
+ e->right.sym = org->right.sym;
+ break;
+ case E_AND:
+ case E_OR:
+ case E_LIST:
+ e->left.expr = expr_copy(org->left.expr);
+ e->right.expr = expr_copy(org->right.expr);
+ break;
+ default:
+ printf("can't copy type %d\n", e->type);
+ free(e);
+ e = NULL;
+ break;
+ }
+
+ return e;
+}
+
+void expr_free(struct expr *e)
+{
+ if (!e)
+ return;
+
+ switch (e->type) {
+ case E_SYMBOL:
+ break;
+ case E_NOT:
+ expr_free(e->left.expr);
+ return;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ break;
+ case E_OR:
+ case E_AND:
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ break;
+ default:
+ printf("how to free type %d?\n", e->type);
+ break;
+ }
+ free(e);
+}
+
+static int trans_count;
+
+#define e1 (*ep1)
+#define e2 (*ep2)
+
+static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+ if (e1->type == type) {
+ __expr_eliminate_eq(type, &e1->left.expr, &e2);
+ __expr_eliminate_eq(type, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ __expr_eliminate_eq(type, &e1, &e2->left.expr);
+ __expr_eliminate_eq(type, &e1, &e2->right.expr);
+ return;
+ }
+ if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+ e1->left.sym == e2->left.sym &&
+ (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
+ return;
+ if (!expr_eq(e1, e2))
+ return;
+ trans_count++;
+ expr_free(e1); expr_free(e2);
+ switch (type) {
+ case E_OR:
+ e1 = expr_alloc_symbol(&symbol_no);
+ e2 = expr_alloc_symbol(&symbol_no);
+ break;
+ case E_AND:
+ e1 = expr_alloc_symbol(&symbol_yes);
+ e2 = expr_alloc_symbol(&symbol_yes);
+ break;
+ default:
+ ;
+ }
+}
+
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
+{
+ if (!e1 || !e2)
+ return;
+ switch (e1->type) {
+ case E_OR:
+ case E_AND:
+ __expr_eliminate_eq(e1->type, ep1, ep2);
+ default:
+ ;
+ }
+ if (e1->type != e2->type) switch (e2->type) {
+ case E_OR:
+ case E_AND:
+ __expr_eliminate_eq(e2->type, ep1, ep2);
+ default:
+ ;
+ }
+ e1 = expr_eliminate_yn(e1);
+ e2 = expr_eliminate_yn(e2);
+}
+
+#undef e1
+#undef e2
+
+int expr_eq(struct expr *e1, struct expr *e2)
+{
+ int res, old_count;
+
+ if (e1->type != e2->type)
+ return 0;
+ switch (e1->type) {
+ case E_EQUAL:
+ case E_UNEQUAL:
+ return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
+ case E_SYMBOL:
+ return e1->left.sym == e2->left.sym;
+ case E_NOT:
+ return expr_eq(e1->left.expr, e2->left.expr);
+ case E_AND:
+ case E_OR:
+ e1 = expr_copy(e1);
+ e2 = expr_copy(e2);
+ old_count = trans_count;
+ expr_eliminate_eq(&e1, &e2);
+ res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+ e1->left.sym == e2->left.sym);
+ expr_free(e1);
+ expr_free(e2);
+ trans_count = old_count;
+ return res;
+ case E_LIST:
+ case E_RANGE:
+ case E_NONE:
+ /* panic */;
+ }
+
+ if (DEBUG_EXPR) {
+ expr_fprint(e1, stdout);
+ printf(" = ");
+ expr_fprint(e2, stdout);
+ printf(" ?\n");
+ }
+
+ return 0;
+}
+
+struct expr *expr_eliminate_yn(struct expr *e)
+{
+ struct expr *tmp;
+
+ if (e) switch (e->type) {
+ case E_AND:
+ e->left.expr = expr_eliminate_yn(e->left.expr);
+ e->right.expr = expr_eliminate_yn(e->right.expr);
+ if (e->left.expr->type == E_SYMBOL) {
+ if (e->left.expr->left.sym == &symbol_no) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ e->right.expr = NULL;
+ return e;
+ } else if (e->left.expr->left.sym == &symbol_yes) {
+ free(e->left.expr);
+ tmp = e->right.expr;
+ *e = *(e->right.expr);
+ free(tmp);
+ return e;
+ }
+ }
+ if (e->right.expr->type == E_SYMBOL) {
+ if (e->right.expr->left.sym == &symbol_no) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ e->right.expr = NULL;
+ return e;
+ } else if (e->right.expr->left.sym == &symbol_yes) {
+ free(e->right.expr);
+ tmp = e->left.expr;
+ *e = *(e->left.expr);
+ free(tmp);
+ return e;
+ }
+ }
+ break;
+ case E_OR:
+ e->left.expr = expr_eliminate_yn(e->left.expr);
+ e->right.expr = expr_eliminate_yn(e->right.expr);
+ if (e->left.expr->type == E_SYMBOL) {
+ if (e->left.expr->left.sym == &symbol_no) {
+ free(e->left.expr);
+ tmp = e->right.expr;
+ *e = *(e->right.expr);
+ free(tmp);
+ return e;
+ } else if (e->left.expr->left.sym == &symbol_yes) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ e->right.expr = NULL;
+ return e;
+ }
+ }
+ if (e->right.expr->type == E_SYMBOL) {
+ if (e->right.expr->left.sym == &symbol_no) {
+ free(e->right.expr);
+ tmp = e->left.expr;
+ *e = *(e->left.expr);
+ free(tmp);
+ return e;
+ } else if (e->right.expr->left.sym == &symbol_yes) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ e->right.expr = NULL;
+ return e;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ return e;
+}
+
+/*
+ * bool FOO!=n => FOO
+ */
+struct expr *expr_trans_bool(struct expr *e)
+{
+ if (!e)
+ return NULL;
+ switch (e->type) {
+ case E_AND:
+ case E_OR:
+ case E_NOT:
+ e->left.expr = expr_trans_bool(e->left.expr);
+ e->right.expr = expr_trans_bool(e->right.expr);
+ break;
+ case E_UNEQUAL:
+ // FOO!=n -> FOO
+ if (e->left.sym->type == S_TRISTATE) {
+ if (e->right.sym == &symbol_no) {
+ e->type = E_SYMBOL;
+ e->right.sym = NULL;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ return e;
+}
+
+/*
+ * e1 || e2 -> ?
+ */
+static struct expr *expr_join_or(struct expr *e1, struct expr *e2)
+{
+ struct expr *tmp;
+ struct symbol *sym1, *sym2;
+
+ if (expr_eq(e1, e2))
+ return expr_copy(e1);
+ if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+ return NULL;
+ if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+ return NULL;
+ if (e1->type == E_NOT) {
+ tmp = e1->left.expr;
+ if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+ return NULL;
+ sym1 = tmp->left.sym;
+ } else
+ sym1 = e1->left.sym;
+ if (e2->type == E_NOT) {
+ if (e2->left.expr->type != E_SYMBOL)
+ return NULL;
+ sym2 = e2->left.expr->left.sym;
+ } else
+ sym2 = e2->left.sym;
+ if (sym1 != sym2)
+ return NULL;
+ if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+ return NULL;
+ if (sym1->type == S_TRISTATE) {
+ if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+ (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
+ // (a='y') || (a='m') -> (a!='n')
+ return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
+ }
+ if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
+ // (a='y') || (a='n') -> (a!='m')
+ return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
+ }
+ if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+ ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
+ // (a='m') || (a='n') -> (a!='y')
+ return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
+ }
+ }
+ if (sym1->type == S_BOOLEAN && sym1 == sym2) {
+ if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
+ (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
+ return expr_alloc_symbol(&symbol_yes);
+ }
+
+ if (DEBUG_EXPR) {
+ printf("optimize (");
+ expr_fprint(e1, stdout);
+ printf(") || (");
+ expr_fprint(e2, stdout);
+ printf(")?\n");
+ }
+ return NULL;
+}
+
+static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
+{
+ struct expr *tmp;
+ struct symbol *sym1, *sym2;
+
+ if (expr_eq(e1, e2))
+ return expr_copy(e1);
+ if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+ return NULL;
+ if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+ return NULL;
+ if (e1->type == E_NOT) {
+ tmp = e1->left.expr;
+ if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+ return NULL;
+ sym1 = tmp->left.sym;
+ } else
+ sym1 = e1->left.sym;
+ if (e2->type == E_NOT) {
+ if (e2->left.expr->type != E_SYMBOL)
+ return NULL;
+ sym2 = e2->left.expr->left.sym;
+ } else
+ sym2 = e2->left.sym;
+ if (sym1 != sym2)
+ return NULL;
+ if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+ return NULL;
+
+ if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
+ (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
+ // (a) && (a='y') -> (a='y')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+ if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
+ (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
+ // (a) && (a!='n') -> (a)
+ return expr_alloc_symbol(sym1);
+
+ if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
+ (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
+ // (a) && (a!='m') -> (a='y')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+ if (sym1->type == S_TRISTATE) {
+ if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
+ // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+ sym2 = e1->right.sym;
+ if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+ return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+ : expr_alloc_symbol(&symbol_no);
+ }
+ if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
+ // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+ sym2 = e2->right.sym;
+ if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+ return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+ : expr_alloc_symbol(&symbol_no);
+ }
+ if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
+ // (a!='y') && (a!='n') -> (a='m')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
+
+ if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+ (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
+ // (a!='y') && (a!='m') -> (a='n')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
+
+ if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+ ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
+ // (a!='m') && (a!='n') -> (a='m')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+ if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
+ (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
+ (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
+ (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
+ return NULL;
+ }
+
+ if (DEBUG_EXPR) {
+ printf("optimize (");
+ expr_fprint(e1, stdout);
+ printf(") && (");
+ expr_fprint(e2, stdout);
+ printf(")?\n");
+ }
+ return NULL;
+}
+
+static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+ struct expr *tmp;
+
+ if (e1->type == type) {
+ expr_eliminate_dups1(type, &e1->left.expr, &e2);
+ expr_eliminate_dups1(type, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ expr_eliminate_dups1(type, &e1, &e2->left.expr);
+ expr_eliminate_dups1(type, &e1, &e2->right.expr);
+ return;
+ }
+ if (e1 == e2)
+ return;
+
+ switch (e1->type) {
+ case E_OR: case E_AND:
+ expr_eliminate_dups1(e1->type, &e1, &e1);
+ default:
+ ;
+ }
+
+ switch (type) {
+ case E_OR:
+ tmp = expr_join_or(e1, e2);
+ if (tmp) {
+ expr_free(e1); expr_free(e2);
+ e1 = expr_alloc_symbol(&symbol_no);
+ e2 = tmp;
+ trans_count++;
+ }
+ break;
+ case E_AND:
+ tmp = expr_join_and(e1, e2);
+ if (tmp) {
+ expr_free(e1); expr_free(e2);
+ e1 = expr_alloc_symbol(&symbol_yes);
+ e2 = tmp;
+ trans_count++;
+ }
+ break;
+ default:
+ ;
+ }
+#undef e1
+#undef e2
+}
+
+static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+ struct expr *tmp, *tmp1, *tmp2;
+
+ if (e1->type == type) {
+ expr_eliminate_dups2(type, &e1->left.expr, &e2);
+ expr_eliminate_dups2(type, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ expr_eliminate_dups2(type, &e1, &e2->left.expr);
+ expr_eliminate_dups2(type, &e1, &e2->right.expr);
+ }
+ if (e1 == e2)
+ return;
+
+ switch (e1->type) {
+ case E_OR:
+ expr_eliminate_dups2(e1->type, &e1, &e1);
+ // (FOO || BAR) && (!FOO && !BAR) -> n
+ tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+ tmp2 = expr_copy(e2);
+ tmp = expr_extract_eq_and(&tmp1, &tmp2);
+ if (expr_is_yes(tmp1)) {
+ expr_free(e1);
+ e1 = expr_alloc_symbol(&symbol_no);
+ trans_count++;
+ }
+ expr_free(tmp2);
+ expr_free(tmp1);
+ expr_free(tmp);
+ break;
+ case E_AND:
+ expr_eliminate_dups2(e1->type, &e1, &e1);
+ // (FOO && BAR) || (!FOO || !BAR) -> y
+ tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+ tmp2 = expr_copy(e2);
+ tmp = expr_extract_eq_or(&tmp1, &tmp2);
+ if (expr_is_no(tmp1)) {
+ expr_free(e1);
+ e1 = expr_alloc_symbol(&symbol_yes);
+ trans_count++;
+ }
+ expr_free(tmp2);
+ expr_free(tmp1);
+ expr_free(tmp);
+ break;
+ default:
+ ;
+ }
+#undef e1
+#undef e2
+}
+
+struct expr *expr_eliminate_dups(struct expr *e)
+{
+ int oldcount;
+ if (!e)
+ return e;
+
+ oldcount = trans_count;
+ while (1) {
+ trans_count = 0;
+ switch (e->type) {
+ case E_OR: case E_AND:
+ expr_eliminate_dups1(e->type, &e, &e);
+ expr_eliminate_dups2(e->type, &e, &e);
+ default:
+ ;
+ }
+ if (!trans_count)
+ break;
+ e = expr_eliminate_yn(e);
+ }
+ trans_count = oldcount;
+ return e;
+}
+
+struct expr *expr_transform(struct expr *e)
+{
+ struct expr *tmp;
+
+ if (!e)
+ return NULL;
+ switch (e->type) {
+ case E_EQUAL:
+ case E_UNEQUAL:
+ case E_SYMBOL:
+ case E_LIST:
+ break;
+ default:
+ e->left.expr = expr_transform(e->left.expr);
+ e->right.expr = expr_transform(e->right.expr);
+ }
+
+ switch (e->type) {
+ case E_EQUAL:
+ if (e->left.sym->type != S_BOOLEAN)
+ break;
+ if (e->right.sym == &symbol_no) {
+ e->type = E_NOT;
+ e->left.expr = expr_alloc_symbol(e->left.sym);
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_mod) {
+ printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_yes) {
+ e->type = E_SYMBOL;
+ e->right.sym = NULL;
+ break;
+ }
+ break;
+ case E_UNEQUAL:
+ if (e->left.sym->type != S_BOOLEAN)
+ break;
+ if (e->right.sym == &symbol_no) {
+ e->type = E_SYMBOL;
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_mod) {
+ printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_yes) {
+ e->type = E_NOT;
+ e->left.expr = expr_alloc_symbol(e->left.sym);
+ e->right.sym = NULL;
+ break;
+ }
+ break;
+ case E_NOT:
+ switch (e->left.expr->type) {
+ case E_NOT:
+ // !!a -> a
+ tmp = e->left.expr->left.expr;
+ free(e->left.expr);
+ free(e);
+ e = tmp;
+ e = expr_transform(e);
+ break;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ // !a='x' -> a!='x'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
+ break;
+ case E_OR:
+ // !(a || b) -> !a && !b
+ tmp = e->left.expr;
+ e->type = E_AND;
+ e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+ tmp->type = E_NOT;
+ tmp->right.expr = NULL;
+ e = expr_transform(e);
+ break;
+ case E_AND:
+ // !(a && b) -> !a || !b
+ tmp = e->left.expr;
+ e->type = E_OR;
+ e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+ tmp->type = E_NOT;
+ tmp->right.expr = NULL;
+ e = expr_transform(e);
+ break;
+ case E_SYMBOL:
+ if (e->left.expr->left.sym == &symbol_yes) {
+ // !'y' -> 'n'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ break;
+ }
+ if (e->left.expr->left.sym == &symbol_mod) {
+ // !'m' -> 'm'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_mod;
+ break;
+ }
+ if (e->left.expr->left.sym == &symbol_no) {
+ // !'n' -> 'y'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ break;
+ }
+ break;
+ default:
+ ;
+ }
+ break;
+ default:
+ ;
+ }
+ return e;
+}
+
+int expr_contains_symbol(struct expr *dep, struct symbol *sym)
+{
+ if (!dep)
+ return 0;
+
+ switch (dep->type) {
+ case E_AND:
+ case E_OR:
+ return expr_contains_symbol(dep->left.expr, sym) ||
+ expr_contains_symbol(dep->right.expr, sym);
+ case E_SYMBOL:
+ return dep->left.sym == sym;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ return dep->left.sym == sym ||
+ dep->right.sym == sym;
+ case E_NOT:
+ return expr_contains_symbol(dep->left.expr, sym);
+ default:
+ ;
+ }
+ return 0;
+}
+
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
+{
+ if (!dep)
+ return false;
+
+ switch (dep->type) {
+ case E_AND:
+ return expr_depends_symbol(dep->left.expr, sym) ||
+ expr_depends_symbol(dep->right.expr, sym);
+ case E_SYMBOL:
+ return dep->left.sym == sym;
+ case E_EQUAL:
+ if (dep->left.sym == sym) {
+ if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
+ return true;
+ }
+ break;
+ case E_UNEQUAL:
+ if (dep->left.sym == sym) {
+ if (dep->right.sym == &symbol_no)
+ return true;
+ }
+ break;
+ default:
+ ;
+ }
+ return false;
+}
+
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
+{
+ struct expr *tmp = NULL;
+ expr_extract_eq(E_AND, &tmp, ep1, ep2);
+ if (tmp) {
+ *ep1 = expr_eliminate_yn(*ep1);
+ *ep2 = expr_eliminate_yn(*ep2);
+ }
+ return tmp;
+}
+
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2)
+{
+ struct expr *tmp = NULL;
+ expr_extract_eq(E_OR, &tmp, ep1, ep2);
+ if (tmp) {
+ *ep1 = expr_eliminate_yn(*ep1);
+ *ep2 = expr_eliminate_yn(*ep2);
+ }
+ return tmp;
+}
+
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+ if (e1->type == type) {
+ expr_extract_eq(type, ep, &e1->left.expr, &e2);
+ expr_extract_eq(type, ep, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ expr_extract_eq(type, ep, ep1, &e2->left.expr);
+ expr_extract_eq(type, ep, ep1, &e2->right.expr);
+ return;
+ }
+ if (expr_eq(e1, e2)) {
+ *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1;
+ expr_free(e2);
+ if (type == E_AND) {
+ e1 = expr_alloc_symbol(&symbol_yes);
+ e2 = expr_alloc_symbol(&symbol_yes);
+ } else if (type == E_OR) {
+ e1 = expr_alloc_symbol(&symbol_no);
+ e2 = expr_alloc_symbol(&symbol_no);
+ }
+ }
+#undef e1
+#undef e2
+}
+
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
+{
+ struct expr *e1, *e2;
+
+ if (!e) {
+ e = expr_alloc_symbol(sym);
+ if (type == E_UNEQUAL)
+ e = expr_alloc_one(E_NOT, e);
+ return e;
+ }
+ switch (e->type) {
+ case E_AND:
+ e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+ e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+ if (sym == &symbol_yes)
+ e = expr_alloc_two(E_AND, e1, e2);
+ if (sym == &symbol_no)
+ e = expr_alloc_two(E_OR, e1, e2);
+ if (type == E_UNEQUAL)
+ e = expr_alloc_one(E_NOT, e);
+ return e;
+ case E_OR:
+ e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+ e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+ if (sym == &symbol_yes)
+ e = expr_alloc_two(E_OR, e1, e2);
+ if (sym == &symbol_no)
+ e = expr_alloc_two(E_AND, e1, e2);
+ if (type == E_UNEQUAL)
+ e = expr_alloc_one(E_NOT, e);
+ return e;
+ case E_NOT:
+ return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
+ case E_UNEQUAL:
+ case E_EQUAL:
+ if (type == E_EQUAL) {
+ if (sym == &symbol_yes)
+ return expr_copy(e);
+ if (sym == &symbol_mod)
+ return expr_alloc_symbol(&symbol_no);
+ if (sym == &symbol_no)
+ return expr_alloc_one(E_NOT, expr_copy(e));
+ } else {
+ if (sym == &symbol_yes)
+ return expr_alloc_one(E_NOT, expr_copy(e));
+ if (sym == &symbol_mod)
+ return expr_alloc_symbol(&symbol_yes);
+ if (sym == &symbol_no)
+ return expr_copy(e);
+ }
+ break;
+ case E_SYMBOL:
+ return expr_alloc_comp(type, e->left.sym, sym);
+ case E_LIST:
+ case E_RANGE:
+ case E_NONE:
+ /* panic */;
+ }
+ return NULL;
+}
+
+tristate expr_calc_value(struct expr *e)
+{
+ tristate val1, val2;
+ const char *str1, *str2;
+
+ if (!e)
+ return yes;
+
+ switch (e->type) {
+ case E_SYMBOL:
+ sym_calc_value(e->left.sym);
+ return e->left.sym->curr.tri;
+ case E_AND:
+ val1 = expr_calc_value(e->left.expr);
+ val2 = expr_calc_value(e->right.expr);
+ return EXPR_AND(val1, val2);
+ case E_OR:
+ val1 = expr_calc_value(e->left.expr);
+ val2 = expr_calc_value(e->right.expr);
+ return EXPR_OR(val1, val2);
+ case E_NOT:
+ val1 = expr_calc_value(e->left.expr);
+ return EXPR_NOT(val1);
+ case E_EQUAL:
+ sym_calc_value(e->left.sym);
+ sym_calc_value(e->right.sym);
+ str1 = sym_get_string_value(e->left.sym);
+ str2 = sym_get_string_value(e->right.sym);
+ return !strcmp(str1, str2) ? yes : no;
+ case E_UNEQUAL:
+ sym_calc_value(e->left.sym);
+ sym_calc_value(e->right.sym);
+ str1 = sym_get_string_value(e->left.sym);
+ str2 = sym_get_string_value(e->right.sym);
+ return !strcmp(str1, str2) ? no : yes;
+ default:
+ printf("expr_calc_value: %d?\n", e->type);
+ return no;
+ }
+}
+
+int expr_compare_type(enum expr_type t1, enum expr_type t2)
+{
+#if 0
+ return 1;
+#else
+ if (t1 == t2)
+ return 0;
+ switch (t1) {
+ case E_EQUAL:
+ case E_UNEQUAL:
+ if (t2 == E_NOT)
+ return 1;
+ case E_NOT:
+ if (t2 == E_AND)
+ return 1;
+ case E_AND:
+ if (t2 == E_OR)
+ return 1;
+ case E_OR:
+ if (t2 == E_LIST)
+ return 1;
+ case E_LIST:
+ if (t2 == 0)
+ return 1;
+ default:
+ return -1;
+ }
+ printf("[%dgt%d?]", t1, t2);
+ return 0;
+#endif
+}
+
+static inline struct expr *
+expr_get_leftmost_symbol(const struct expr *e)
+{
+
+ if (e == NULL)
+ return NULL;
+
+ while (e->type != E_SYMBOL)
+ e = e->left.expr;
+
+ return expr_copy(e);
+}
+
+/*
+ * Given expression `e1' and `e2', returns the leaf of the longest
+ * sub-expression of `e1' not containing 'e2.
+ */
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
+{
+ struct expr *ret;
+
+ switch (e1->type) {
+ case E_OR:
+ return expr_alloc_and(
+ expr_simplify_unmet_dep(e1->left.expr, e2),
+ expr_simplify_unmet_dep(e1->right.expr, e2));
+ case E_AND: {
+ struct expr *e;
+ e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
+ e = expr_eliminate_dups(e);
+ ret = (!expr_eq(e, e1)) ? e1 : NULL;
+ expr_free(e);
+ break;
+ }
+ default:
+ ret = e1;
+ break;
+ }
+
+ return expr_get_leftmost_symbol(ret);
+}
+
+void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
+{
+ if (!e) {
+ fn(data, NULL, "y");
+ return;
+ }
+
+ if (expr_compare_type(prevtoken, e->type) > 0)
+ fn(data, NULL, "(");
+ switch (e->type) {
+ case E_SYMBOL:
+ if (e->left.sym->name)
+ fn(data, e->left.sym, e->left.sym->name);
+ else
+ fn(data, NULL, "<choice>");
+ break;
+ case E_NOT:
+ fn(data, NULL, "!");
+ expr_print(e->left.expr, fn, data, E_NOT);
+ break;
+ case E_EQUAL:
+ if (e->left.sym->name)
+ fn(data, e->left.sym, e->left.sym->name);
+ else
+ fn(data, NULL, "<choice>");
+ fn(data, NULL, "=");
+ fn(data, e->right.sym, e->right.sym->name);
+ break;
+ case E_UNEQUAL:
+ if (e->left.sym->name)
+ fn(data, e->left.sym, e->left.sym->name);
+ else
+ fn(data, NULL, "<choice>");
+ fn(data, NULL, "!=");
+ fn(data, e->right.sym, e->right.sym->name);
+ break;
+ case E_OR:
+ expr_print(e->left.expr, fn, data, E_OR);
+ fn(data, NULL, " || ");
+ expr_print(e->right.expr, fn, data, E_OR);
+ break;
+ case E_AND:
+ expr_print(e->left.expr, fn, data, E_AND);
+ fn(data, NULL, " && ");
+ expr_print(e->right.expr, fn, data, E_AND);
+ break;
+ case E_LIST:
+ fn(data, e->right.sym, e->right.sym->name);
+ if (e->left.expr) {
+ fn(data, NULL, " ^ ");
+ expr_print(e->left.expr, fn, data, E_LIST);
+ }
+ break;
+ case E_RANGE:
+ fn(data, NULL, "[");
+ fn(data, e->left.sym, e->left.sym->name);
+ fn(data, NULL, " ");
+ fn(data, e->right.sym, e->right.sym->name);
+ fn(data, NULL, "]");
+ break;
+ default:
+ {
+ char buf[32];
+ sprintf(buf, "<unknown type %d>", e->type);
+ fn(data, NULL, buf);
+ break;
+ }
+ }
+ if (expr_compare_type(prevtoken, e->type) > 0)
+ fn(data, NULL, ")");
+}
+
+static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
+{
+ xfwrite(str, strlen(str), 1, data);
+}
+
+void expr_fprint(struct expr *e, FILE *out)
+{
+ expr_print(e, expr_print_file_helper, out, E_NONE);
+}
+
+static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
+{
+ struct gstr *gs = (struct gstr*)data;
+ const char *sym_str = NULL;
+
+ if (sym)
+ sym_str = sym_get_string_value(sym);
+
+ if (gs->max_width) {
+ unsigned extra_length = strlen(str);
+ const char *last_cr = strrchr(gs->s, '\n');
+ unsigned last_line_length;
+
+ if (sym_str)
+ extra_length += 4 + strlen(sym_str);
+
+ if (!last_cr)
+ last_cr = gs->s;
+
+ last_line_length = strlen(gs->s) - (last_cr - gs->s);
+
+ if ((last_line_length + extra_length) > gs->max_width)
+ str_append(gs, "\\\n");
+ }
+
+ str_append(gs, str);
+ if (sym && sym->type != S_UNKNOWN)
+ str_printf(gs, " [=%s]", sym_str);
+}
+
+void expr_gstr_print(struct expr *e, struct gstr *gs)
+{
+ expr_print(e, expr_print_gstr_helper, gs, E_NONE);
+}
diff --git a/roms/seabios/scripts/kconfig/expr.h b/roms/seabios/scripts/kconfig/expr.h
new file mode 100644
index 00000000..412ea8a2
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/expr.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef EXPR_H
+#define EXPR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include "list.h"
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+struct file {
+ struct file *next;
+ struct file *parent;
+ const char *name;
+ int lineno;
+};
+
+typedef enum tristate {
+ no, mod, yes
+} tristate;
+
+enum expr_type {
+ E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE
+};
+
+union expr_data {
+ struct expr *expr;
+ struct symbol *sym;
+};
+
+struct expr {
+ enum expr_type type;
+ union expr_data left, right;
+};
+
+#define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2))
+#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2))
+#define EXPR_NOT(dep) (2-(dep))
+
+#define expr_list_for_each_sym(l, e, s) \
+ for (e = (l); e && (s = e->right.sym); e = e->left.expr)
+
+struct expr_value {
+ struct expr *expr;
+ tristate tri;
+};
+
+struct symbol_value {
+ void *val;
+ tristate tri;
+};
+
+enum symbol_type {
+ S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
+};
+
+/* enum values are used as index to symbol.def[] */
+enum {
+ S_DEF_USER, /* main user value */
+ S_DEF_AUTO, /* values read from auto.conf */
+ S_DEF_DEF3, /* Reserved for UI usage */
+ S_DEF_DEF4, /* Reserved for UI usage */
+ S_DEF_COUNT
+};
+
+struct symbol {
+ struct symbol *next;
+ char *name;
+ enum symbol_type type;
+ struct symbol_value curr;
+ struct symbol_value def[S_DEF_COUNT];
+ tristate visible;
+ int flags;
+ struct property *prop;
+ struct expr_value dir_dep;
+ struct expr_value rev_dep;
+};
+
+#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
+
+#define SYMBOL_CONST 0x0001 /* symbol is const */
+#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
+#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */
+#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */
+#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */
+#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */
+#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */
+#define SYMBOL_CHANGED 0x0400 /* ? */
+#define SYMBOL_AUTO 0x1000 /* value from environment variable */
+#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */
+#define SYMBOL_WARNED 0x8000 /* warning has been issued */
+
+/* Set when symbol.def[] is used */
+#define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */
+#define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */
+#define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */
+#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */
+#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */
+
+/* choice values need to be set before calculating this symbol value */
+#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000
+
+/* Set symbol to y if allnoconfig; used for symbols that hide others */
+#define SYMBOL_ALLNOCONFIG_Y 0x200000
+
+#define SYMBOL_MAXLENGTH 256
+#define SYMBOL_HASHSIZE 9973
+
+/* A property represent the config options that can be associated
+ * with a config "symbol".
+ * Sample:
+ * config FOO
+ * default y
+ * prompt "foo prompt"
+ * select BAR
+ * config BAZ
+ * int "BAZ Value"
+ * range 1..255
+ */
+enum prop_type {
+ P_UNKNOWN,
+ P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */
+ P_COMMENT, /* text associated with a comment */
+ P_MENU, /* prompt associated with a menuconfig option */
+ P_DEFAULT, /* default y */
+ P_CHOICE, /* choice value */
+ P_SELECT, /* select BAR */
+ P_RANGE, /* range 7..100 (for a symbol) */
+ P_ENV, /* value from environment variable */
+ P_SYMBOL, /* where a symbol is defined */
+};
+
+struct property {
+ struct property *next; /* next property - null if last */
+ struct symbol *sym; /* the symbol for which the property is associated */
+ enum prop_type type; /* type of property */
+ const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */
+ struct expr_value visible;
+ struct expr *expr; /* the optional conditional part of the property */
+ struct menu *menu; /* the menu the property are associated with
+ * valid for: P_SELECT, P_RANGE, P_CHOICE,
+ * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
+ struct file *file; /* what file was this property defined */
+ int lineno; /* what lineno was this property defined */
+};
+
+#define for_all_properties(sym, st, tok) \
+ for (st = sym->prop; st; st = st->next) \
+ if (st->type == (tok))
+#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
+#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
+#define for_all_prompts(sym, st) \
+ for (st = sym->prop; st; st = st->next) \
+ if (st->text)
+
+struct menu {
+ struct menu *next;
+ struct menu *parent;
+ struct menu *list;
+ struct symbol *sym;
+ struct property *prompt;
+ struct expr *visibility;
+ struct expr *dep;
+ unsigned int flags;
+ char *help;
+ struct file *file;
+ int lineno;
+ void *data;
+};
+
+#define MENU_CHANGED 0x0001
+#define MENU_ROOT 0x0002
+
+struct jump_key {
+ struct list_head entries;
+ size_t offset;
+ struct menu *target;
+ int index;
+};
+
+#define JUMP_NB 9
+
+extern struct file *file_list;
+extern struct file *current_file;
+struct file *lookup_file(const char *name);
+
+extern struct symbol symbol_yes, symbol_no, symbol_mod;
+extern struct symbol *modules_sym;
+extern struct symbol *sym_defconfig_list;
+extern int cdebug;
+struct expr *expr_alloc_symbol(struct symbol *sym);
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
+struct expr *expr_copy(const struct expr *org);
+void expr_free(struct expr *e);
+int expr_eq(struct expr *e1, struct expr *e2);
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
+tristate expr_calc_value(struct expr *e);
+struct expr *expr_eliminate_yn(struct expr *e);
+struct expr *expr_trans_bool(struct expr *e);
+struct expr *expr_eliminate_dups(struct expr *e);
+struct expr *expr_transform(struct expr *e);
+int expr_contains_symbol(struct expr *dep, struct symbol *sym);
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
+
+void expr_fprint(struct expr *e, FILE *out);
+struct gstr; /* forward */
+void expr_gstr_print(struct expr *e, struct gstr *gs);
+
+static inline int expr_is_yes(struct expr *e)
+{
+ return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
+}
+
+static inline int expr_is_no(struct expr *e)
+{
+ return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXPR_H */
diff --git a/roms/seabios/scripts/kconfig/gconf.c b/roms/seabios/scripts/kconfig/gconf.c
new file mode 100644
index 00000000..d0a35b21
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/gconf.c
@@ -0,0 +1,1542 @@
+/* Hey EMACS -*- linux-c -*- */
+/*
+ *
+ * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include "lkc.h"
+#include "images.c"
+
+#include <glade/glade.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+//#define DEBUG
+
+enum {
+ SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
+};
+
+enum {
+ OPT_NORMAL, OPT_ALL, OPT_PROMPT
+};
+
+static gint view_mode = FULL_VIEW;
+static gboolean show_name = TRUE;
+static gboolean show_range = TRUE;
+static gboolean show_value = TRUE;
+static gboolean resizeable = FALSE;
+static int opt_mode = OPT_NORMAL;
+
+GtkWidget *main_wnd = NULL;
+GtkWidget *tree1_w = NULL; // left frame
+GtkWidget *tree2_w = NULL; // right frame
+GtkWidget *text_w = NULL;
+GtkWidget *hpaned = NULL;
+GtkWidget *vpaned = NULL;
+GtkWidget *back_btn = NULL;
+GtkWidget *save_btn = NULL;
+GtkWidget *save_menu_item = NULL;
+
+GtkTextTag *tag1, *tag2;
+GdkColor color;
+
+GtkTreeStore *tree1, *tree2, *tree;
+GtkTreeModel *model1, *model2;
+static GtkTreeIter *parents[256];
+static gint indent;
+
+static struct menu *current; // current node for SINGLE view
+static struct menu *browsed; // browsed node for SPLIT view
+
+enum {
+ COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
+ COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
+ COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
+ COL_NUMBER
+};
+
+static void display_list(void);
+static void display_tree(struct menu *menu);
+static void display_tree_part(void);
+static void update_tree(struct menu *src, GtkTreeIter * dst);
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
+static gchar **fill_row(struct menu *menu);
+static void conf_changed(void);
+
+/* Helping/Debugging Functions */
+
+const char *dbg_sym_flags(int val)
+{
+ static char buf[256];
+
+ bzero(buf, 256);
+
+ if (val & SYMBOL_CONST)
+ strcat(buf, "const/");
+ if (val & SYMBOL_CHECK)
+ strcat(buf, "check/");
+ if (val & SYMBOL_CHOICE)
+ strcat(buf, "choice/");
+ if (val & SYMBOL_CHOICEVAL)
+ strcat(buf, "choiceval/");
+ if (val & SYMBOL_VALID)
+ strcat(buf, "valid/");
+ if (val & SYMBOL_OPTIONAL)
+ strcat(buf, "optional/");
+ if (val & SYMBOL_WRITE)
+ strcat(buf, "write/");
+ if (val & SYMBOL_CHANGED)
+ strcat(buf, "changed/");
+ if (val & SYMBOL_AUTO)
+ strcat(buf, "auto/");
+
+ buf[strlen(buf) - 1] = '\0';
+
+ return buf;
+}
+
+void replace_button_icon(GladeXML * xml, GdkDrawable * window,
+ GtkStyle * style, gchar * btn_name, gchar ** xpm)
+{
+ GdkPixmap *pixmap;
+ GdkBitmap *mask;
+ GtkToolButton *button;
+ GtkWidget *image;
+
+ pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
+ &style->bg[GTK_STATE_NORMAL],
+ xpm);
+
+ button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
+ image = gtk_image_new_from_pixmap(pixmap, mask);
+ gtk_widget_show(image);
+ gtk_tool_button_set_icon_widget(button, image);
+}
+
+/* Main Window Initialization */
+void init_main_window(const gchar * glade_file)
+{
+ GladeXML *xml;
+ GtkWidget *widget;
+ GtkTextBuffer *txtbuf;
+ GtkStyle *style;
+
+ xml = glade_xml_new(glade_file, "window1", NULL);
+ if (!xml)
+ g_error(_("GUI loading failed !\n"));
+ glade_xml_signal_autoconnect(xml);
+
+ main_wnd = glade_xml_get_widget(xml, "window1");
+ hpaned = glade_xml_get_widget(xml, "hpaned1");
+ vpaned = glade_xml_get_widget(xml, "vpaned1");
+ tree1_w = glade_xml_get_widget(xml, "treeview1");
+ tree2_w = glade_xml_get_widget(xml, "treeview2");
+ text_w = glade_xml_get_widget(xml, "textview3");
+
+ back_btn = glade_xml_get_widget(xml, "button1");
+ gtk_widget_set_sensitive(back_btn, FALSE);
+
+ widget = glade_xml_get_widget(xml, "show_name1");
+ gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+ show_name);
+
+ widget = glade_xml_get_widget(xml, "show_range1");
+ gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+ show_range);
+
+ widget = glade_xml_get_widget(xml, "show_data1");
+ gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+ show_value);
+
+ save_btn = glade_xml_get_widget(xml, "button3");
+ save_menu_item = glade_xml_get_widget(xml, "save1");
+ conf_set_changed_callback(conf_changed);
+
+ style = gtk_widget_get_style(main_wnd);
+ widget = glade_xml_get_widget(xml, "toolbar1");
+
+#if 0 /* Use stock Gtk icons instead */
+ replace_button_icon(xml, main_wnd->window, style,
+ "button1", (gchar **) xpm_back);
+ replace_button_icon(xml, main_wnd->window, style,
+ "button2", (gchar **) xpm_load);
+ replace_button_icon(xml, main_wnd->window, style,
+ "button3", (gchar **) xpm_save);
+#endif
+ replace_button_icon(xml, main_wnd->window, style,
+ "button4", (gchar **) xpm_single_view);
+ replace_button_icon(xml, main_wnd->window, style,
+ "button5", (gchar **) xpm_split_view);
+ replace_button_icon(xml, main_wnd->window, style,
+ "button6", (gchar **) xpm_tree_view);
+
+#if 0
+ switch (view_mode) {
+ case SINGLE_VIEW:
+ widget = glade_xml_get_widget(xml, "button4");
+ g_signal_emit_by_name(widget, "clicked");
+ break;
+ case SPLIT_VIEW:
+ widget = glade_xml_get_widget(xml, "button5");
+ g_signal_emit_by_name(widget, "clicked");
+ break;
+ case FULL_VIEW:
+ widget = glade_xml_get_widget(xml, "button6");
+ g_signal_emit_by_name(widget, "clicked");
+ break;
+ }
+#endif
+ txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+ tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
+ "foreground", "red",
+ "weight", PANGO_WEIGHT_BOLD,
+ NULL);
+ tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
+ /*"style", PANGO_STYLE_OBLIQUE, */
+ NULL);
+
+ gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text);
+
+ gtk_widget_show(main_wnd);
+}
+
+void init_tree_model(void)
+{
+ gint i;
+
+ tree = tree2 = gtk_tree_store_new(COL_NUMBER,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_POINTER, GDK_TYPE_COLOR,
+ G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN);
+ model2 = GTK_TREE_MODEL(tree2);
+
+ for (parents[0] = NULL, i = 1; i < 256; i++)
+ parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
+
+ tree1 = gtk_tree_store_new(COL_NUMBER,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_POINTER, GDK_TYPE_COLOR,
+ G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN);
+ model1 = GTK_TREE_MODEL(tree1);
+}
+
+void init_left_tree(void)
+{
+ GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
+ GtkCellRenderer *renderer;
+ GtkTreeSelection *sel;
+ GtkTreeViewColumn *column;
+
+ gtk_tree_view_set_model(view, model1);
+ gtk_tree_view_set_headers_visible(view, TRUE);
+ gtk_tree_view_set_rules_hint(view, TRUE);
+
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_append_column(view, column);
+ gtk_tree_view_column_set_title(column, _("Options"));
+
+ renderer = gtk_cell_renderer_toggle_new();
+ gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+ renderer, FALSE);
+ gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+ renderer,
+ "active", COL_BTNACT,
+ "inconsistent", COL_BTNINC,
+ "visible", COL_BTNVIS,
+ "radio", COL_BTNRAD, NULL);
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+ renderer, FALSE);
+ gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+ renderer,
+ "text", COL_OPTION,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+
+ sel = gtk_tree_view_get_selection(view);
+ gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+ gtk_widget_realize(tree1_w);
+}
+
+static void renderer_edited(GtkCellRendererText * cell,
+ const gchar * path_string,
+ const gchar * new_text, gpointer user_data);
+
+void init_right_tree(void)
+{
+ GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
+ GtkCellRenderer *renderer;
+ GtkTreeSelection *sel;
+ GtkTreeViewColumn *column;
+ gint i;
+
+ gtk_tree_view_set_model(view, model2);
+ gtk_tree_view_set_headers_visible(view, TRUE);
+ gtk_tree_view_set_rules_hint(view, TRUE);
+
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_append_column(view, column);
+ gtk_tree_view_column_set_title(column, _("Options"));
+
+ renderer = gtk_cell_renderer_pixbuf_new();
+ gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+ renderer, FALSE);
+ gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+ renderer,
+ "pixbuf", COL_PIXBUF,
+ "visible", COL_PIXVIS, NULL);
+ renderer = gtk_cell_renderer_toggle_new();
+ gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+ renderer, FALSE);
+ gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+ renderer,
+ "active", COL_BTNACT,
+ "inconsistent", COL_BTNINC,
+ "visible", COL_BTNVIS,
+ "radio", COL_BTNRAD, NULL);
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+ renderer, FALSE);
+ gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+ renderer,
+ "text", COL_OPTION,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes(view, -1,
+ _("Name"), renderer,
+ "text", COL_NAME,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes(view, -1,
+ "N", renderer,
+ "text", COL_NO,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes(view, -1,
+ "M", renderer,
+ "text", COL_MOD,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes(view, -1,
+ "Y", renderer,
+ "text", COL_YES,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes(view, -1,
+ _("Value"), renderer,
+ "text", COL_VALUE,
+ "editable",
+ COL_EDIT,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+ g_signal_connect(G_OBJECT(renderer), "edited",
+ G_CALLBACK(renderer_edited), NULL);
+
+ column = gtk_tree_view_get_column(view, COL_NAME);
+ gtk_tree_view_column_set_visible(column, show_name);
+ column = gtk_tree_view_get_column(view, COL_NO);
+ gtk_tree_view_column_set_visible(column, show_range);
+ column = gtk_tree_view_get_column(view, COL_MOD);
+ gtk_tree_view_column_set_visible(column, show_range);
+ column = gtk_tree_view_get_column(view, COL_YES);
+ gtk_tree_view_column_set_visible(column, show_range);
+ column = gtk_tree_view_get_column(view, COL_VALUE);
+ gtk_tree_view_column_set_visible(column, show_value);
+
+ if (resizeable) {
+ for (i = 0; i < COL_VALUE; i++) {
+ column = gtk_tree_view_get_column(view, i);
+ gtk_tree_view_column_set_resizable(column, TRUE);
+ }
+ }
+
+ sel = gtk_tree_view_get_selection(view);
+ gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+}
+
+
+/* Utility Functions */
+
+
+static void text_insert_help(struct menu *menu)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter start, end;
+ const char *prompt = _(menu_get_prompt(menu));
+ struct gstr help = str_new();
+
+ menu_get_ext_help(menu, &help);
+
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+ gtk_text_buffer_get_bounds(buffer, &start, &end);
+ gtk_text_buffer_delete(buffer, &start, &end);
+ gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+ gtk_text_buffer_get_end_iter(buffer, &end);
+ gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
+ NULL);
+ gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+ gtk_text_buffer_get_end_iter(buffer, &end);
+ gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
+ NULL);
+ str_free(&help);
+}
+
+
+static void text_insert_msg(const char *title, const char *message)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter start, end;
+ const char *msg = message;
+
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+ gtk_text_buffer_get_bounds(buffer, &start, &end);
+ gtk_text_buffer_delete(buffer, &start, &end);
+ gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+ gtk_text_buffer_get_end_iter(buffer, &end);
+ gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
+ NULL);
+ gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+ gtk_text_buffer_get_end_iter(buffer, &end);
+ gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
+ NULL);
+}
+
+
+/* Main Windows Callbacks */
+
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
+gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
+ gpointer user_data)
+{
+ GtkWidget *dialog, *label;
+ gint result;
+
+ if (!conf_get_changed())
+ return FALSE;
+
+ dialog = gtk_dialog_new_with_buttons(_("Warning !"),
+ GTK_WINDOW(main_wnd),
+ (GtkDialogFlags)
+ (GTK_DIALOG_MODAL |
+ GTK_DIALOG_DESTROY_WITH_PARENT),
+ GTK_STOCK_OK,
+ GTK_RESPONSE_YES,
+ GTK_STOCK_NO,
+ GTK_RESPONSE_NO,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL, NULL);
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog),
+ GTK_RESPONSE_CANCEL);
+
+ label = gtk_label_new(_("\nSave configuration ?\n"));
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
+ gtk_widget_show(label);
+
+ result = gtk_dialog_run(GTK_DIALOG(dialog));
+ switch (result) {
+ case GTK_RESPONSE_YES:
+ on_save_activate(NULL, NULL);
+ return FALSE;
+ case GTK_RESPONSE_NO:
+ return FALSE;
+ case GTK_RESPONSE_CANCEL:
+ case GTK_RESPONSE_DELETE_EVENT:
+ default:
+ gtk_widget_destroy(dialog);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+void on_window1_destroy(GtkObject * object, gpointer user_data)
+{
+ gtk_main_quit();
+}
+
+
+void
+on_window1_size_request(GtkWidget * widget,
+ GtkRequisition * requisition, gpointer user_data)
+{
+ static gint old_h;
+ gint w, h;
+
+ if (widget->window == NULL)
+ gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+ else
+ gdk_window_get_size(widget->window, &w, &h);
+
+ if (h == old_h)
+ return;
+ old_h = h;
+
+ gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
+}
+
+
+/* Menu & Toolbar Callbacks */
+
+
+static void
+load_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+ const gchar *fn;
+
+ fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+ (user_data));
+
+ if (conf_read(fn))
+ text_insert_msg(_("Error"), _("Unable to load configuration !"));
+ else
+ display_tree(&rootmenu);
+}
+
+void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkWidget *fs;
+
+ fs = gtk_file_selection_new(_("Load file..."));
+ g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+ "clicked",
+ G_CALLBACK(load_filename), (gpointer) fs);
+ g_signal_connect_swapped(GTK_OBJECT
+ (GTK_FILE_SELECTION(fs)->ok_button),
+ "clicked", G_CALLBACK(gtk_widget_destroy),
+ (gpointer) fs);
+ g_signal_connect_swapped(GTK_OBJECT
+ (GTK_FILE_SELECTION(fs)->cancel_button),
+ "clicked", G_CALLBACK(gtk_widget_destroy),
+ (gpointer) fs);
+ gtk_widget_show(fs);
+}
+
+
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ if (conf_write(NULL))
+ text_insert_msg(_("Error"), _("Unable to save configuration !"));
+}
+
+
+static void
+store_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+ const gchar *fn;
+
+ fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+ (user_data));
+
+ if (conf_write(fn))
+ text_insert_msg(_("Error"), _("Unable to save configuration !"));
+
+ gtk_widget_destroy(GTK_WIDGET(user_data));
+}
+
+void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkWidget *fs;
+
+ fs = gtk_file_selection_new(_("Save file as..."));
+ g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+ "clicked",
+ G_CALLBACK(store_filename), (gpointer) fs);
+ g_signal_connect_swapped(GTK_OBJECT
+ (GTK_FILE_SELECTION(fs)->ok_button),
+ "clicked", G_CALLBACK(gtk_widget_destroy),
+ (gpointer) fs);
+ g_signal_connect_swapped(GTK_OBJECT
+ (GTK_FILE_SELECTION(fs)->cancel_button),
+ "clicked", G_CALLBACK(gtk_widget_destroy),
+ (gpointer) fs);
+ gtk_widget_show(fs);
+}
+
+
+void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ if (!on_window1_delete_event(NULL, NULL, NULL))
+ gtk_widget_destroy(GTK_WIDGET(main_wnd));
+}
+
+
+void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkTreeViewColumn *col;
+
+ show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
+ col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
+ if (col)
+ gtk_tree_view_column_set_visible(col, show_name);
+}
+
+
+void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkTreeViewColumn *col;
+
+ show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
+ col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
+ if (col)
+ gtk_tree_view_column_set_visible(col, show_range);
+ col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
+ if (col)
+ gtk_tree_view_column_set_visible(col, show_range);
+ col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
+ if (col)
+ gtk_tree_view_column_set_visible(col, show_range);
+
+}
+
+
+void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkTreeViewColumn *col;
+
+ show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
+ col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
+ if (col)
+ gtk_tree_view_column_set_visible(col, show_value);
+}
+
+
+void
+on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+ opt_mode = OPT_NORMAL;
+ gtk_tree_store_clear(tree2);
+ display_tree(&rootmenu); /* instead of update_tree to speed-up */
+}
+
+
+void
+on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+ opt_mode = OPT_ALL;
+ gtk_tree_store_clear(tree2);
+ display_tree(&rootmenu); /* instead of update_tree to speed-up */
+}
+
+
+void
+on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+ opt_mode = OPT_PROMPT;
+ gtk_tree_store_clear(tree2);
+ display_tree(&rootmenu); /* instead of update_tree to speed-up */
+}
+
+
+void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkWidget *dialog;
+ const gchar *intro_text = _(
+ "Welcome to gkc, the GTK+ graphical configuration tool\n"
+ "For each option, a blank box indicates the feature is disabled, a\n"
+ "check indicates it is enabled, and a dot indicates that it is to\n"
+ "be compiled as a module. Clicking on the box will cycle through the three states.\n"
+ "\n"
+ "If you do not see an option (e.g., a device driver) that you\n"
+ "believe should be present, try turning on Show All Options\n"
+ "under the Options menu.\n"
+ "Although there is no cross reference yet to help you figure out\n"
+ "what other options must be enabled to support the option you\n"
+ "are interested in, you can still view the help of a grayed-out\n"
+ "option.\n"
+ "\n"
+ "Toggling Show Debug Info under the Options menu will show \n"
+ "the dependencies, which you can then match by examining other options.");
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE, "%s", intro_text);
+ g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+ G_CALLBACK(gtk_widget_destroy),
+ GTK_OBJECT(dialog));
+ gtk_widget_show_all(dialog);
+}
+
+
+void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkWidget *dialog;
+ const gchar *about_text =
+ _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
+ "Based on the source code from Roman Zippel.\n");
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE, "%s", about_text);
+ g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+ G_CALLBACK(gtk_widget_destroy),
+ GTK_OBJECT(dialog));
+ gtk_widget_show_all(dialog);
+}
+
+
+void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkWidget *dialog;
+ const gchar *license_text =
+ _("gkc is released under the terms of the GNU GPL v2.\n"
+ "For more information, please see the source code or\n"
+ "visit http://www.fsf.org/licenses/licenses.html\n");
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE, "%s", license_text);
+ g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+ G_CALLBACK(gtk_widget_destroy),
+ GTK_OBJECT(dialog));
+ gtk_widget_show_all(dialog);
+}
+
+
+void on_back_clicked(GtkButton * button, gpointer user_data)
+{
+ enum prop_type ptype;
+
+ current = current->parent;
+ ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
+ if (ptype != P_MENU)
+ current = current->parent;
+ display_tree_part();
+
+ if (current == &rootmenu)
+ gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_load_clicked(GtkButton * button, gpointer user_data)
+{
+ on_load1_activate(NULL, user_data);
+}
+
+
+void on_single_clicked(GtkButton * button, gpointer user_data)
+{
+ view_mode = SINGLE_VIEW;
+ gtk_widget_hide(tree1_w);
+ current = &rootmenu;
+ display_tree_part();
+}
+
+
+void on_split_clicked(GtkButton * button, gpointer user_data)
+{
+ gint w, h;
+ view_mode = SPLIT_VIEW;
+ gtk_widget_show(tree1_w);
+ gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+ gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
+ if (tree2)
+ gtk_tree_store_clear(tree2);
+ display_list();
+
+ /* Disable back btn, like in full mode. */
+ gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_full_clicked(GtkButton * button, gpointer user_data)
+{
+ view_mode = FULL_VIEW;
+ gtk_widget_hide(tree1_w);
+ if (tree2)
+ gtk_tree_store_clear(tree2);
+ display_tree(&rootmenu);
+ gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_collapse_clicked(GtkButton * button, gpointer user_data)
+{
+ gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+void on_expand_clicked(GtkButton * button, gpointer user_data)
+{
+ gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+/* CTree Callbacks */
+
+/* Change hex/int/string value in the cell */
+static void renderer_edited(GtkCellRendererText * cell,
+ const gchar * path_string,
+ const gchar * new_text, gpointer user_data)
+{
+ GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
+ GtkTreeIter iter;
+ const char *old_def, *new_def;
+ struct menu *menu;
+ struct symbol *sym;
+
+ if (!gtk_tree_model_get_iter(model2, &iter, path))
+ return;
+
+ gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+ sym = menu->sym;
+
+ gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
+ new_def = new_text;
+
+ sym_set_string_value(sym, new_def);
+
+ update_tree(&rootmenu, NULL);
+
+ gtk_tree_path_free(path);
+}
+
+/* Change the value of a symbol and update the tree */
+static void change_sym_value(struct menu *menu, gint col)
+{
+ struct symbol *sym = menu->sym;
+ tristate newval;
+
+ if (!sym)
+ return;
+
+ if (col == COL_NO)
+ newval = no;
+ else if (col == COL_MOD)
+ newval = mod;
+ else if (col == COL_YES)
+ newval = yes;
+ else
+ return;
+
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (!sym_tristate_within_range(sym, newval))
+ newval = yes;
+ sym_set_tristate_value(sym, newval);
+ if (view_mode == FULL_VIEW)
+ update_tree(&rootmenu, NULL);
+ else if (view_mode == SPLIT_VIEW) {
+ update_tree(browsed, NULL);
+ display_list();
+ }
+ else if (view_mode == SINGLE_VIEW)
+ display_tree_part(); //fixme: keep exp/coll
+ break;
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ default:
+ break;
+ }
+}
+
+static void toggle_sym_value(struct menu *menu)
+{
+ if (!menu->sym)
+ return;
+
+ sym_toggle_tristate_value(menu->sym);
+ if (view_mode == FULL_VIEW)
+ update_tree(&rootmenu, NULL);
+ else if (view_mode == SPLIT_VIEW) {
+ update_tree(browsed, NULL);
+ display_list();
+ }
+ else if (view_mode == SINGLE_VIEW)
+ display_tree_part(); //fixme: keep exp/coll
+}
+
+static gint column2index(GtkTreeViewColumn * column)
+{
+ gint i;
+
+ for (i = 0; i < COL_NUMBER; i++) {
+ GtkTreeViewColumn *col;
+
+ col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
+ if (col == column)
+ return i;
+ }
+
+ return -1;
+}
+
+
+/* User click: update choice (full) or goes down (single) */
+gboolean
+on_treeview2_button_press_event(GtkWidget * widget,
+ GdkEventButton * event, gpointer user_data)
+{
+ GtkTreeView *view = GTK_TREE_VIEW(widget);
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ struct menu *menu;
+ gint col;
+
+#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
+ gint tx = (gint) event->x;
+ gint ty = (gint) event->y;
+ gint cx, cy;
+
+ gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+ &cy);
+#else
+ gtk_tree_view_get_cursor(view, &path, &column);
+#endif
+ if (path == NULL)
+ return FALSE;
+
+ if (!gtk_tree_model_get_iter(model2, &iter, path))
+ return FALSE;
+ gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+ col = column2index(column);
+ if (event->type == GDK_2BUTTON_PRESS) {
+ enum prop_type ptype;
+ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+
+ if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
+ // goes down into menu
+ current = menu;
+ display_tree_part();
+ gtk_widget_set_sensitive(back_btn, TRUE);
+ } else if ((col == COL_OPTION)) {
+ toggle_sym_value(menu);
+ gtk_tree_view_expand_row(view, path, TRUE);
+ }
+ } else {
+ if (col == COL_VALUE) {
+ toggle_sym_value(menu);
+ gtk_tree_view_expand_row(view, path, TRUE);
+ } else if (col == COL_NO || col == COL_MOD
+ || col == COL_YES) {
+ change_sym_value(menu, col);
+ gtk_tree_view_expand_row(view, path, TRUE);
+ }
+ }
+
+ return FALSE;
+}
+
+/* Key pressed: update choice */
+gboolean
+on_treeview2_key_press_event(GtkWidget * widget,
+ GdkEventKey * event, gpointer user_data)
+{
+ GtkTreeView *view = GTK_TREE_VIEW(widget);
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ struct menu *menu;
+ gint col;
+
+ gtk_tree_view_get_cursor(view, &path, &column);
+ if (path == NULL)
+ return FALSE;
+
+ if (event->keyval == GDK_space) {
+ if (gtk_tree_view_row_expanded(view, path))
+ gtk_tree_view_collapse_row(view, path);
+ else
+ gtk_tree_view_expand_row(view, path, FALSE);
+ return TRUE;
+ }
+ if (event->keyval == GDK_KP_Enter) {
+ }
+ if (widget == tree1_w)
+ return FALSE;
+
+ gtk_tree_model_get_iter(model2, &iter, path);
+ gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+ if (!strcasecmp(event->string, "n"))
+ col = COL_NO;
+ else if (!strcasecmp(event->string, "m"))
+ col = COL_MOD;
+ else if (!strcasecmp(event->string, "y"))
+ col = COL_YES;
+ else
+ col = -1;
+ change_sym_value(menu, col);
+
+ return FALSE;
+}
+
+
+/* Row selection changed: update help */
+void
+on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
+{
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ struct menu *menu;
+
+ selection = gtk_tree_view_get_selection(treeview);
+ if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
+ gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+ text_insert_help(menu);
+ }
+}
+
+
+/* User click: display sub-tree in the right frame. */
+gboolean
+on_treeview1_button_press_event(GtkWidget * widget,
+ GdkEventButton * event, gpointer user_data)
+{
+ GtkTreeView *view = GTK_TREE_VIEW(widget);
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ struct menu *menu;
+
+ gint tx = (gint) event->x;
+ gint ty = (gint) event->y;
+ gint cx, cy;
+
+ gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+ &cy);
+ if (path == NULL)
+ return FALSE;
+
+ gtk_tree_model_get_iter(model1, &iter, path);
+ gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
+
+ if (event->type == GDK_2BUTTON_PRESS) {
+ toggle_sym_value(menu);
+ current = menu;
+ display_tree_part();
+ } else {
+ browsed = menu;
+ display_tree_part();
+ }
+
+ gtk_widget_realize(tree2_w);
+ gtk_tree_view_set_cursor(view, path, NULL, FALSE);
+ gtk_widget_grab_focus(tree2_w);
+
+ return FALSE;
+}
+
+
+/* Fill a row of strings */
+static gchar **fill_row(struct menu *menu)
+{
+ static gchar *row[COL_NUMBER];
+ struct symbol *sym = menu->sym;
+ const char *def;
+ int stype;
+ tristate val;
+ enum prop_type ptype;
+ int i;
+
+ for (i = COL_OPTION; i <= COL_COLOR; i++)
+ g_free(row[i]);
+ bzero(row, sizeof(row));
+
+ row[COL_OPTION] =
+ g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
+ sym && !sym_has_value(sym) ? "(NEW)" : "");
+
+ if (opt_mode == OPT_ALL && !menu_is_visible(menu))
+ row[COL_COLOR] = g_strdup("DarkGray");
+ else if (opt_mode == OPT_PROMPT &&
+ menu_has_prompt(menu) && !menu_is_visible(menu))
+ row[COL_COLOR] = g_strdup("DarkGray");
+ else
+ row[COL_COLOR] = g_strdup("Black");
+
+ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ switch (ptype) {
+ case P_MENU:
+ row[COL_PIXBUF] = (gchar *) xpm_menu;
+ if (view_mode == SINGLE_VIEW)
+ row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
+ row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+ break;
+ case P_COMMENT:
+ row[COL_PIXBUF] = (gchar *) xpm_void;
+ row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+ row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+ break;
+ default:
+ row[COL_PIXBUF] = (gchar *) xpm_void;
+ row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+ row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+ break;
+ }
+
+ if (!sym)
+ return row;
+ row[COL_NAME] = g_strdup(sym->name);
+
+ sym_calc_value(sym);
+ sym->flags &= ~SYMBOL_CHANGED;
+
+ if (sym_is_choice(sym)) { // parse childs for getting final value
+ struct menu *child;
+ struct symbol *def_sym = sym_get_choice_value(sym);
+ struct menu *def_menu = NULL;
+
+ row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child)
+ && child->sym == def_sym)
+ def_menu = child;
+ }
+
+ if (def_menu)
+ row[COL_VALUE] =
+ g_strdup(_(menu_get_prompt(def_menu)));
+ }
+ if (sym->flags & SYMBOL_CHOICEVAL)
+ row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
+
+ stype = sym_get_type(sym);
+ switch (stype) {
+ case S_BOOLEAN:
+ if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
+ row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+ if (sym_is_choice(sym))
+ break;
+ /* fall through */
+ case S_TRISTATE:
+ val = sym_get_tristate_value(sym);
+ switch (val) {
+ case no:
+ row[COL_NO] = g_strdup("N");
+ row[COL_VALUE] = g_strdup("N");
+ row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
+ row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+ break;
+ case mod:
+ row[COL_MOD] = g_strdup("M");
+ row[COL_VALUE] = g_strdup("M");
+ row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
+ break;
+ case yes:
+ row[COL_YES] = g_strdup("Y");
+ row[COL_VALUE] = g_strdup("Y");
+ row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
+ row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+ break;
+ }
+
+ if (val != no && sym_tristate_within_range(sym, no))
+ row[COL_NO] = g_strdup("_");
+ if (val != mod && sym_tristate_within_range(sym, mod))
+ row[COL_MOD] = g_strdup("_");
+ if (val != yes && sym_tristate_within_range(sym, yes))
+ row[COL_YES] = g_strdup("_");
+ break;
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ def = sym_get_string_value(sym);
+ row[COL_VALUE] = g_strdup(def);
+ row[COL_EDIT] = GINT_TO_POINTER(TRUE);
+ row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+ break;
+ }
+
+ return row;
+}
+
+
+/* Set the node content with a row of strings */
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
+{
+ GdkColor color;
+ gboolean success;
+ GdkPixbuf *pix;
+
+ pix = gdk_pixbuf_new_from_xpm_data((const char **)
+ row[COL_PIXBUF]);
+
+ gdk_color_parse(row[COL_COLOR], &color);
+ gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
+ FALSE, FALSE, &success);
+
+ gtk_tree_store_set(tree, node,
+ COL_OPTION, row[COL_OPTION],
+ COL_NAME, row[COL_NAME],
+ COL_NO, row[COL_NO],
+ COL_MOD, row[COL_MOD],
+ COL_YES, row[COL_YES],
+ COL_VALUE, row[COL_VALUE],
+ COL_MENU, (gpointer) menu,
+ COL_COLOR, &color,
+ COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
+ COL_PIXBUF, pix,
+ COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
+ COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
+ COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
+ COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
+ COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
+ -1);
+
+ g_object_unref(pix);
+}
+
+
+/* Add a node to the tree */
+static void place_node(struct menu *menu, char **row)
+{
+ GtkTreeIter *parent = parents[indent - 1];
+ GtkTreeIter *node = parents[indent];
+
+ gtk_tree_store_append(tree, node, parent);
+ set_node(node, menu, row);
+}
+
+
+/* Find a node in the GTK+ tree */
+static GtkTreeIter found;
+
+/*
+ * Find a menu in the GtkTree starting at parent.
+ */
+GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
+ struct menu *tofind)
+{
+ GtkTreeIter iter;
+ GtkTreeIter *child = &iter;
+ gboolean valid;
+ GtkTreeIter *ret;
+
+ valid = gtk_tree_model_iter_children(model2, child, parent);
+ while (valid) {
+ struct menu *menu;
+
+ gtk_tree_model_get(model2, child, 6, &menu, -1);
+
+ if (menu == tofind) {
+ memcpy(&found, child, sizeof(GtkTreeIter));
+ return &found;
+ }
+
+ ret = gtktree_iter_find_node(child, tofind);
+ if (ret)
+ return ret;
+
+ valid = gtk_tree_model_iter_next(model2, child);
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Update the tree by adding/removing entries
+ * Does not change other nodes
+ */
+static void update_tree(struct menu *src, GtkTreeIter * dst)
+{
+ struct menu *child1;
+ GtkTreeIter iter, tmp;
+ GtkTreeIter *child2 = &iter;
+ gboolean valid;
+ GtkTreeIter *sibling;
+ struct symbol *sym;
+ struct menu *menu1, *menu2;
+
+ if (src == &rootmenu)
+ indent = 1;
+
+ valid = gtk_tree_model_iter_children(model2, child2, dst);
+ for (child1 = src->list; child1; child1 = child1->next) {
+
+ sym = child1->sym;
+
+ reparse:
+ menu1 = child1;
+ if (valid)
+ gtk_tree_model_get(model2, child2, COL_MENU,
+ &menu2, -1);
+ else
+ menu2 = NULL; // force adding of a first child
+
+#ifdef DEBUG
+ printf("%*c%s | %s\n", indent, ' ',
+ menu1 ? menu_get_prompt(menu1) : "nil",
+ menu2 ? menu_get_prompt(menu2) : "nil");
+#endif
+
+ if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) ||
+ (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) ||
+ (opt_mode == OPT_ALL && !menu_get_prompt(child1))) {
+
+ /* remove node */
+ if (gtktree_iter_find_node(dst, menu1) != NULL) {
+ memcpy(&tmp, child2, sizeof(GtkTreeIter));
+ valid = gtk_tree_model_iter_next(model2,
+ child2);
+ gtk_tree_store_remove(tree2, &tmp);
+ if (!valid)
+ return; /* next parent */
+ else
+ goto reparse; /* next child */
+ } else
+ continue;
+ }
+
+ if (menu1 != menu2) {
+ if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
+ if (!valid && !menu2)
+ sibling = NULL;
+ else
+ sibling = child2;
+ gtk_tree_store_insert_before(tree2,
+ child2,
+ dst, sibling);
+ set_node(child2, menu1, fill_row(menu1));
+ if (menu2 == NULL)
+ valid = TRUE;
+ } else { // remove node
+ memcpy(&tmp, child2, sizeof(GtkTreeIter));
+ valid = gtk_tree_model_iter_next(model2,
+ child2);
+ gtk_tree_store_remove(tree2, &tmp);
+ if (!valid)
+ return; // next parent
+ else
+ goto reparse; // next child
+ }
+ } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
+ set_node(child2, menu1, fill_row(menu1));
+ }
+
+ indent++;
+ update_tree(child1, child2);
+ indent--;
+
+ valid = gtk_tree_model_iter_next(model2, child2);
+ }
+}
+
+
+/* Display the whole tree (single/split/full view) */
+static void display_tree(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+ enum prop_type ptype;
+
+ if (menu == &rootmenu) {
+ indent = 1;
+ current = &rootmenu;
+ }
+
+ for (child = menu->list; child; child = child->next) {
+ prop = child->prompt;
+ sym = child->sym;
+ ptype = prop ? prop->type : P_UNKNOWN;
+
+ if (sym)
+ sym->flags &= ~SYMBOL_CHANGED;
+
+ if ((view_mode == SPLIT_VIEW)
+ && !(child->flags & MENU_ROOT) && (tree == tree1))
+ continue;
+
+ if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
+ && (tree == tree2))
+ continue;
+
+ if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) ||
+ (opt_mode == OPT_PROMPT && menu_has_prompt(child)) ||
+ (opt_mode == OPT_ALL && menu_get_prompt(child)))
+ place_node(child, fill_row(child));
+#ifdef DEBUG
+ printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
+ printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
+ printf("%s", prop_get_type_name(ptype));
+ printf(" | ");
+ if (sym) {
+ printf("%s", sym_type_name(sym->type));
+ printf(" | ");
+ printf("%s", dbg_sym_flags(sym->flags));
+ printf("\n");
+ } else
+ printf("\n");
+#endif
+ if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
+ && (tree == tree2))
+ continue;
+/*
+ if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
+ || (view_mode == FULL_VIEW)
+ || (view_mode == SPLIT_VIEW))*/
+
+ /* Change paned position if the view is not in 'split mode' */
+ if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) {
+ gtk_paned_set_position(GTK_PANED(hpaned), 0);
+ }
+
+ if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
+ || (view_mode == FULL_VIEW)
+ || (view_mode == SPLIT_VIEW)) {
+ indent++;
+ display_tree(child);
+ indent--;
+ }
+ }
+}
+
+/* Display a part of the tree starting at current node (single/split view) */
+static void display_tree_part(void)
+{
+ if (tree2)
+ gtk_tree_store_clear(tree2);
+ if (view_mode == SINGLE_VIEW)
+ display_tree(current);
+ else if (view_mode == SPLIT_VIEW)
+ display_tree(browsed);
+ gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+/* Display the list in the left frame (split view) */
+static void display_list(void)
+{
+ if (tree1)
+ gtk_tree_store_clear(tree1);
+
+ tree = tree1;
+ display_tree(&rootmenu);
+ gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
+ tree = tree2;
+}
+
+void fixup_rootmenu(struct menu *menu)
+{
+ struct menu *child;
+ static int menu_cnt = 0;
+
+ menu->flags |= MENU_ROOT;
+ for (child = menu->list; child; child = child->next) {
+ if (child->prompt && child->prompt->type == P_MENU) {
+ menu_cnt++;
+ fixup_rootmenu(child);
+ menu_cnt--;
+ } else if (!menu_cnt)
+ fixup_rootmenu(child);
+ }
+}
+
+
+/* Main */
+int main(int ac, char *av[])
+{
+ const char *name;
+ char *env;
+ gchar *glade_file;
+
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset(PACKAGE, "UTF-8");
+ textdomain(PACKAGE);
+
+ /* GTK stuffs */
+ gtk_set_locale();
+ gtk_init(&ac, &av);
+ glade_init();
+
+ //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
+ //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
+
+ /* Determine GUI path */
+ env = getenv(SRCTREE);
+ if (env)
+ glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
+ else if (av[0][0] == '/')
+ glade_file = g_strconcat(av[0], ".glade", NULL);
+ else
+ glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
+
+ /* Conf stuffs */
+ if (ac > 1 && av[1][0] == '-') {
+ switch (av[1][1]) {
+ case 'a':
+ //showAll = 1;
+ break;
+ case 'h':
+ case '?':
+ printf("%s <config>\n", av[0]);
+ exit(0);
+ }
+ name = av[2];
+ } else
+ name = av[1];
+
+ conf_parse(name);
+ fixup_rootmenu(&rootmenu);
+ conf_read(NULL);
+
+ /* Load the interface and connect signals */
+ init_main_window(glade_file);
+ init_tree_model();
+ init_left_tree();
+ init_right_tree();
+
+ switch (view_mode) {
+ case SINGLE_VIEW:
+ display_tree_part();
+ break;
+ case SPLIT_VIEW:
+ display_list();
+ break;
+ case FULL_VIEW:
+ display_tree(&rootmenu);
+ break;
+ }
+
+ gtk_main();
+
+ return 0;
+}
+
+static void conf_changed(void)
+{
+ bool changed = conf_get_changed();
+ gtk_widget_set_sensitive(save_btn, changed);
+ gtk_widget_set_sensitive(save_menu_item, changed);
+}
diff --git a/roms/seabios/scripts/kconfig/gconf.glade b/roms/seabios/scripts/kconfig/gconf.glade
new file mode 100644
index 00000000..aa483cb3
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/gconf.glade
@@ -0,0 +1,661 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+
+<glade-interface>
+
+<widget class="GtkWindow" id="window1">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Gtk Kernel Configurator</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">640</property>
+ <property name="default_height">480</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <signal name="destroy" handler="on_window1_destroy" object="window1"/>
+ <signal name="size_request" handler="on_window1_size_request" object="vpaned1" last_modification_time="Fri, 11 Jan 2002 16:17:11 GMT"/>
+ <signal name="delete_event" handler="on_window1_delete_event" object="window1" last_modification_time="Sun, 09 Mar 2003 19:42:46 GMT"/>
+
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="file1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="file1_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="load1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Load a config file</property>
+ <property name="label" translatable="yes">_Load</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_load1_activate"/>
+ <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image39">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="save1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Save the config in .config</property>
+ <property name="label" translatable="yes">_Save</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_save_activate"/>
+ <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image40">
+ <property name="visible">True</property>
+ <property name="stock">gtk-save</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="save_as1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Save the config in a file</property>
+ <property name="label" translatable="yes">Save _as</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_save_as1_activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image41">
+ <property name="visible">True</property>
+ <property name="stock">gtk-save-as</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator1">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="quit1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Quit</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_quit1_activate"/>
+ <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image42">
+ <property name="visible">True</property>
+ <property name="stock">gtk-quit</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="options1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Options</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="options1_menu">
+
+ <child>
+ <widget class="GtkCheckMenuItem" id="show_name1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Show name</property>
+ <property name="label" translatable="yes">Show _name</property>
+ <property name="use_underline">True</property>
+ <property name="active">False</property>
+ <signal name="activate" handler="on_show_name1_activate"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkCheckMenuItem" id="show_range1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Show range (Y/M/N)</property>
+ <property name="label" translatable="yes">Show _range</property>
+ <property name="use_underline">True</property>
+ <property name="active">False</property>
+ <signal name="activate" handler="on_show_range1_activate"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkCheckMenuItem" id="show_data1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Show value of the option</property>
+ <property name="label" translatable="yes">Show _data</property>
+ <property name="use_underline">True</property>
+ <property name="active">False</property>
+ <signal name="activate" handler="on_show_data1_activate"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator2">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkRadioMenuItem" id="set_option_mode1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Show normal options</property>
+ <property name="label" translatable="yes">Show normal options</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <signal name="activate" handler="on_set_option_mode1_activate"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkRadioMenuItem" id="set_option_mode2">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Show all options</property>
+ <property name="label" translatable="yes">Show all _options</property>
+ <property name="use_underline">True</property>
+ <property name="active">False</property>
+ <property name="group">set_option_mode1</property>
+ <signal name="activate" handler="on_set_option_mode2_activate"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkRadioMenuItem" id="set_option_mode3">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Show all options with prompts</property>
+ <property name="label" translatable="yes">Show all prompt options</property>
+ <property name="use_underline">True</property>
+ <property name="active">False</property>
+ <property name="group">set_option_mode1</property>
+ <signal name="activate" handler="on_set_option_mode3_activate"/>
+ </widget>
+ </child>
+
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="help1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Help</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="help1_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="introduction1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Introduction</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_introduction1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+ <accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image43">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-question</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="about1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_About</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_about1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+ <accelerator key="A" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image44">
+ <property name="visible">True</property>
+ <property name="stock">gtk-properties</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="license1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_License</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_license1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image45">
+ <property name="visible">True</property>
+ <property name="stock">gtk-justify-fill</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHandleBox" id="handlebox1">
+ <property name="visible">True</property>
+ <property name="shadow_type">GTK_SHADOW_OUT</property>
+ <property name="handle_position">GTK_POS_LEFT</property>
+ <property name="snap_edge">GTK_POS_TOP</property>
+
+ <child>
+ <widget class="GtkToolbar" id="toolbar1">
+ <property name="visible">True</property>
+ <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+ <property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
+ <property name="tooltips">True</property>
+ <property name="show_arrow">True</property>
+
+ <child>
+ <widget class="GtkToolButton" id="button1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Goes up of one level (single view)</property>
+ <property name="label" translatable="yes">Back</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-undo</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_back_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem1">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkVSeparator" id="vseparator1">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button2">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Load a config file</property>
+ <property name="label" translatable="yes">Load</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-open</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_load_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button3">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Save a config file</property>
+ <property name="label" translatable="yes">Save</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-save</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_save_activate"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem2">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkVSeparator" id="vseparator2">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button4">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Single view</property>
+ <property name="label" translatable="yes">Single</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-missing-image</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_single_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:39 GMT"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button5">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Split view</property>
+ <property name="label" translatable="yes">Split</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-missing-image</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_split_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:45 GMT"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button6">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Full view</property>
+ <property name="label" translatable="yes">Full</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-missing-image</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_full_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:50 GMT"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem3">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkVSeparator" id="vseparator3">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button7">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Collapse the whole tree in the right frame</property>
+ <property name="label" translatable="yes">Collapse</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-remove</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_collapse_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button8">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Expand the whole tree in the right frame</property>
+ <property name="label" translatable="yes">Expand</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-add</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_expand_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHPaned" id="hpaned1">
+ <property name="width_request">1</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="position">0</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">False</property>
+ <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:58:22 GMT"/>
+ <signal name="button_press_event" handler="on_treeview1_button_press_event" last_modification_time="Sun, 12 Jan 2003 16:03:52 GMT"/>
+ <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 16:11:44 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVPaned" id="vpaned1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="position">0</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">False</property>
+ <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:57:55 GMT"/>
+ <signal name="button_press_event" handler="on_treeview2_button_press_event" last_modification_time="Sun, 12 Jan 2003 15:57:58 GMT"/>
+ <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 15:58:01 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow3">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTextView" id="textview3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="overwrite">False</property>
+ <property name="accepts_tab">True</property>
+ <property name="justification">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap_mode">GTK_WRAP_WORD</property>
+ <property name="cursor_visible">True</property>
+ <property name="pixels_above_lines">0</property>
+ <property name="pixels_below_lines">0</property>
+ <property name="pixels_inside_wrap">0</property>
+ <property name="left_margin">0</property>
+ <property name="right_margin">0</property>
+ <property name="indent">0</property>
+ <property name="text" translatable="yes">Sorry, no help available for this option yet.</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/roms/seabios/scripts/kconfig/images.c b/roms/seabios/scripts/kconfig/images.c
new file mode 100644
index 00000000..d4f84bd4
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/images.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+static const char *xpm_load[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"c c #838100",
+"a c #ffff00",
+"b c #ffffff",
+"......................",
+"......................",
+"......................",
+"............####....#.",
+"...........#....##.##.",
+"..................###.",
+".................####.",
+".####...........#####.",
+"#abab##########.......",
+"#babababababab#.......",
+"#ababababababa#.......",
+"#babababababab#.......",
+"#ababab###############",
+"#babab##cccccccccccc##",
+"#abab##cccccccccccc##.",
+"#bab##cccccccccccc##..",
+"#ab##cccccccccccc##...",
+"#b##cccccccccccc##....",
+"###cccccccccccc##.....",
+"##cccccccccccc##......",
+"###############.......",
+"......................"};
+
+static const char *xpm_save[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"a c #838100",
+"b c #c5c2c5",
+"c c #cdb6d5",
+"......................",
+".####################.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbcbb####.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aaa############aaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaa#############aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+"..##################..",
+"......................"};
+
+static const char *xpm_back[] = {
+"22 22 3 1",
+". c None",
+"# c #000083",
+"a c #838183",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"...........######a....",
+"..#......##########...",
+"..##...####......##a..",
+"..###.###.........##..",
+"..######..........##..",
+"..#####...........##..",
+"..######..........##..",
+"..#######.........##..",
+"..########.......##a..",
+"...............a###...",
+"...............###....",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................"};
+
+static const char *xpm_tree_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......................",
+"......................"};
+
+static const char *xpm_single_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"......................",
+"......................"};
+
+static const char *xpm_split_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......................",
+"......................"};
+
+static const char *xpm_symbol_no[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" .......... ",
+" "};
+
+static const char *xpm_symbol_mod[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" . . ",
+" .......... ",
+" "};
+
+static const char *xpm_symbol_yes[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . . ",
+" . . . ",
+" . .. . ",
+" . . .. . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .......... ",
+" "};
+
+static const char *xpm_choice_no[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .... ",
+" .. .. ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" .. .. ",
+" .... ",
+" "};
+
+static const char *xpm_choice_yes[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .... ",
+" .. .. ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .. .. ",
+" .... ",
+" "};
+
+static const char *xpm_menu[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . ...... . ",
+" . ...... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .......... ",
+" "};
+
+static const char *xpm_menu_inv[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" .......... ",
+" .. ...... ",
+" .. .... ",
+" .. .. ",
+" .. .. ",
+" .. .... ",
+" .. ...... ",
+" .......... ",
+" .......... ",
+" "};
+
+static const char *xpm_menuback[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . ...... . ",
+" . ...... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .......... ",
+" "};
+
+static const char *xpm_void[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "};
diff --git a/roms/seabios/scripts/kconfig/kxgettext.c b/roms/seabios/scripts/kconfig/kxgettext.c
new file mode 100644
index 00000000..2858738b
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/kxgettext.c
@@ -0,0 +1,235 @@
+/*
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2005
+ *
+ * Released under the terms of the GNU GPL v2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "lkc.h"
+
+static char *escape(const char* text, char *bf, int len)
+{
+ char *bfp = bf;
+ int multiline = strchr(text, '\n') != NULL;
+ int eol = 0;
+ int textlen = strlen(text);
+
+ if ((textlen > 0) && (text[textlen-1] == '\n'))
+ eol = 1;
+
+ *bfp++ = '"';
+ --len;
+
+ if (multiline) {
+ *bfp++ = '"';
+ *bfp++ = '\n';
+ *bfp++ = '"';
+ len -= 3;
+ }
+
+ while (*text != '\0' && len > 1) {
+ if (*text == '"')
+ *bfp++ = '\\';
+ else if (*text == '\n') {
+ *bfp++ = '\\';
+ *bfp++ = 'n';
+ *bfp++ = '"';
+ *bfp++ = '\n';
+ *bfp++ = '"';
+ len -= 5;
+ ++text;
+ goto next;
+ }
+ else if (*text == '\\') {
+ *bfp++ = '\\';
+ len--;
+ }
+ *bfp++ = *text++;
+next:
+ --len;
+ }
+
+ if (multiline && eol)
+ bfp -= 3;
+
+ *bfp++ = '"';
+ *bfp = '\0';
+
+ return bf;
+}
+
+struct file_line {
+ struct file_line *next;
+ const char *file;
+ int lineno;
+};
+
+static struct file_line *file_line__new(const char *file, int lineno)
+{
+ struct file_line *self = malloc(sizeof(*self));
+
+ if (self == NULL)
+ goto out;
+
+ self->file = file;
+ self->lineno = lineno;
+ self->next = NULL;
+out:
+ return self;
+}
+
+struct message {
+ const char *msg;
+ const char *option;
+ struct message *next;
+ struct file_line *files;
+};
+
+static struct message *message__list;
+
+static struct message *message__new(const char *msg, char *option,
+ const char *file, int lineno)
+{
+ struct message *self = malloc(sizeof(*self));
+
+ if (self == NULL)
+ goto out;
+
+ self->files = file_line__new(file, lineno);
+ if (self->files == NULL)
+ goto out_fail;
+
+ self->msg = strdup(msg);
+ if (self->msg == NULL)
+ goto out_fail_msg;
+
+ self->option = option;
+ self->next = NULL;
+out:
+ return self;
+out_fail_msg:
+ free(self->files);
+out_fail:
+ free(self);
+ self = NULL;
+ goto out;
+}
+
+static struct message *mesage__find(const char *msg)
+{
+ struct message *m = message__list;
+
+ while (m != NULL) {
+ if (strcmp(m->msg, msg) == 0)
+ break;
+ m = m->next;
+ }
+
+ return m;
+}
+
+static int message__add_file_line(struct message *self, const char *file,
+ int lineno)
+{
+ int rc = -1;
+ struct file_line *fl = file_line__new(file, lineno);
+
+ if (fl == NULL)
+ goto out;
+
+ fl->next = self->files;
+ self->files = fl;
+ rc = 0;
+out:
+ return rc;
+}
+
+static int message__add(const char *msg, char *option, const char *file,
+ int lineno)
+{
+ int rc = 0;
+ char bf[16384];
+ char *escaped = escape(msg, bf, sizeof(bf));
+ struct message *m = mesage__find(escaped);
+
+ if (m != NULL)
+ rc = message__add_file_line(m, file, lineno);
+ else {
+ m = message__new(escaped, option, file, lineno);
+
+ if (m != NULL) {
+ m->next = message__list;
+ message__list = m;
+ } else
+ rc = -1;
+ }
+ return rc;
+}
+
+static void menu_build_message_list(struct menu *menu)
+{
+ struct menu *child;
+
+ message__add(menu_get_prompt(menu), NULL,
+ menu->file == NULL ? "Root Menu" : menu->file->name,
+ menu->lineno);
+
+ if (menu->sym != NULL && menu_has_help(menu))
+ message__add(menu_get_help(menu), menu->sym->name,
+ menu->file == NULL ? "Root Menu" : menu->file->name,
+ menu->lineno);
+
+ for (child = menu->list; child != NULL; child = child->next)
+ if (child->prompt != NULL)
+ menu_build_message_list(child);
+}
+
+static void message__print_file_lineno(struct message *self)
+{
+ struct file_line *fl = self->files;
+
+ putchar('\n');
+ if (self->option != NULL)
+ printf("# %s:00000\n", self->option);
+
+ printf("#: %s:%d", fl->file, fl->lineno);
+ fl = fl->next;
+
+ while (fl != NULL) {
+ printf(", %s:%d", fl->file, fl->lineno);
+ fl = fl->next;
+ }
+
+ putchar('\n');
+}
+
+static void message__print_gettext_msgid_msgstr(struct message *self)
+{
+ message__print_file_lineno(self);
+
+ printf("msgid %s\n"
+ "msgstr \"\"\n", self->msg);
+}
+
+static void menu__xgettext(void)
+{
+ struct message *m = message__list;
+
+ while (m != NULL) {
+ /* skip empty lines ("") */
+ if (strlen(m->msg) > sizeof("\"\""))
+ message__print_gettext_msgid_msgstr(m);
+ m = m->next;
+ }
+}
+
+int main(int ac, char **av)
+{
+ conf_parse(av[1]);
+
+ menu_build_message_list(menu_get_root_menu(NULL));
+ menu__xgettext();
+ return 0;
+}
diff --git a/roms/seabios/scripts/kconfig/lex.zconf.c b/roms/seabios/scripts/kconfig/lex.zconf.c
new file mode 100644
index 00000000..6eb03971
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/lex.zconf.c
@@ -0,0 +1,2430 @@
+
+#line 3 "scripts/kconfig/lex.zconf.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer zconf_create_buffer
+#define yy_delete_buffer zconf_delete_buffer
+#define yy_flex_debug zconf_flex_debug
+#define yy_init_buffer zconf_init_buffer
+#define yy_flush_buffer zconf_flush_buffer
+#define yy_load_buffer_state zconf_load_buffer_state
+#define yy_switch_to_buffer zconf_switch_to_buffer
+#define yyin zconfin
+#define yyleng zconfleng
+#define yylex zconflex
+#define yylineno zconflineno
+#define yyout zconfout
+#define yyrestart zconfrestart
+#define yytext zconftext
+#define yywrap zconfwrap
+#define yyalloc zconfalloc
+#define yyrealloc zconfrealloc
+#define yyfree zconffree
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE zconfrestart(zconfin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int zconfleng;
+
+extern FILE *zconfin, *zconfout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up zconftext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up zconftext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via zconfrestart()), so that the user can continue scanning by
+ * just pointing zconfin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when zconftext is formed. */
+static char yy_hold_char;
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+int zconfleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow zconfwrap()'s to do buffer switches
+ * instead of setting up a fresh zconfin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void zconfrestart (FILE *input_file );
+void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size );
+void zconf_delete_buffer (YY_BUFFER_STATE b );
+void zconf_flush_buffer (YY_BUFFER_STATE b );
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer );
+void zconfpop_buffer_state (void );
+
+static void zconfensure_buffer_stack (void );
+static void zconf_load_buffer_state (void );
+static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len );
+
+void *zconfalloc (yy_size_t );
+void *zconfrealloc (void *,yy_size_t );
+void zconffree (void * );
+
+#define yy_new_buffer zconf_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ zconfensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ zconfensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define zconfwrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int zconflineno;
+
+int zconflineno = 1;
+
+extern char *zconftext;
+#define yytext_ptr zconftext
+static yyconst flex_int16_t yy_nxt[][17] =
+ {
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0
+ },
+
+ {
+ 11, 12, 13, 14, 12, 12, 15, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12
+ },
+
+ {
+ 11, 12, 13, 14, 12, 12, 15, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12
+ },
+
+ {
+ 11, 16, 16, 17, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 18, 16, 16, 16
+ },
+
+ {
+ 11, 16, 16, 17, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 18, 16, 16, 16
+
+ },
+
+ {
+ 11, 19, 20, 21, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19
+ },
+
+ {
+ 11, 19, 20, 21, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19
+ },
+
+ {
+ 11, 22, 22, 23, 22, 24, 22, 22, 24, 22,
+ 22, 22, 22, 22, 22, 25, 22
+ },
+
+ {
+ 11, 22, 22, 23, 22, 24, 22, 22, 24, 22,
+ 22, 22, 22, 22, 22, 25, 22
+ },
+
+ {
+ 11, 26, 26, 27, 28, 29, 30, 31, 29, 32,
+ 33, 34, 35, 35, 36, 37, 38
+
+ },
+
+ {
+ 11, 26, 26, 27, 28, 29, 30, 31, 29, 32,
+ 33, 34, 35, 35, 36, 37, 38
+ },
+
+ {
+ -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+ -11, -11, -11, -11, -11, -11, -11
+ },
+
+ {
+ 11, -12, -12, -12, -12, -12, -12, -12, -12, -12,
+ -12, -12, -12, -12, -12, -12, -12
+ },
+
+ {
+ 11, -13, 39, 40, -13, -13, 41, -13, -13, -13,
+ -13, -13, -13, -13, -13, -13, -13
+ },
+
+ {
+ 11, -14, -14, -14, -14, -14, -14, -14, -14, -14,
+ -14, -14, -14, -14, -14, -14, -14
+
+ },
+
+ {
+ 11, 42, 42, 43, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42
+ },
+
+ {
+ 11, -16, -16, -16, -16, -16, -16, -16, -16, -16,
+ -16, -16, -16, -16, -16, -16, -16
+ },
+
+ {
+ 11, -17, -17, -17, -17, -17, -17, -17, -17, -17,
+ -17, -17, -17, -17, -17, -17, -17
+ },
+
+ {
+ 11, -18, -18, -18, -18, -18, -18, -18, -18, -18,
+ -18, -18, -18, 44, -18, -18, -18
+ },
+
+ {
+ 11, 45, 45, -19, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45
+
+ },
+
+ {
+ 11, -20, 46, 47, -20, -20, -20, -20, -20, -20,
+ -20, -20, -20, -20, -20, -20, -20
+ },
+
+ {
+ 11, 48, -21, -21, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48
+ },
+
+ {
+ 11, 49, 49, 50, 49, -22, 49, 49, -22, 49,
+ 49, 49, 49, 49, 49, -22, 49
+ },
+
+ {
+ 11, -23, -23, -23, -23, -23, -23, -23, -23, -23,
+ -23, -23, -23, -23, -23, -23, -23
+ },
+
+ {
+ 11, -24, -24, -24, -24, -24, -24, -24, -24, -24,
+ -24, -24, -24, -24, -24, -24, -24
+
+ },
+
+ {
+ 11, 51, 51, 52, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51
+ },
+
+ {
+ 11, -26, -26, -26, -26, -26, -26, -26, -26, -26,
+ -26, -26, -26, -26, -26, -26, -26
+ },
+
+ {
+ 11, -27, -27, -27, -27, -27, -27, -27, -27, -27,
+ -27, -27, -27, -27, -27, -27, -27
+ },
+
+ {
+ 11, -28, -28, -28, -28, -28, -28, -28, -28, -28,
+ -28, -28, -28, -28, 53, -28, -28
+ },
+
+ {
+ 11, -29, -29, -29, -29, -29, -29, -29, -29, -29,
+ -29, -29, -29, -29, -29, -29, -29
+
+ },
+
+ {
+ 11, 54, 54, -30, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54
+ },
+
+ {
+ 11, -31, -31, -31, -31, -31, -31, 55, -31, -31,
+ -31, -31, -31, -31, -31, -31, -31
+ },
+
+ {
+ 11, -32, -32, -32, -32, -32, -32, -32, -32, -32,
+ -32, -32, -32, -32, -32, -32, -32
+ },
+
+ {
+ 11, -33, -33, -33, -33, -33, -33, -33, -33, -33,
+ -33, -33, -33, -33, -33, -33, -33
+ },
+
+ {
+ 11, -34, -34, -34, -34, -34, -34, -34, -34, -34,
+ -34, 56, 57, 57, -34, -34, -34
+
+ },
+
+ {
+ 11, -35, -35, -35, -35, -35, -35, -35, -35, -35,
+ -35, 57, 57, 57, -35, -35, -35
+ },
+
+ {
+ 11, -36, -36, -36, -36, -36, -36, -36, -36, -36,
+ -36, -36, -36, -36, -36, -36, -36
+ },
+
+ {
+ 11, -37, -37, 58, -37, -37, -37, -37, -37, -37,
+ -37, -37, -37, -37, -37, -37, -37
+ },
+
+ {
+ 11, -38, -38, -38, -38, -38, -38, -38, -38, -38,
+ -38, -38, -38, -38, -38, -38, 59
+ },
+
+ {
+ 11, -39, 39, 40, -39, -39, 41, -39, -39, -39,
+ -39, -39, -39, -39, -39, -39, -39
+
+ },
+
+ {
+ 11, -40, -40, -40, -40, -40, -40, -40, -40, -40,
+ -40, -40, -40, -40, -40, -40, -40
+ },
+
+ {
+ 11, 42, 42, 43, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42
+ },
+
+ {
+ 11, 42, 42, 43, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42
+ },
+
+ {
+ 11, -43, -43, -43, -43, -43, -43, -43, -43, -43,
+ -43, -43, -43, -43, -43, -43, -43
+ },
+
+ {
+ 11, -44, -44, -44, -44, -44, -44, -44, -44, -44,
+ -44, -44, -44, 44, -44, -44, -44
+
+ },
+
+ {
+ 11, 45, 45, -45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45
+ },
+
+ {
+ 11, -46, 46, 47, -46, -46, -46, -46, -46, -46,
+ -46, -46, -46, -46, -46, -46, -46
+ },
+
+ {
+ 11, 48, -47, -47, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48
+ },
+
+ {
+ 11, -48, -48, -48, -48, -48, -48, -48, -48, -48,
+ -48, -48, -48, -48, -48, -48, -48
+ },
+
+ {
+ 11, 49, 49, 50, 49, -49, 49, 49, -49, 49,
+ 49, 49, 49, 49, 49, -49, 49
+
+ },
+
+ {
+ 11, -50, -50, -50, -50, -50, -50, -50, -50, -50,
+ -50, -50, -50, -50, -50, -50, -50
+ },
+
+ {
+ 11, -51, -51, 52, -51, -51, -51, -51, -51, -51,
+ -51, -51, -51, -51, -51, -51, -51
+ },
+
+ {
+ 11, -52, -52, -52, -52, -52, -52, -52, -52, -52,
+ -52, -52, -52, -52, -52, -52, -52
+ },
+
+ {
+ 11, -53, -53, -53, -53, -53, -53, -53, -53, -53,
+ -53, -53, -53, -53, -53, -53, -53
+ },
+
+ {
+ 11, 54, 54, -54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54
+
+ },
+
+ {
+ 11, -55, -55, -55, -55, -55, -55, -55, -55, -55,
+ -55, -55, -55, -55, -55, -55, -55
+ },
+
+ {
+ 11, -56, -56, -56, -56, -56, -56, -56, -56, -56,
+ -56, 60, 57, 57, -56, -56, -56
+ },
+
+ {
+ 11, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, 57, 57, 57, -57, -57, -57
+ },
+
+ {
+ 11, -58, -58, -58, -58, -58, -58, -58, -58, -58,
+ -58, -58, -58, -58, -58, -58, -58
+ },
+
+ {
+ 11, -59, -59, -59, -59, -59, -59, -59, -59, -59,
+ -59, -59, -59, -59, -59, -59, -59
+
+ },
+
+ {
+ 11, -60, -60, -60, -60, -60, -60, -60, -60, -60,
+ -60, 57, 57, 57, -60, -60, -60
+ },
+
+ } ;
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up zconftext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ zconfleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 33
+#define YY_END_OF_BUFFER 34
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[61] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 34, 5, 4, 2, 3, 7, 8, 6, 32, 29,
+ 31, 24, 28, 27, 26, 22, 17, 13, 16, 20,
+ 22, 11, 12, 19, 19, 14, 22, 22, 4, 2,
+ 3, 3, 1, 6, 32, 29, 31, 30, 24, 23,
+ 26, 25, 15, 20, 9, 19, 19, 21, 10, 18
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 5, 6, 1, 1, 7, 8, 9,
+ 10, 1, 1, 1, 11, 12, 12, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 1, 1, 1,
+ 14, 1, 1, 1, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 1, 15, 1, 1, 13, 1, 13, 13, 13, 13,
+
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 1, 16, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+extern int zconf_flex_debug;
+int zconf_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *zconftext;
+#define YY_NO_INPUT 1
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE 16
+
+static struct {
+ struct file *file;
+ int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+ text = malloc(START_STRSIZE);
+ text_asize = START_STRSIZE;
+ text_size = 0;
+ *text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+ int new_size = text_size + size + 1;
+ if (new_size > text_asize) {
+ new_size += START_STRSIZE - 1;
+ new_size &= -START_STRSIZE;
+ text = realloc(text, new_size);
+ text_asize = new_size;
+ }
+ memcpy(text + text_size, str, size);
+ text_size += size;
+ text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+ text = malloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+
+#define INITIAL 0
+#define COMMAND 1
+#define HELP 2
+#define STRING 3
+#define PARAM 4
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int zconflex_destroy (void );
+
+int zconfget_debug (void );
+
+void zconfset_debug (int debug_flag );
+
+YY_EXTRA_TYPE zconfget_extra (void );
+
+void zconfset_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *zconfget_in (void );
+
+void zconfset_in (FILE * in_str );
+
+FILE *zconfget_out (void );
+
+void zconfset_out (FILE * out_str );
+
+int zconfget_leng (void );
+
+char *zconfget_text (void );
+
+int zconfget_lineno (void );
+
+void zconfset_lineno (int line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int zconfwrap (void );
+#else
+extern int zconfwrap (void );
+#endif
+#endif
+
+ static void yyunput (int c,char *buf_ptr );
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( zconftext, zconfleng, 1, zconfout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ errno=0; \
+ while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(zconfin); \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int zconflex (void);
+
+#define YY_DECL int zconflex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after zconftext and zconfleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+ int str = 0;
+ int ts, i;
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! zconfin )
+ zconfin = stdin;
+
+ if ( ! zconfout )
+ zconfout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ zconfensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ zconf_create_buffer(zconfin,YY_BUF_SIZE );
+ }
+
+ zconf_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of zconftext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 )
+ ++yy_cp;
+
+ yy_current_state = -yy_current_state;
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+case 1:
+/* rule 1 can match eol */
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+{
+ current_file->lineno++;
+ return T_EOL;
+}
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+ BEGIN(COMMAND);
+}
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{
+ unput(zconftext[0]);
+ BEGIN(COMMAND);
+}
+ YY_BREAK
+
+case 6:
+YY_RULE_SETUP
+{
+ struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+ BEGIN(PARAM);
+ current_pos.file = current_file;
+ current_pos.lineno = current_file->lineno;
+ if (id && id->flags & TF_COMMAND) {
+ zconflval.id = id;
+ return id->token;
+ }
+ alloc_string(zconftext, zconfleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+
+ YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+{
+ BEGIN(INITIAL);
+ current_file->lineno++;
+ return T_EOL;
+ }
+ YY_BREAK
+
+case 9:
+YY_RULE_SETUP
+return T_AND;
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+return T_OR;
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+return T_OPEN_PAREN;
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+return T_CLOSE_PAREN;
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+return T_NOT;
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+return T_EQUAL;
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+return T_UNEQUAL;
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{
+ str = zconftext[0];
+ new_string();
+ BEGIN(STRING);
+ }
+ YY_BREAK
+case 17:
+/* rule 17 can match eol */
+YY_RULE_SETUP
+BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+/* ignore */
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+{
+ struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+ if (id && id->flags & TF_PARAM) {
+ zconflval.id = id;
+ return id->token;
+ }
+ alloc_string(zconftext, zconfleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+/* comment */
+ YY_BREAK
+case 21:
+/* rule 21 can match eol */
+YY_RULE_SETUP
+current_file->lineno++;
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+
+ YY_BREAK
+case YY_STATE_EOF(PARAM):
+{
+ BEGIN(INITIAL);
+ }
+ YY_BREAK
+
+case 23:
+/* rule 23 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+ append_string(zconftext, zconfleng);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+{
+ append_string(zconftext, zconfleng);
+ }
+ YY_BREAK
+case 25:
+/* rule 25 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+ append_string(zconftext + 1, zconfleng - 1);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+{
+ append_string(zconftext + 1, zconfleng - 1);
+ }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+{
+ if (str == zconftext[0]) {
+ BEGIN(PARAM);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(zconftext, 1);
+ }
+ YY_BREAK
+case 28:
+/* rule 28 can match eol */
+YY_RULE_SETUP
+{
+ printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+ current_file->lineno++;
+ BEGIN(INITIAL);
+ return T_EOL;
+ }
+ YY_BREAK
+case YY_STATE_EOF(STRING):
+{
+ BEGIN(INITIAL);
+ }
+ YY_BREAK
+
+case 29:
+YY_RULE_SETUP
+{
+ ts = 0;
+ for (i = 0; i < zconfleng; i++) {
+ if (zconftext[i] == '\t')
+ ts = (ts & ~7) + 8;
+ else
+ ts++;
+ }
+ last_ts = ts;
+ if (first_ts) {
+ if (ts < first_ts) {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ ts -= first_ts;
+ while (ts > 8) {
+ append_string(" ", 8);
+ ts -= 8;
+ }
+ append_string(" ", ts);
+ }
+ }
+ YY_BREAK
+case 30:
+/* rule 30 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+ current_file->lineno++;
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ YY_BREAK
+case 31:
+/* rule 31 can match eol */
+YY_RULE_SETUP
+{
+ current_file->lineno++;
+ append_string("\n", 1);
+ }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+{
+ while (zconfleng) {
+ if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t'))
+ break;
+ zconfleng--;
+ }
+ append_string(zconftext, zconfleng);
+ if (!first_ts)
+ first_ts = last_ts;
+ }
+ YY_BREAK
+case YY_STATE_EOF(HELP):
+{
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ YY_BREAK
+
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMAND):
+{
+ if (current_file) {
+ zconf_endfile();
+ return T_EOL;
+ }
+ fclose(zconfin);
+ yyterminate();
+}
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed zconfin at a new source and called
+ * zconflex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( zconfwrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * zconftext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of zconflex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), (size_t) num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ zconfrestart(zconfin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) zconfrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+
+ yy_current_state = yy_nxt[yy_current_state][1];
+ yy_is_jam = (yy_current_state <= 0);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ static void yyunput (int c, register char * yy_bp )
+{
+ register char *yy_cp;
+
+ yy_cp = (yy_c_buf_p);
+
+ /* undo effects of setting up zconftext */
+ *yy_cp = (yy_hold_char);
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = (yy_n_chars) + 2;
+ register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ (yytext_ptr) = yy_bp;
+ (yy_hold_char) = *yy_cp;
+ (yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ int offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ zconfrestart(zconfin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( zconfwrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve zconftext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void zconfrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ zconfensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ zconf_create_buffer(zconfin,YY_BUF_SIZE );
+ }
+
+ zconf_init_buffer(YY_CURRENT_BUFFER,input_file );
+ zconf_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * zconfpop_buffer_state();
+ * zconfpush_buffer_state(new_buffer);
+ */
+ zconfensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ zconf_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (zconfwrap()) processing, but the only time this flag
+ * is looked at is after zconfwrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void zconf_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE zconf_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ zconf_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with zconf_create_buffer()
+ *
+ */
+ void zconf_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ zconffree((void *) b->yy_ch_buf );
+
+ zconffree((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a zconfrestart() or at EOF.
+ */
+ static void zconf_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ zconf_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then zconf_init_buffer was _probably_
+ * called from zconfrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void zconf_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ zconf_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ zconfensure_buffer_stack();
+
+ /* This block is copied from zconf_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from zconf_switch_to_buffer. */
+ zconf_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void zconfpop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ zconf_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ zconf_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void zconfensure_buffer_stack (void)
+{
+ int num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ zconf_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to zconflex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * zconf_scan_bytes() instead.
+ */
+YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr )
+{
+
+ return zconf_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char * yybytes, int _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) zconfalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = zconf_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up zconftext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ zconftext[zconfleng] = (yy_hold_char); \
+ (yy_c_buf_p) = zconftext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ zconfleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int zconfget_lineno (void)
+{
+
+ return zconflineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *zconfget_in (void)
+{
+ return zconfin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *zconfget_out (void)
+{
+ return zconfout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int zconfget_leng (void)
+{
+ return zconfleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *zconfget_text (void)
+{
+ return zconftext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void zconfset_lineno (int line_number )
+{
+
+ zconflineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see zconf_switch_to_buffer
+ */
+void zconfset_in (FILE * in_str )
+{
+ zconfin = in_str ;
+}
+
+void zconfset_out (FILE * out_str )
+{
+ zconfout = out_str ;
+}
+
+int zconfget_debug (void)
+{
+ return zconf_flex_debug;
+}
+
+void zconfset_debug (int bdebug )
+{
+ zconf_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from zconflex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ zconfin = stdin;
+ zconfout = stdout;
+#else
+ zconfin = (FILE *) 0;
+ zconfout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * zconflex_init()
+ */
+ return 0;
+}
+
+/* zconflex_destroy is for both reentrant and non-reentrant scanners. */
+int zconflex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ zconf_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ zconfpop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ zconffree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * zconflex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *zconfalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *zconfrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void zconffree (void * ptr )
+{
+ free( (char *) ptr ); /* see zconfrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+void zconf_starthelp(void)
+{
+ new_string();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ zconflval.string = text;
+ BEGIN(INITIAL);
+}
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+ char *env, fullname[PATH_MAX+1];
+ FILE *f;
+
+ f = fopen(name, "r");
+ if (!f && name != NULL && name[0] != '/') {
+ env = getenv(SRCTREE);
+ if (env) {
+ sprintf(fullname, "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ zconfin = zconf_fopen(name);
+ if (!zconfin) {
+ printf("can't find file %s\n", name);
+ exit(1);
+ }
+
+ current_buf = malloc(sizeof(*current_buf));
+ memset(current_buf, 0, sizeof(*current_buf));
+
+ current_file = file_lookup(name);
+ current_file->lineno = 1;
+ current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct file *file = file_lookup(name);
+ struct buffer *buf = malloc(sizeof(*buf));
+ memset(buf, 0, sizeof(*buf));
+
+ current_buf->state = YY_CURRENT_BUFFER;
+ zconfin = zconf_fopen(file->name);
+ if (!zconfin) {
+ printf("%s:%d: can't open file \"%s\"\n",
+ zconf_curname(), zconf_lineno(), file->name);
+ exit(1);
+ }
+ zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
+ buf->parent = current_buf;
+ current_buf = buf;
+
+ if (file->flags & FILE_BUSY) {
+ printf("%s:%d: do not source '%s' from itself\n",
+ zconf_curname(), zconf_lineno(), name);
+ exit(1);
+ }
+ if (file->flags & FILE_SCANNED) {
+ printf("%s:%d: file '%s' is already sourced from '%s'\n",
+ zconf_curname(), zconf_lineno(), name,
+ file->parent->name);
+ exit(1);
+ }
+ file->flags |= FILE_BUSY;
+ file->lineno = 1;
+ file->parent = current_file;
+ current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+ struct buffer *parent;
+
+ current_file->flags |= FILE_SCANNED;
+ current_file->flags &= ~FILE_BUSY;
+ current_file = current_file->parent;
+
+ parent = current_buf->parent;
+ if (parent) {
+ fclose(zconfin);
+ zconf_delete_buffer(YY_CURRENT_BUFFER);
+ zconf_switch_to_buffer(parent->state);
+ }
+ free(current_buf);
+ current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+ return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+ return current_pos.file ? current_pos.file->name : "<none>";
+}
+
diff --git a/roms/seabios/scripts/kconfig/list.h b/roms/seabios/scripts/kconfig/list.h
new file mode 100644
index 00000000..685d80e1
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/list.h
@@ -0,0 +1,131 @@
+#ifndef LIST_H
+#define LIST_H
+
+/*
+ * Copied from include/linux/...
+ */
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *_new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = _new;
+ _new->next = next;
+ _new->prev = prev;
+ prev->next = _new;
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *_new, struct list_head *head)
+{
+ __list_add(_new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = (struct list_head*)LIST_POISON1;
+ entry->prev = (struct list_head*)LIST_POISON2;
+}
+#endif
diff --git a/roms/seabios/scripts/kconfig/lkc.h b/roms/seabios/scripts/kconfig/lkc.h
new file mode 100644
index 00000000..d5daa7af
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/lkc.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef LKC_H
+#define LKC_H
+
+#include "expr.h"
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+static inline const char *gettext(const char *txt) { return txt; }
+static inline void textdomain(const char *domainname) {}
+static inline void bindtextdomain(const char *name, const char *dir) {}
+static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; }
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define P(name,type,arg) extern type name arg
+#include "lkc_proto.h"
+#undef P
+
+#define SRCTREE "srctree"
+
+#ifndef PACKAGE
+#define PACKAGE "linux"
+#endif
+
+#define LOCALEDIR "/usr/share/locale"
+
+#define _(text) gettext(text)
+#define N_(text) (text)
+
+#ifndef CONFIG_
+#define CONFIG_ "CONFIG_"
+#endif
+static inline const char *CONFIG_prefix(void)
+{
+ return getenv( "CONFIG_" ) ?: CONFIG_;
+}
+#undef CONFIG_
+#define CONFIG_ CONFIG_prefix()
+
+#define TF_COMMAND 0x0001
+#define TF_PARAM 0x0002
+#define TF_OPTION 0x0004
+
+enum conf_def_mode {
+ def_default,
+ def_yes,
+ def_mod,
+ def_no,
+ def_random
+};
+
+#define T_OPT_MODULES 1
+#define T_OPT_DEFCONFIG_LIST 2
+#define T_OPT_ENV 3
+#define T_OPT_ALLNOCONFIG_Y 4
+
+struct kconf_id {
+ int name;
+ int token;
+ unsigned int flags;
+ enum symbol_type stype;
+};
+
+extern int zconfdebug;
+
+int zconfparse(void);
+void zconfdump(FILE *out);
+void zconf_starthelp(void);
+FILE *zconf_fopen(const char *name);
+void zconf_initscan(const char *name);
+void zconf_nextfile(const char *name);
+int zconf_lineno(void);
+const char *zconf_curname(void);
+
+/* confdata.c */
+const char *conf_get_configname(void);
+const char *conf_get_autoconfig_name(void);
+char *conf_get_default_confname(void);
+void sym_set_change_count(int count);
+void sym_add_change_count(int count);
+bool conf_set_all_new_symbols(enum conf_def_mode mode);
+void set_all_choice_values(struct symbol *csym);
+
+struct conf_printer {
+ void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
+ void (*print_comment)(FILE *, const char *, void *);
+};
+
+/* confdata.c and expr.c */
+static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
+{
+ assert(len != 0);
+
+ if (fwrite(str, len, count, out) != count)
+ fprintf(stderr, "Error in writing or end of file.\n");
+}
+
+/* menu.c */
+void _menu_init(void);
+void menu_warn(struct menu *menu, const char *fmt, ...);
+struct menu *menu_add_menu(void);
+void menu_end_menu(void);
+void menu_add_entry(struct symbol *sym);
+void menu_end_entry(void);
+void menu_add_dep(struct expr *dep);
+void menu_add_visibility(struct expr *dep);
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_add_option(int token, char *arg);
+void menu_finalize(struct menu *parent);
+void menu_set_type(int type);
+
+/* util.c */
+struct file *file_lookup(const char *name);
+int file_write_dep(const char *name);
+void *xmalloc(size_t size);
+void *xcalloc(size_t nmemb, size_t size);
+
+struct gstr {
+ size_t len;
+ char *s;
+ /*
+ * when max_width is not zero long lines in string s (if any) get
+ * wrapped not to exceed the max_width value
+ */
+ int max_width;
+};
+struct gstr str_new(void);
+struct gstr str_assign(const char *s);
+void str_free(struct gstr *gs);
+void str_append(struct gstr *gs, const char *s);
+void str_printf(struct gstr *gs, const char *fmt, ...);
+const char *str_get(struct gstr *gs);
+
+/* symbol.c */
+extern struct expr *sym_env_list;
+
+void sym_init(void);
+void sym_clear_all_valid(void);
+void sym_set_all_changed(void);
+void sym_set_changed(struct symbol *sym);
+struct symbol *sym_choice_default(struct symbol *sym);
+const char *sym_get_string_default(struct symbol *sym);
+struct symbol *sym_check_deps(struct symbol *sym);
+struct property *prop_alloc(enum prop_type type, struct symbol *sym);
+struct symbol *prop_get_symbol(struct property *prop);
+struct property *sym_get_env_prop(struct symbol *sym);
+
+static inline tristate sym_get_tristate_value(struct symbol *sym)
+{
+ return sym->curr.tri;
+}
+
+
+static inline struct symbol *sym_get_choice_value(struct symbol *sym)
+{
+ return (struct symbol *)sym->curr.val;
+}
+
+static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
+{
+ return sym_set_tristate_value(chval, yes);
+}
+
+static inline bool sym_is_choice(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_CHOICE ? true : false;
+}
+
+static inline bool sym_is_choice_value(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_CHOICEVAL ? true : false;
+}
+
+static inline bool sym_is_optional(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_OPTIONAL ? true : false;
+}
+
+static inline bool sym_has_value(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_DEF_USER ? true : false;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LKC_H */
diff --git a/roms/seabios/scripts/kconfig/lkc_proto.h b/roms/seabios/scripts/kconfig/lkc_proto.h
new file mode 100644
index 00000000..ecdb9659
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/lkc_proto.h
@@ -0,0 +1,57 @@
+#include <stdarg.h>
+
+/* confdata.c */
+P(conf_parse,void,(const char *name));
+P(conf_read,int,(const char *name));
+P(conf_read_simple,int,(const char *name, int));
+P(conf_write_defconfig,int,(const char *name));
+P(conf_write,int,(const char *name));
+P(conf_write_autoconf,int,(void));
+P(conf_get_changed,bool,(void));
+P(conf_set_changed_callback, void,(void (*fn)(void)));
+P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap)));
+
+/* menu.c */
+P(rootmenu,struct menu,);
+
+P(menu_is_empty, bool, (struct menu *menu));
+P(menu_is_visible, bool, (struct menu *menu));
+P(menu_has_prompt, bool, (struct menu *menu));
+P(menu_get_prompt,const char *,(struct menu *menu));
+P(menu_get_root_menu,struct menu *,(struct menu *menu));
+P(menu_get_parent_menu,struct menu *,(struct menu *menu));
+P(menu_has_help,bool,(struct menu *menu));
+P(menu_get_help,const char *,(struct menu *menu));
+P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct list_head
+ *head));
+P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct list_head
+ *head));
+P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
+
+/* symbol.c */
+P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
+
+P(sym_lookup,struct symbol *,(const char *name, int flags));
+P(sym_find,struct symbol *,(const char *name));
+P(sym_expand_string_value,const char *,(const char *in));
+P(sym_escape_string_value, const char *,(const char *in));
+P(sym_re_search,struct symbol **,(const char *pattern));
+P(sym_type_name,const char *,(enum symbol_type type));
+P(sym_calc_value,void,(struct symbol *sym));
+P(sym_get_type,enum symbol_type,(struct symbol *sym));
+P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
+P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
+P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
+P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
+P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
+P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
+P(sym_is_changable,bool,(struct symbol *sym));
+P(sym_get_choice_prop,struct property *,(struct symbol *sym));
+P(sym_get_default_prop,struct property *,(struct symbol *sym));
+P(sym_get_string_value,const char *,(struct symbol *sym));
+
+P(prop_get_type_name,const char *,(enum prop_type type));
+
+/* expr.c */
+P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2));
+P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken));
diff --git a/roms/seabios/scripts/kconfig/lxdialog/.gitignore b/roms/seabios/scripts/kconfig/lxdialog/.gitignore
new file mode 100644
index 00000000..90b08ff0
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/lxdialog/.gitignore
@@ -0,0 +1,4 @@
+#
+# Generated files
+#
+lxdialog
diff --git a/roms/seabios/scripts/kconfig/lxdialog/BIG.FAT.WARNING b/roms/seabios/scripts/kconfig/lxdialog/BIG.FAT.WARNING
new file mode 100644
index 00000000..a8999d82
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/lxdialog/BIG.FAT.WARNING
@@ -0,0 +1,4 @@
+This is NOT the official version of dialog. This version has been
+significantly modified from the original. It is for use by the Linux
+kernel configuration script. Please do not bother Savio Lam with
+questions about this program.
diff --git a/roms/seabios/scripts/kconfig/lxdialog/check-lxdialog.sh b/roms/seabios/scripts/kconfig/lxdialog/check-lxdialog.sh
new file mode 100644
index 00000000..9d2a4c58
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/lxdialog/check-lxdialog.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+# Check ncurses compatibility
+
+# What library to link
+ldflags()
+{
+ pkg-config --libs ncursesw 2>/dev/null && exit
+ pkg-config --libs ncurses 2>/dev/null && exit
+ for ext in so a dll.a dylib ; do
+ for lib in ncursesw ncurses curses ; do
+ $cc -print-file-name=lib${lib}.${ext} | grep -q /
+ if [ $? -eq 0 ]; then
+ echo "-l${lib}"
+ exit
+ fi
+ done
+ done
+ exit 1
+}
+
+# Where is ncurses.h?
+ccflags()
+{
+ if [ -f /usr/include/ncursesw/curses.h ]; then
+ echo '-I/usr/include/ncursesw -DCURSES_LOC="<curses.h>"'
+ echo ' -DNCURSES_WIDECHAR=1'
+ elif [ -f /usr/include/ncurses/ncurses.h ]; then
+ echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
+ elif [ -f /usr/include/ncurses/curses.h ]; then
+ echo '-I/usr/include/ncurses -DCURSES_LOC="<curses.h>"'
+ elif [ -f /usr/include/ncurses.h ]; then
+ echo '-DCURSES_LOC="<ncurses.h>"'
+ else
+ echo '-DCURSES_LOC="<curses.h>"'
+ fi
+}
+
+# Temp file, try to clean up after us
+tmp=.lxdialog.tmp
+trap "rm -f $tmp" 0 1 2 3 15
+
+# Check if we can link to ncurses
+check() {
+ $cc -x c - -o $tmp 2>/dev/null <<'EOF'
+#include CURSES_LOC
+main() {}
+EOF
+ if [ $? != 0 ]; then
+ echo " *** Unable to find the ncurses libraries or the" 1>&2
+ echo " *** required header files." 1>&2
+ echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2
+ echo " *** " 1>&2
+ echo " *** Install ncurses (ncurses-devel) and try again." 1>&2
+ echo " *** " 1>&2
+ exit 1
+ fi
+}
+
+usage() {
+ printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n"
+}
+
+if [ $# -eq 0 ]; then
+ usage
+ exit 1
+fi
+
+cc=""
+case "$1" in
+ "-check")
+ shift
+ cc="$@"
+ check
+ ;;
+ "-ccflags")
+ ccflags
+ ;;
+ "-ldflags")
+ shift
+ cc="$@"
+ ldflags
+ ;;
+ "*")
+ usage
+ exit 1
+ ;;
+esac
diff --git a/roms/seabios/scripts/kconfig/lxdialog/checklist.c b/roms/seabios/scripts/kconfig/lxdialog/checklist.c
new file mode 100644
index 00000000..8d016faa
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/lxdialog/checklist.c
@@ -0,0 +1,332 @@
+/*
+ * checklist.c -- implements the checklist box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
+ * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static int list_width, check_x, item_x;
+
+/*
+ * Print list item
+ */
+static void print_item(WINDOW * win, int choice, int selected)
+{
+ int i;
+ char *list_item = malloc(list_width + 1);
+
+ strncpy(list_item, item_str(), list_width - item_x);
+ list_item[list_width - item_x] = '\0';
+
+ /* Clear 'residue' of last item */
+ wattrset(win, dlg.menubox.atr);
+ wmove(win, choice, 0);
+ for (i = 0; i < list_width; i++)
+ waddch(win, ' ');
+
+ wmove(win, choice, check_x);
+ wattrset(win, selected ? dlg.check_selected.atr
+ : dlg.check.atr);
+ if (!item_is_tag(':'))
+ wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
+
+ wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
+ mvwaddch(win, choice, item_x, list_item[0]);
+ wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+ waddstr(win, list_item + 1);
+ if (selected) {
+ wmove(win, choice, check_x + 1);
+ wrefresh(win);
+ }
+ free(list_item);
+}
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
+ int y, int x, int height)
+{
+ wmove(win, y, x);
+
+ if (scroll > 0) {
+ wattrset(win, dlg.uarrow.atr);
+ waddch(win, ACS_UARROW);
+ waddstr(win, "(-)");
+ } else {
+ wattrset(win, dlg.menubox.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ }
+
+ y = y + height + 1;
+ wmove(win, y, x);
+
+ if ((height < item_no) && (scroll + choice < item_no - 1)) {
+ wattrset(win, dlg.darrow.atr);
+ waddch(win, ACS_DARROW);
+ waddstr(win, "(+)");
+ } else {
+ wattrset(win, dlg.menubox_border.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ }
+}
+
+/*
+ * Display the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+ int x = width / 2 - 11;
+ int y = height - 2;
+
+ print_button(dialog, gettext("Select"), y, x, selected == 0);
+ print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+
+ wmove(dialog, y, x + 1 + 14 * selected);
+ wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ * in the style of radiolist (only one option turned on at a time).
+ */
+int dialog_checklist(const char *title, const char *prompt, int height,
+ int width, int list_height)
+{
+ int i, x, y, box_x, box_y;
+ int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
+ WINDOW *dialog, *list;
+
+ /* which item to highlight */
+ item_foreach() {
+ if (item_is_tag('X'))
+ choice = item_n();
+ if (item_is_selected()) {
+ choice = item_n();
+ break;
+ }
+ }
+
+do_resize:
+ if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN))
+ return -ERRDISPLAYTOOSMALL;
+
+ max_choice = MIN(list_height, item_count());
+
+ /* center dialog box on screen */
+ x = (getmaxx(stdscr) - width) / 2;
+ y = (getmaxy(stdscr) - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ list_width = width - 6;
+ box_y = height - list_height - 5;
+ box_x = (width - list_width) / 2 - 1;
+
+ /* create new window for the list */
+ list = subwin(dialog, list_height, list_width, y + box_y + 1,
+ x + box_x + 1);
+
+ keypad(list, TRUE);
+
+ /* draw a box around the list items */
+ draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
+ dlg.menubox_border.atr, dlg.menubox.atr);
+
+ /* Find length of longest item in order to center checklist */
+ check_x = 0;
+ item_foreach()
+ check_x = MAX(check_x, strlen(item_str()) + 4);
+ check_x = MIN(check_x, list_width);
+
+ check_x = (list_width - check_x) / 2;
+ item_x = check_x + 4;
+
+ if (choice >= list_height) {
+ scroll = choice - list_height + 1;
+ choice -= scroll;
+ }
+
+ /* Print the list */
+ for (i = 0; i < max_choice; i++) {
+ item_set(scroll + i);
+ print_item(list, i, i == choice);
+ }
+
+ print_arrows(dialog, choice, item_count(), scroll,
+ box_y, box_x + check_x + 5, list_height);
+
+ print_buttons(dialog, height, width, 0);
+
+ wnoutrefresh(dialog);
+ wnoutrefresh(list);
+ doupdate();
+
+ while (key != KEY_ESC) {
+ key = wgetch(dialog);
+
+ for (i = 0; i < max_choice; i++) {
+ item_set(i + scroll);
+ if (toupper(key) == toupper(item_str()[0]))
+ break;
+ }
+
+ if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+ key == '+' || key == '-') {
+ if (key == KEY_UP || key == '-') {
+ if (!choice) {
+ if (!scroll)
+ continue;
+ /* Scroll list down */
+ if (list_height > 1) {
+ /* De-highlight current first item */
+ item_set(scroll);
+ print_item(list, 0, FALSE);
+ scrollok(list, TRUE);
+ wscrl(list, -1);
+ scrollok(list, FALSE);
+ }
+ scroll--;
+ item_set(scroll);
+ print_item(list, 0, TRUE);
+ print_arrows(dialog, choice, item_count(),
+ scroll, box_y, box_x + check_x + 5, list_height);
+
+ wnoutrefresh(dialog);
+ wrefresh(list);
+
+ continue; /* wait for another key press */
+ } else
+ i = choice - 1;
+ } else if (key == KEY_DOWN || key == '+') {
+ if (choice == max_choice - 1) {
+ if (scroll + choice >= item_count() - 1)
+ continue;
+ /* Scroll list up */
+ if (list_height > 1) {
+ /* De-highlight current last item before scrolling up */
+ item_set(scroll + max_choice - 1);
+ print_item(list,
+ max_choice - 1,
+ FALSE);
+ scrollok(list, TRUE);
+ wscrl(list, 1);
+ scrollok(list, FALSE);
+ }
+ scroll++;
+ item_set(scroll + max_choice - 1);
+ print_item(list, max_choice - 1, TRUE);
+
+ print_arrows(dialog, choice, item_count(),
+ scroll, box_y, box_x + check_x + 5, list_height);
+
+ wnoutrefresh(dialog);
+ wrefresh(list);
+
+ continue; /* wait for another key press */
+ } else
+ i = choice + 1;
+ }
+ if (i != choice) {
+ /* De-highlight current item */
+ item_set(scroll + choice);
+ print_item(list, choice, FALSE);
+ /* Highlight new item */
+ choice = i;
+ item_set(scroll + choice);
+ print_item(list, choice, TRUE);
+ wnoutrefresh(dialog);
+ wrefresh(list);
+ }
+ continue; /* wait for another key press */
+ }
+ switch (key) {
+ case 'H':
+ case 'h':
+ case '?':
+ button = 1;
+ /* fall-through */
+ case 'S':
+ case 's':
+ case ' ':
+ case '\n':
+ item_foreach()
+ item_set_selected(0);
+ item_set(scroll + choice);
+ item_set_selected(1);
+ delwin(list);
+ delwin(dialog);
+ return button;
+ case TAB:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ button = ((key == KEY_LEFT ? --button : ++button) < 0)
+ ? 1 : (button > 1 ? 0 : button);
+
+ print_buttons(dialog, height, width, button);
+ wrefresh(dialog);
+ break;
+ case 'X':
+ case 'x':
+ key = KEY_ESC;
+ break;
+ case KEY_ESC:
+ key = on_key_esc(dialog);
+ break;
+ case KEY_RESIZE:
+ delwin(list);
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
+ }
+
+ /* Now, update everything... */
+ doupdate();
+ }
+ delwin(list);
+ delwin(dialog);
+ return key; /* ESC pressed */
+}
diff --git a/roms/seabios/scripts/kconfig/lxdialog/dialog.h b/roms/seabios/scripts/kconfig/lxdialog/dialog.h
new file mode 100644
index 00000000..b4343d38
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/lxdialog/dialog.h
@@ -0,0 +1,257 @@
+/*
+ * dialog.h -- common declarations for all dialog modules
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+# define gettext(Msgid) ((const char *) (Msgid))
+#endif
+
+#ifdef __sun__
+#define CURS_MACROS
+#endif
+#include CURSES_LOC
+
+/*
+ * Colors in ncurses 1.9.9e do not work properly since foreground and
+ * background colors are OR'd rather than separately masked. This version
+ * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
+ * with standard curses. The simplest fix (to make this work with standard
+ * curses) uses the wbkgdset() function, not used in the original hack.
+ * Turn it off if we're building with 1.9.9e, since it just confuses things.
+ */
+#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
+#define OLD_NCURSES 1
+#undef wbkgdset
+#define wbkgdset(w,p) /*nothing */
+#else
+#define OLD_NCURSES 0
+#endif
+
+#define TR(params) _tracef params
+
+#define KEY_ESC 27
+#define TAB 9
+#define MAX_LEN 2048
+#define BUF_SIZE (10*1024)
+#define MIN(x,y) (x < y ? x : y)
+#define MAX(x,y) (x > y ? x : y)
+
+#ifndef ACS_ULCORNER
+#define ACS_ULCORNER '+'
+#endif
+#ifndef ACS_LLCORNER
+#define ACS_LLCORNER '+'
+#endif
+#ifndef ACS_URCORNER
+#define ACS_URCORNER '+'
+#endif
+#ifndef ACS_LRCORNER
+#define ACS_LRCORNER '+'
+#endif
+#ifndef ACS_HLINE
+#define ACS_HLINE '-'
+#endif
+#ifndef ACS_VLINE
+#define ACS_VLINE '|'
+#endif
+#ifndef ACS_LTEE
+#define ACS_LTEE '+'
+#endif
+#ifndef ACS_RTEE
+#define ACS_RTEE '+'
+#endif
+#ifndef ACS_UARROW
+#define ACS_UARROW '^'
+#endif
+#ifndef ACS_DARROW
+#define ACS_DARROW 'v'
+#endif
+
+/* error return codes */
+#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
+
+/*
+ * Color definitions
+ */
+struct dialog_color {
+ chtype atr; /* Color attribute */
+ int fg; /* foreground */
+ int bg; /* background */
+ int hl; /* highlight this item */
+};
+
+struct subtitle_list {
+ struct subtitle_list *next;
+ const char *text;
+};
+
+struct dialog_info {
+ const char *backtitle;
+ struct subtitle_list *subtitles;
+ struct dialog_color screen;
+ struct dialog_color shadow;
+ struct dialog_color dialog;
+ struct dialog_color title;
+ struct dialog_color border;
+ struct dialog_color button_active;
+ struct dialog_color button_inactive;
+ struct dialog_color button_key_active;
+ struct dialog_color button_key_inactive;
+ struct dialog_color button_label_active;
+ struct dialog_color button_label_inactive;
+ struct dialog_color inputbox;
+ struct dialog_color inputbox_border;
+ struct dialog_color searchbox;
+ struct dialog_color searchbox_title;
+ struct dialog_color searchbox_border;
+ struct dialog_color position_indicator;
+ struct dialog_color menubox;
+ struct dialog_color menubox_border;
+ struct dialog_color item;
+ struct dialog_color item_selected;
+ struct dialog_color tag;
+ struct dialog_color tag_selected;
+ struct dialog_color tag_key;
+ struct dialog_color tag_key_selected;
+ struct dialog_color check;
+ struct dialog_color check_selected;
+ struct dialog_color uarrow;
+ struct dialog_color darrow;
+};
+
+/*
+ * Global variables
+ */
+extern struct dialog_info dlg;
+extern char dialog_input_result[];
+extern int saved_x, saved_y; /* Needed in signal handler in mconf.c */
+
+/*
+ * Function prototypes
+ */
+
+/* item list as used by checklist and menubox */
+void item_reset(void);
+void item_make(const char *fmt, ...);
+void item_add_str(const char *fmt, ...);
+void item_set_tag(char tag);
+void item_set_data(void *p);
+void item_set_selected(int val);
+int item_activate_selected(void);
+void *item_data(void);
+char item_tag(void);
+
+/* item list manipulation for lxdialog use */
+#define MAXITEMSTR 200
+struct dialog_item {
+ char str[MAXITEMSTR]; /* promtp displayed */
+ char tag;
+ void *data; /* pointer to menu item - used by menubox+checklist */
+ int selected; /* Set to 1 by dialog_*() function if selected. */
+};
+
+/* list of lialog_items */
+struct dialog_list {
+ struct dialog_item node;
+ struct dialog_list *next;
+};
+
+extern struct dialog_list *item_cur;
+extern struct dialog_list item_nil;
+extern struct dialog_list *item_head;
+
+int item_count(void);
+void item_set(int n);
+int item_n(void);
+const char *item_str(void);
+int item_is_selected(void);
+int item_is_tag(char tag);
+#define item_foreach() \
+ for (item_cur = item_head ? item_head: item_cur; \
+ item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
+
+/* generic key handlers */
+int on_key_esc(WINDOW *win);
+int on_key_resize(void);
+
+/* minimum (re)size values */
+#define CHECKLIST_HEIGTH_MIN 6 /* For dialog_checklist() */
+#define CHECKLIST_WIDTH_MIN 6
+#define INPUTBOX_HEIGTH_MIN 2 /* For dialog_inputbox() */
+#define INPUTBOX_WIDTH_MIN 2
+#define MENUBOX_HEIGTH_MIN 15 /* For dialog_menu() */
+#define MENUBOX_WIDTH_MIN 65
+#define TEXTBOX_HEIGTH_MIN 8 /* For dialog_textbox() */
+#define TEXTBOX_WIDTH_MIN 8
+#define YESNO_HEIGTH_MIN 4 /* For dialog_yesno() */
+#define YESNO_WIDTH_MIN 4
+#define WINDOW_HEIGTH_MIN 19 /* For init_dialog() */
+#define WINDOW_WIDTH_MIN 80
+
+int init_dialog(const char *backtitle);
+void set_dialog_backtitle(const char *backtitle);
+void set_dialog_subtitles(struct subtitle_list *subtitles);
+void end_dialog(int x, int y);
+void attr_clear(WINDOW * win, int height, int width, chtype attr);
+void dialog_clear(void);
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
+void print_button(WINDOW * win, const char *label, int y, int x, int selected);
+void print_title(WINDOW *dialog, const char *title, int width);
+void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
+ chtype border);
+void draw_shadow(WINDOW * win, int y, int x, int height, int width);
+
+int first_alpha(const char *string, const char *exempt);
+int dialog_yesno(const char *title, const char *prompt, int height, int width);
+int dialog_msgbox(const char *title, const char *prompt, int height,
+ int width, int pause);
+
+
+typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void
+ *_data);
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+ int initial_width, int *keys, int *_vscroll, int *_hscroll,
+ update_text_fn update_text, void *data);
+int dialog_menu(const char *title, const char *prompt,
+ const void *selected, int *s_scroll);
+int dialog_checklist(const char *title, const char *prompt, int height,
+ int width, int list_height);
+int dialog_inputbox(const char *title, const char *prompt, int height,
+ int width, const char *init);
+
+/*
+ * This is the base for fictitious keys, which activate
+ * the buttons.
+ *
+ * Mouse-generated keys are the following:
+ * -- the first 32 are used as numbers, in addition to '0'-'9'
+ * -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
+ * -- uppercase chars are used to invoke the button (M_EVENT + 'O')
+ */
+#define M_EVENT (KEY_MAX+1)
diff --git a/roms/seabios/scripts/kconfig/lxdialog/inputbox.c b/roms/seabios/scripts/kconfig/lxdialog/inputbox.c
new file mode 100644
index 00000000..d58de1dc
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/lxdialog/inputbox.c
@@ -0,0 +1,301 @@
+/*
+ * inputbox.c -- implements the input box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+char dialog_input_result[MAX_LEN + 1];
+
+/*
+ * Print the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+ int x = width / 2 - 11;
+ int y = height - 2;
+
+ print_button(dialog, gettext(" Ok "), y, x, selected == 0);
+ print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+
+ wmove(dialog, y, x + 1 + 14 * selected);
+ wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box for inputing a string
+ */
+int dialog_inputbox(const char *title, const char *prompt, int height, int width,
+ const char *init)
+{
+ int i, x, y, box_y, box_x, box_width;
+ int input_x = 0, key = 0, button = -1;
+ int show_x, len, pos;
+ char *instr = dialog_input_result;
+ WINDOW *dialog;
+
+ if (!init)
+ instr[0] = '\0';
+ else
+ strcpy(instr, init);
+
+do_resize:
+ if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
+ return -ERRDISPLAYTOOSMALL;
+
+ /* center dialog box on screen */
+ x = (getmaxx(stdscr) - width) / 2;
+ y = (getmaxy(stdscr) - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ /* Draw the input field box */
+ box_width = width - 6;
+ getyx(dialog, y, x);
+ box_y = y + 2;
+ box_x = (width - box_width) / 2;
+ draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
+ dlg.dialog.atr, dlg.border.atr);
+
+ print_buttons(dialog, height, width, 0);
+
+ /* Set up the initial value */
+ wmove(dialog, box_y, box_x);
+ wattrset(dialog, dlg.inputbox.atr);
+
+ len = strlen(instr);
+ pos = len;
+
+ if (len >= box_width) {
+ show_x = len - box_width + 1;
+ input_x = box_width - 1;
+ for (i = 0; i < box_width - 1; i++)
+ waddch(dialog, instr[show_x + i]);
+ } else {
+ show_x = 0;
+ input_x = len;
+ waddstr(dialog, instr);
+ }
+
+ wmove(dialog, box_y, box_x + input_x);
+
+ wrefresh(dialog);
+
+ while (key != KEY_ESC) {
+ key = wgetch(dialog);
+
+ if (button == -1) { /* Input box selected */
+ switch (key) {
+ case TAB:
+ case KEY_UP:
+ case KEY_DOWN:
+ break;
+ case KEY_BACKSPACE:
+ case 127:
+ if (pos) {
+ wattrset(dialog, dlg.inputbox.atr);
+ if (input_x == 0) {
+ show_x--;
+ } else
+ input_x--;
+
+ if (pos < len) {
+ for (i = pos - 1; i < len; i++) {
+ instr[i] = instr[i+1];
+ }
+ }
+
+ pos--;
+ len--;
+ instr[len] = '\0';
+ wmove(dialog, box_y, box_x);
+ for (i = 0; i < box_width; i++) {
+ if (!instr[show_x + i]) {
+ waddch(dialog, ' ');
+ break;
+ }
+ waddch(dialog, instr[show_x + i]);
+ }
+ wmove(dialog, box_y, input_x + box_x);
+ wrefresh(dialog);
+ }
+ continue;
+ case KEY_LEFT:
+ if (pos > 0) {
+ if (input_x > 0) {
+ wmove(dialog, box_y, --input_x + box_x);
+ } else if (input_x == 0) {
+ show_x--;
+ wmove(dialog, box_y, box_x);
+ for (i = 0; i < box_width; i++) {
+ if (!instr[show_x + i]) {
+ waddch(dialog, ' ');
+ break;
+ }
+ waddch(dialog, instr[show_x + i]);
+ }
+ wmove(dialog, box_y, box_x);
+ }
+ pos--;
+ }
+ continue;
+ case KEY_RIGHT:
+ if (pos < len) {
+ if (input_x < box_width - 1) {
+ wmove(dialog, box_y, ++input_x + box_x);
+ } else if (input_x == box_width - 1) {
+ show_x++;
+ wmove(dialog, box_y, box_x);
+ for (i = 0; i < box_width; i++) {
+ if (!instr[show_x + i]) {
+ waddch(dialog, ' ');
+ break;
+ }
+ waddch(dialog, instr[show_x + i]);
+ }
+ wmove(dialog, box_y, input_x + box_x);
+ }
+ pos++;
+ }
+ continue;
+ default:
+ if (key < 0x100 && isprint(key)) {
+ if (len < MAX_LEN) {
+ wattrset(dialog, dlg.inputbox.atr);
+ if (pos < len) {
+ for (i = len; i > pos; i--)
+ instr[i] = instr[i-1];
+ instr[pos] = key;
+ } else {
+ instr[len] = key;
+ }
+ pos++;
+ len++;
+ instr[len] = '\0';
+
+ if (input_x == box_width - 1) {
+ show_x++;
+ } else {
+ input_x++;
+ }
+
+ wmove(dialog, box_y, box_x);
+ for (i = 0; i < box_width; i++) {
+ if (!instr[show_x + i]) {
+ waddch(dialog, ' ');
+ break;
+ }
+ waddch(dialog, instr[show_x + i]);
+ }
+ wmove(dialog, box_y, input_x + box_x);
+ wrefresh(dialog);
+ } else
+ flash(); /* Alarm user about overflow */
+ continue;
+ }
+ }
+ }
+ switch (key) {
+ case 'O':
+ case 'o':
+ delwin(dialog);
+ return 0;
+ case 'H':
+ case 'h':
+ delwin(dialog);
+ return 1;
+ case KEY_UP:
+ case KEY_LEFT:
+ switch (button) {
+ case -1:
+ button = 1; /* Indicates "Help" button is selected */
+ print_buttons(dialog, height, width, 1);
+ break;
+ case 0:
+ button = -1; /* Indicates input box is selected */
+ print_buttons(dialog, height, width, 0);
+ wmove(dialog, box_y, box_x + input_x);
+ wrefresh(dialog);
+ break;
+ case 1:
+ button = 0; /* Indicates "OK" button is selected */
+ print_buttons(dialog, height, width, 0);
+ break;
+ }
+ break;
+ case TAB:
+ case KEY_DOWN:
+ case KEY_RIGHT:
+ switch (button) {
+ case -1:
+ button = 0; /* Indicates "OK" button is selected */
+ print_buttons(dialog, height, width, 0);
+ break;
+ case 0:
+ button = 1; /* Indicates "Help" button is selected */
+ print_buttons(dialog, height, width, 1);
+ break;
+ case 1:
+ button = -1; /* Indicates input box is selected */
+ print_buttons(dialog, height, width, 0);
+ wmove(dialog, box_y, box_x + input_x);
+ wrefresh(dialog);
+ break;
+ }
+ break;
+ case ' ':
+ case '\n':
+ delwin(dialog);
+ return (button == -1 ? 0 : button);
+ case 'X':
+ case 'x':
+ key = KEY_ESC;
+ break;
+ case KEY_ESC:
+ key = on_key_esc(dialog);
+ break;
+ case KEY_RESIZE:
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
+ }
+ }
+
+ delwin(dialog);
+ return KEY_ESC; /* ESC pressed */
+}
diff --git a/roms/seabios/scripts/kconfig/lxdialog/menubox.c b/roms/seabios/scripts/kconfig/lxdialog/menubox.c
new file mode 100644
index 00000000..11ae9ad7
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/lxdialog/menubox.c
@@ -0,0 +1,437 @@
+/*
+ * menubox.c -- implements the menu box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Changes by Clifford Wolf (god@clifford.at)
+ *
+ * [ 1998-06-13 ]
+ *
+ * *) A bugfix for the Page-Down problem
+ *
+ * *) Formerly when I used Page Down and Page Up, the cursor would be set
+ * to the first position in the menu box. Now lxdialog is a bit
+ * smarter and works more like other menu systems (just have a look at
+ * it).
+ *
+ * *) Formerly if I selected something my scrolling would be broken because
+ * lxdialog is re-invoked by the Menuconfig shell script, can't
+ * remember the last scrolling position, and just sets it so that the
+ * cursor is at the bottom of the box. Now it writes the temporary file
+ * lxdialog.scrltmp which contains this information. The file is
+ * deleted by lxdialog if the user leaves a submenu or enters a new
+ * one, but it would be nice if Menuconfig could make another "rm -f"
+ * just to be sure. Just try it out - you will recognise a difference!
+ *
+ * [ 1998-06-14 ]
+ *
+ * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
+ * and menus change their size on the fly.
+ *
+ * *) If for some reason the last scrolling position is not saved by
+ * lxdialog, it sets the scrolling so that the selected item is in the
+ * middle of the menu box, not at the bottom.
+ *
+ * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
+ * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
+ * This fixes a bug in Menuconfig where using ' ' to descend into menus
+ * would leave mis-synchronized lxdialog.scrltmp files lying around,
+ * fscanf would read in 'scroll', and eventually that value would get used.
+ */
+
+#include "dialog.h"
+
+static int menu_width, item_x;
+
+/*
+ * Print menu item
+ */
+static void do_print_item(WINDOW * win, const char *item, int line_y,
+ int selected, int hotkey)
+{
+ int j;
+ char *menu_item = malloc(menu_width + 1);
+
+ strncpy(menu_item, item, menu_width - item_x);
+ menu_item[menu_width - item_x] = '\0';
+ j = first_alpha(menu_item, "YyNnMmHh");
+
+ /* Clear 'residue' of last item */
+ wattrset(win, dlg.menubox.atr);
+ wmove(win, line_y, 0);
+#if OLD_NCURSES
+ {
+ int i;
+ for (i = 0; i < menu_width; i++)
+ waddch(win, ' ');
+ }
+#else
+ wclrtoeol(win);
+#endif
+ wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+ mvwaddstr(win, line_y, item_x, menu_item);
+ if (hotkey) {
+ wattrset(win, selected ? dlg.tag_key_selected.atr
+ : dlg.tag_key.atr);
+ mvwaddch(win, line_y, item_x + j, menu_item[j]);
+ }
+ if (selected) {
+ wmove(win, line_y, item_x + 1);
+ }
+ free(menu_item);
+ wrefresh(win);
+}
+
+#define print_item(index, choice, selected) \
+do { \
+ item_set(index); \
+ do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
+} while (0)
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
+ int height)
+{
+ int cur_y, cur_x;
+
+ getyx(win, cur_y, cur_x);
+
+ wmove(win, y, x);
+
+ if (scroll > 0) {
+ wattrset(win, dlg.uarrow.atr);
+ waddch(win, ACS_UARROW);
+ waddstr(win, "(-)");
+ } else {
+ wattrset(win, dlg.menubox.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ }
+
+ y = y + height + 1;
+ wmove(win, y, x);
+ wrefresh(win);
+
+ if ((height < item_no) && (scroll + height < item_no)) {
+ wattrset(win, dlg.darrow.atr);
+ waddch(win, ACS_DARROW);
+ waddstr(win, "(+)");
+ } else {
+ wattrset(win, dlg.menubox_border.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ }
+
+ wmove(win, cur_y, cur_x);
+ wrefresh(win);
+}
+
+/*
+ * Display the termination buttons.
+ */
+static void print_buttons(WINDOW * win, int height, int width, int selected)
+{
+ int x = width / 2 - 28;
+ int y = height - 2;
+
+ print_button(win, gettext("Select"), y, x, selected == 0);
+ print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
+ print_button(win, gettext(" Help "), y, x + 24, selected == 2);
+ print_button(win, gettext(" Save "), y, x + 36, selected == 3);
+ print_button(win, gettext(" Load "), y, x + 48, selected == 4);
+
+ wmove(win, y, x + 1 + 12 * selected);
+ wrefresh(win);
+}
+
+/* scroll up n lines (n may be negative) */
+static void do_scroll(WINDOW *win, int *scroll, int n)
+{
+ /* Scroll menu up */
+ scrollok(win, TRUE);
+ wscrl(win, n);
+ scrollok(win, FALSE);
+ *scroll = *scroll + n;
+ wrefresh(win);
+}
+
+/*
+ * Display a menu for choosing among a number of options
+ */
+int dialog_menu(const char *title, const char *prompt,
+ const void *selected, int *s_scroll)
+{
+ int i, j, x, y, box_x, box_y;
+ int height, width, menu_height;
+ int key = 0, button = 0, scroll = 0, choice = 0;
+ int first_item = 0, max_choice;
+ WINDOW *dialog, *menu;
+
+do_resize:
+ height = getmaxy(stdscr);
+ width = getmaxx(stdscr);
+ if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN)
+ return -ERRDISPLAYTOOSMALL;
+
+ height -= 4;
+ width -= 5;
+ menu_height = height - 10;
+
+ max_choice = MIN(menu_height, item_count());
+
+ /* center dialog box on screen */
+ x = (getmaxx(stdscr) - width) / 2;
+ y = (getmaxy(stdscr) - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ menu_width = width - 6;
+ box_y = height - menu_height - 5;
+ box_x = (width - menu_width) / 2 - 1;
+
+ /* create new window for the menu */
+ menu = subwin(dialog, menu_height, menu_width,
+ y + box_y + 1, x + box_x + 1);
+ keypad(menu, TRUE);
+
+ /* draw a box around the menu items */
+ draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
+ dlg.menubox_border.atr, dlg.menubox.atr);
+
+ if (menu_width >= 80)
+ item_x = (menu_width - 70) / 2;
+ else
+ item_x = 4;
+
+ /* Set choice to default item */
+ item_foreach()
+ if (selected && (selected == item_data()))
+ choice = item_n();
+ /* get the saved scroll info */
+ scroll = *s_scroll;
+ if ((scroll <= choice) && (scroll + max_choice > choice) &&
+ (scroll >= 0) && (scroll + max_choice <= item_count())) {
+ first_item = scroll;
+ choice = choice - scroll;
+ } else {
+ scroll = 0;
+ }
+ if ((choice >= max_choice)) {
+ if (choice >= item_count() - max_choice / 2)
+ scroll = first_item = item_count() - max_choice;
+ else
+ scroll = first_item = choice - max_choice / 2;
+ choice = choice - scroll;
+ }
+
+ /* Print the menu */
+ for (i = 0; i < max_choice; i++) {
+ print_item(first_item + i, i, i == choice);
+ }
+
+ wnoutrefresh(menu);
+
+ print_arrows(dialog, item_count(), scroll,
+ box_y, box_x + item_x + 1, menu_height);
+
+ print_buttons(dialog, height, width, 0);
+ wmove(menu, choice, item_x + 1);
+ wrefresh(menu);
+
+ while (key != KEY_ESC) {
+ key = wgetch(menu);
+
+ if (key < 256 && isalpha(key))
+ key = tolower(key);
+
+ if (strchr("ynmh", key))
+ i = max_choice;
+ else {
+ for (i = choice + 1; i < max_choice; i++) {
+ item_set(scroll + i);
+ j = first_alpha(item_str(), "YyNnMmHh");
+ if (key == tolower(item_str()[j]))
+ break;
+ }
+ if (i == max_choice)
+ for (i = 0; i < max_choice; i++) {
+ item_set(scroll + i);
+ j = first_alpha(item_str(), "YyNnMmHh");
+ if (key == tolower(item_str()[j]))
+ break;
+ }
+ }
+
+ if (item_count() != 0 &&
+ (i < max_choice ||
+ key == KEY_UP || key == KEY_DOWN ||
+ key == '-' || key == '+' ||
+ key == KEY_PPAGE || key == KEY_NPAGE)) {
+ /* Remove highligt of current item */
+ print_item(scroll + choice, choice, FALSE);
+
+ if (key == KEY_UP || key == '-') {
+ if (choice < 2 && scroll) {
+ /* Scroll menu down */
+ do_scroll(menu, &scroll, -1);
+
+ print_item(scroll, 0, FALSE);
+ } else
+ choice = MAX(choice - 1, 0);
+
+ } else if (key == KEY_DOWN || key == '+') {
+ print_item(scroll+choice, choice, FALSE);
+
+ if ((choice > max_choice - 3) &&
+ (scroll + max_choice < item_count())) {
+ /* Scroll menu up */
+ do_scroll(menu, &scroll, 1);
+
+ print_item(scroll+max_choice - 1,
+ max_choice - 1, FALSE);
+ } else
+ choice = MIN(choice + 1, max_choice - 1);
+
+ } else if (key == KEY_PPAGE) {
+ scrollok(menu, TRUE);
+ for (i = 0; (i < max_choice); i++) {
+ if (scroll > 0) {
+ do_scroll(menu, &scroll, -1);
+ print_item(scroll, 0, FALSE);
+ } else {
+ if (choice > 0)
+ choice--;
+ }
+ }
+
+ } else if (key == KEY_NPAGE) {
+ for (i = 0; (i < max_choice); i++) {
+ if (scroll + max_choice < item_count()) {
+ do_scroll(menu, &scroll, 1);
+ print_item(scroll+max_choice-1,
+ max_choice - 1, FALSE);
+ } else {
+ if (choice + 1 < max_choice)
+ choice++;
+ }
+ }
+ } else
+ choice = i;
+
+ print_item(scroll + choice, choice, TRUE);
+
+ print_arrows(dialog, item_count(), scroll,
+ box_y, box_x + item_x + 1, menu_height);
+
+ wnoutrefresh(dialog);
+ wrefresh(menu);
+
+ continue; /* wait for another key press */
+ }
+
+ switch (key) {
+ case KEY_LEFT:
+ case TAB:
+ case KEY_RIGHT:
+ button = ((key == KEY_LEFT ? --button : ++button) < 0)
+ ? 4 : (button > 4 ? 0 : button);
+
+ print_buttons(dialog, height, width, button);
+ wrefresh(menu);
+ break;
+ case ' ':
+ case 's':
+ case 'y':
+ case 'n':
+ case 'm':
+ case '/':
+ case 'h':
+ case '?':
+ case 'z':
+ case '\n':
+ /* save scroll info */
+ *s_scroll = scroll;
+ delwin(menu);
+ delwin(dialog);
+ item_set(scroll + choice);
+ item_set_selected(1);
+ switch (key) {
+ case 'h':
+ case '?':
+ return 2;
+ case 's':
+ case 'y':
+ return 5;
+ case 'n':
+ return 6;
+ case 'm':
+ return 7;
+ case ' ':
+ return 8;
+ case '/':
+ return 9;
+ case 'z':
+ return 10;
+ case '\n':
+ return button;
+ }
+ return 0;
+ case 'e':
+ case 'x':
+ key = KEY_ESC;
+ break;
+ case KEY_ESC:
+ key = on_key_esc(menu);
+ break;
+ case KEY_RESIZE:
+ on_key_resize();
+ delwin(menu);
+ delwin(dialog);
+ goto do_resize;
+ }
+ }
+ delwin(menu);
+ delwin(dialog);
+ return key; /* ESC pressed */
+}
diff --git a/roms/seabios/scripts/kconfig/lxdialog/textbox.c b/roms/seabios/scripts/kconfig/lxdialog/textbox.c
new file mode 100644
index 00000000..1773319b
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/lxdialog/textbox.c
@@ -0,0 +1,408 @@
+/*
+ * textbox.c -- implements the text box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static void back_lines(int n);
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+ update_text, void *data);
+static void print_line(WINDOW *win, int row, int width);
+static char *get_line(void);
+static void print_position(WINDOW * win);
+
+static int hscroll;
+static int begin_reached, end_reached, page_length;
+static char *buf;
+static char *page;
+
+/*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+ int cur_y, int cur_x, update_text_fn update_text,
+ void *data)
+{
+ print_page(box, boxh, boxw, update_text, data);
+ print_position(dialog);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+}
+
+
+/*
+ * Display text from a file in a dialog box.
+ *
+ * keys is a null-terminated array
+ * update_text() may not add or remove any '\n' or '\0' in tbuf
+ */
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+ int initial_width, int *keys, int *_vscroll, int *_hscroll,
+ update_text_fn update_text, void *data)
+{
+ int i, x, y, cur_x, cur_y, key = 0;
+ int height, width, boxh, boxw;
+ WINDOW *dialog, *box;
+ bool done = false;
+
+ begin_reached = 1;
+ end_reached = 0;
+ page_length = 0;
+ hscroll = 0;
+ buf = tbuf;
+ page = buf; /* page is pointer to start of page to be displayed */
+
+ if (_vscroll && *_vscroll) {
+ begin_reached = 0;
+
+ for (i = 0; i < *_vscroll; i++)
+ get_line();
+ }
+ if (_hscroll)
+ hscroll = *_hscroll;
+
+do_resize:
+ getmaxyx(stdscr, height, width);
+ if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN)
+ return -ERRDISPLAYTOOSMALL;
+ if (initial_height != 0)
+ height = initial_height;
+ else
+ if (height > 4)
+ height -= 4;
+ else
+ height = 0;
+ if (initial_width != 0)
+ width = initial_width;
+ else
+ if (width > 5)
+ width -= 5;
+ else
+ width = 0;
+
+ /* center dialog box on screen */
+ x = (getmaxx(stdscr) - width) / 2;
+ y = (getmaxy(stdscr) - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ /* Create window for box region, used for scrolling text */
+ boxh = height - 4;
+ boxw = width - 2;
+ box = subwin(dialog, boxh, boxw, y + 1, x + 1);
+ wattrset(box, dlg.dialog.atr);
+ wbkgdset(box, dlg.dialog.atr & A_COLOR);
+
+ keypad(box, TRUE);
+
+ /* register the new window, along with its borders */
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE);
+ wnoutrefresh(dialog);
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+
+ /* Print first page of text */
+ attr_clear(box, boxh, boxw, dlg.dialog.atr);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text,
+ data);
+
+ while (!done) {
+ key = wgetch(dialog);
+ switch (key) {
+ case 'E': /* Exit */
+ case 'e':
+ case 'X':
+ case 'x':
+ case 'q':
+ case '\n':
+ done = true;
+ break;
+ case 'g': /* First page */
+ case KEY_HOME:
+ if (!begin_reached) {
+ begin_reached = 1;
+ page = buf;
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x, update_text,
+ data);
+ }
+ break;
+ case 'G': /* Last page */
+ case KEY_END:
+
+ end_reached = 1;
+ /* point to last char in buf */
+ page = buf + strlen(buf);
+ back_lines(boxh);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
+ break;
+ case 'K': /* Previous line */
+ case 'k':
+ case KEY_UP:
+ if (begin_reached)
+ break;
+
+ back_lines(page_length + 1);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
+ break;
+ case 'B': /* Previous page */
+ case 'b':
+ case 'u':
+ case KEY_PPAGE:
+ if (begin_reached)
+ break;
+ back_lines(page_length + boxh);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
+ break;
+ case 'J': /* Next line */
+ case 'j':
+ case KEY_DOWN:
+ if (end_reached)
+ break;
+
+ back_lines(page_length - 1);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
+ break;
+ case KEY_NPAGE: /* Next page */
+ case ' ':
+ case 'd':
+ if (end_reached)
+ break;
+
+ begin_reached = 0;
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
+ break;
+ case '0': /* Beginning of line */
+ case 'H': /* Scroll left */
+ case 'h':
+ case KEY_LEFT:
+ if (hscroll <= 0)
+ break;
+
+ if (key == '0')
+ hscroll = 0;
+ else
+ hscroll--;
+ /* Reprint current page to scroll horizontally */
+ back_lines(page_length);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
+ break;
+ case 'L': /* Scroll right */
+ case 'l':
+ case KEY_RIGHT:
+ if (hscroll >= MAX_LEN)
+ break;
+ hscroll++;
+ /* Reprint current page to scroll horizontally */
+ back_lines(page_length);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
+ break;
+ case KEY_ESC:
+ if (on_key_esc(dialog) == KEY_ESC)
+ done = true;
+ break;
+ case KEY_RESIZE:
+ back_lines(height);
+ delwin(box);
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
+ default:
+ for (i = 0; keys[i]; i++) {
+ if (key == keys[i]) {
+ done = true;
+ break;
+ }
+ }
+ }
+ }
+ delwin(box);
+ delwin(dialog);
+ if (_vscroll) {
+ const char *s;
+
+ s = buf;
+ *_vscroll = 0;
+ back_lines(page_length);
+ while (s < page && (s = strchr(s, '\n'))) {
+ (*_vscroll)++;
+ s++;
+ }
+ }
+ if (_hscroll)
+ *_hscroll = hscroll;
+ return key;
+}
+
+/*
+ * Go back 'n' lines in text. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+static void back_lines(int n)
+{
+ int i;
+
+ begin_reached = 0;
+ /* Go back 'n' lines */
+ for (i = 0; i < n; i++) {
+ if (*page == '\0') {
+ if (end_reached) {
+ end_reached = 0;
+ continue;
+ }
+ }
+ if (page == buf) {
+ begin_reached = 1;
+ return;
+ }
+ page--;
+ do {
+ if (page == buf) {
+ begin_reached = 1;
+ return;
+ }
+ page--;
+ } while (*page != '\n');
+ page++;
+ }
+}
+
+/*
+ * Print a new page of text.
+ */
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+ update_text, void *data)
+{
+ int i, passed_end = 0;
+
+ if (update_text) {
+ char *end;
+
+ for (i = 0; i < height; i++)
+ get_line();
+ end = page;
+ back_lines(height);
+ update_text(buf, page - buf, end - buf, data);
+ }
+
+ page_length = 0;
+ for (i = 0; i < height; i++) {
+ print_line(win, i, width);
+ if (!passed_end)
+ page_length++;
+ if (end_reached && !passed_end)
+ passed_end = 1;
+ }
+ wnoutrefresh(win);
+}
+
+/*
+ * Print a new line of text.
+ */
+static void print_line(WINDOW * win, int row, int width)
+{
+ char *line;
+
+ line = get_line();
+ line += MIN(strlen(line), hscroll); /* Scroll horizontally */
+ wmove(win, row, 0); /* move cursor to correct line */
+ waddch(win, ' ');
+ waddnstr(win, line, MIN(strlen(line), width - 2));
+
+ /* Clear 'residue' of previous line */
+#if OLD_NCURSES
+ {
+ int x = getcurx(win);
+ int i;
+ for (i = 0; i < width - x; i++)
+ waddch(win, ' ');
+ }
+#else
+ wclrtoeol(win);
+#endif
+}
+
+/*
+ * Return current line of text. Called by dialog_textbox() and print_line().
+ * 'page' should point to start of current line before calling, and will be
+ * updated to point to start of next line.
+ */
+static char *get_line(void)
+{
+ int i = 0;
+ static char line[MAX_LEN + 1];
+
+ end_reached = 0;
+ while (*page != '\n') {
+ if (*page == '\0') {
+ end_reached = 1;
+ break;
+ } else if (i < MAX_LEN)
+ line[i++] = *(page++);
+ else {
+ /* Truncate lines longer than MAX_LEN characters */
+ if (i == MAX_LEN)
+ line[i++] = '\0';
+ page++;
+ }
+ }
+ if (i <= MAX_LEN)
+ line[i] = '\0';
+ if (!end_reached)
+ page++; /* move past '\n' */
+
+ return line;
+}
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW * win)
+{
+ int percent;
+
+ wattrset(win, dlg.position_indicator.atr);
+ wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
+ percent = (page - buf) * 100 / strlen(buf);
+ wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
+ wprintw(win, "(%3d%%)", percent);
+}
diff --git a/roms/seabios/scripts/kconfig/lxdialog/util.c b/roms/seabios/scripts/kconfig/lxdialog/util.c
new file mode 100644
index 00000000..f7abdeb9
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/lxdialog/util.c
@@ -0,0 +1,713 @@
+/*
+ * util.c
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdarg.h>
+
+#include "dialog.h"
+
+/* Needed in signal handler in mconf.c */
+int saved_x, saved_y;
+
+struct dialog_info dlg;
+
+static void set_mono_theme(void)
+{
+ dlg.screen.atr = A_NORMAL;
+ dlg.shadow.atr = A_NORMAL;
+ dlg.dialog.atr = A_NORMAL;
+ dlg.title.atr = A_BOLD;
+ dlg.border.atr = A_NORMAL;
+ dlg.button_active.atr = A_REVERSE;
+ dlg.button_inactive.atr = A_DIM;
+ dlg.button_key_active.atr = A_REVERSE;
+ dlg.button_key_inactive.atr = A_BOLD;
+ dlg.button_label_active.atr = A_REVERSE;
+ dlg.button_label_inactive.atr = A_NORMAL;
+ dlg.inputbox.atr = A_NORMAL;
+ dlg.inputbox_border.atr = A_NORMAL;
+ dlg.searchbox.atr = A_NORMAL;
+ dlg.searchbox_title.atr = A_BOLD;
+ dlg.searchbox_border.atr = A_NORMAL;
+ dlg.position_indicator.atr = A_BOLD;
+ dlg.menubox.atr = A_NORMAL;
+ dlg.menubox_border.atr = A_NORMAL;
+ dlg.item.atr = A_NORMAL;
+ dlg.item_selected.atr = A_REVERSE;
+ dlg.tag.atr = A_BOLD;
+ dlg.tag_selected.atr = A_REVERSE;
+ dlg.tag_key.atr = A_BOLD;
+ dlg.tag_key_selected.atr = A_REVERSE;
+ dlg.check.atr = A_BOLD;
+ dlg.check_selected.atr = A_REVERSE;
+ dlg.uarrow.atr = A_BOLD;
+ dlg.darrow.atr = A_BOLD;
+}
+
+#define DLG_COLOR(dialog, f, b, h) \
+do { \
+ dlg.dialog.fg = (f); \
+ dlg.dialog.bg = (b); \
+ dlg.dialog.hl = (h); \
+} while (0)
+
+static void set_classic_theme(void)
+{
+ DLG_COLOR(screen, COLOR_CYAN, COLOR_BLUE, true);
+ DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, true);
+ DLG_COLOR(dialog, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(border, COLOR_WHITE, COLOR_WHITE, true);
+ DLG_COLOR(button_active, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(button_inactive, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(button_key_active, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_WHITE, false);
+ DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true);
+ DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true);
+ DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true);
+ DLG_COLOR(item, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(item_selected, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(check, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(check_selected, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(uarrow, COLOR_GREEN, COLOR_WHITE, true);
+ DLG_COLOR(darrow, COLOR_GREEN, COLOR_WHITE, true);
+}
+
+static void set_blackbg_theme(void)
+{
+ DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true);
+ DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
+ DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
+ DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false);
+ DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true);
+ DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false);
+ DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false);
+
+ DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true);
+ DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false);
+
+ DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false);
+ DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false);
+
+ DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true);
+ DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true);
+
+ DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true);
+
+ DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
+}
+
+static void set_bluetitle_theme(void)
+{
+ set_classic_theme();
+ DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true);
+
+}
+
+/*
+ * Select color theme
+ */
+static int set_theme(const char *theme)
+{
+ int use_color = 1;
+ if (!theme)
+ set_bluetitle_theme();
+ else if (strcmp(theme, "classic") == 0)
+ set_classic_theme();
+ else if (strcmp(theme, "bluetitle") == 0)
+ set_bluetitle_theme();
+ else if (strcmp(theme, "blackbg") == 0)
+ set_blackbg_theme();
+ else if (strcmp(theme, "mono") == 0)
+ use_color = 0;
+
+ return use_color;
+}
+
+static void init_one_color(struct dialog_color *color)
+{
+ static int pair = 0;
+
+ pair++;
+ init_pair(pair, color->fg, color->bg);
+ if (color->hl)
+ color->atr = A_BOLD | COLOR_PAIR(pair);
+ else
+ color->atr = COLOR_PAIR(pair);
+}
+
+static void init_dialog_colors(void)
+{
+ init_one_color(&dlg.screen);
+ init_one_color(&dlg.shadow);
+ init_one_color(&dlg.dialog);
+ init_one_color(&dlg.title);
+ init_one_color(&dlg.border);
+ init_one_color(&dlg.button_active);
+ init_one_color(&dlg.button_inactive);
+ init_one_color(&dlg.button_key_active);
+ init_one_color(&dlg.button_key_inactive);
+ init_one_color(&dlg.button_label_active);
+ init_one_color(&dlg.button_label_inactive);
+ init_one_color(&dlg.inputbox);
+ init_one_color(&dlg.inputbox_border);
+ init_one_color(&dlg.searchbox);
+ init_one_color(&dlg.searchbox_title);
+ init_one_color(&dlg.searchbox_border);
+ init_one_color(&dlg.position_indicator);
+ init_one_color(&dlg.menubox);
+ init_one_color(&dlg.menubox_border);
+ init_one_color(&dlg.item);
+ init_one_color(&dlg.item_selected);
+ init_one_color(&dlg.tag);
+ init_one_color(&dlg.tag_selected);
+ init_one_color(&dlg.tag_key);
+ init_one_color(&dlg.tag_key_selected);
+ init_one_color(&dlg.check);
+ init_one_color(&dlg.check_selected);
+ init_one_color(&dlg.uarrow);
+ init_one_color(&dlg.darrow);
+}
+
+/*
+ * Setup for color display
+ */
+static void color_setup(const char *theme)
+{
+ int use_color;
+
+ use_color = set_theme(theme);
+ if (use_color && has_colors()) {
+ start_color();
+ init_dialog_colors();
+ } else
+ set_mono_theme();
+}
+
+/*
+ * Set window to attribute 'attr'
+ */
+void attr_clear(WINDOW * win, int height, int width, chtype attr)
+{
+ int i, j;
+
+ wattrset(win, attr);
+ for (i = 0; i < height; i++) {
+ wmove(win, i, 0);
+ for (j = 0; j < width; j++)
+ waddch(win, ' ');
+ }
+ touchwin(win);
+}
+
+void dialog_clear(void)
+{
+ int lines, columns;
+
+ lines = getmaxy(stdscr);
+ columns = getmaxx(stdscr);
+
+ attr_clear(stdscr, lines, columns, dlg.screen.atr);
+ /* Display background title if it exists ... - SLH */
+ if (dlg.backtitle != NULL) {
+ int i, len = 0, skip = 0;
+ struct subtitle_list *pos;
+
+ wattrset(stdscr, dlg.screen.atr);
+ mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
+
+ for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
+ /* 3 is for the arrow and spaces */
+ len += strlen(pos->text) + 3;
+ }
+
+ wmove(stdscr, 1, 1);
+ if (len > columns - 2) {
+ const char *ellipsis = "[...] ";
+ waddstr(stdscr, ellipsis);
+ skip = len - (columns - 2 - strlen(ellipsis));
+ }
+
+ for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
+ if (skip == 0)
+ waddch(stdscr, ACS_RARROW);
+ else
+ skip--;
+
+ if (skip == 0)
+ waddch(stdscr, ' ');
+ else
+ skip--;
+
+ if (skip < strlen(pos->text)) {
+ waddstr(stdscr, pos->text + skip);
+ skip = 0;
+ } else
+ skip -= strlen(pos->text);
+
+ if (skip == 0)
+ waddch(stdscr, ' ');
+ else
+ skip--;
+ }
+
+ for (i = len + 1; i < columns - 1; i++)
+ waddch(stdscr, ACS_HLINE);
+ }
+ wnoutrefresh(stdscr);
+}
+
+/*
+ * Do some initialization for dialog
+ */
+int init_dialog(const char *backtitle)
+{
+ int height, width;
+
+ initscr(); /* Init curses */
+
+ /* Get current cursor position for signal handler in mconf.c */
+ getyx(stdscr, saved_y, saved_x);
+
+ getmaxyx(stdscr, height, width);
+ if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) {
+ endwin();
+ return -ERRDISPLAYTOOSMALL;
+ }
+
+ dlg.backtitle = backtitle;
+ color_setup(getenv("MENUCONFIG_COLOR"));
+
+ keypad(stdscr, TRUE);
+ cbreak();
+ noecho();
+ dialog_clear();
+
+ return 0;
+}
+
+void set_dialog_backtitle(const char *backtitle)
+{
+ dlg.backtitle = backtitle;
+}
+
+void set_dialog_subtitles(struct subtitle_list *subtitles)
+{
+ dlg.subtitles = subtitles;
+}
+
+/*
+ * End using dialog functions.
+ */
+void end_dialog(int x, int y)
+{
+ /* move cursor back to original position */
+ move(y, x);
+ refresh();
+ endwin();
+}
+
+/* Print the title of the dialog. Center the title and truncate
+ * tile if wider than dialog (- 2 chars).
+ **/
+void print_title(WINDOW *dialog, const char *title, int width)
+{
+ if (title) {
+ int tlen = MIN(width - 2, strlen(title));
+ wattrset(dialog, dlg.title.atr);
+ mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
+ mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
+ waddch(dialog, ' ');
+ }
+}
+
+/*
+ * Print a string of text in a window, automatically wrap around to the
+ * next line if the string is too long to fit on one line. Newline
+ * characters '\n' are propperly processed. We start on a new line
+ * if there is no room for at least 4 nonblanks following a double-space.
+ */
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
+{
+ int newl, cur_x, cur_y;
+ int prompt_len, room, wlen;
+ char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
+
+ strcpy(tempstr, prompt);
+
+ prompt_len = strlen(tempstr);
+
+ if (prompt_len <= width - x * 2) { /* If prompt is short */
+ wmove(win, y, (width - prompt_len) / 2);
+ waddstr(win, tempstr);
+ } else {
+ cur_x = x;
+ cur_y = y;
+ newl = 1;
+ word = tempstr;
+ while (word && *word) {
+ sp = strpbrk(word, "\n ");
+ if (sp && *sp == '\n')
+ newline_separator = sp;
+
+ if (sp)
+ *sp++ = 0;
+
+ /* Wrap to next line if either the word does not fit,
+ or it is the first word of a new sentence, and it is
+ short, and the next word does not fit. */
+ room = width - cur_x;
+ wlen = strlen(word);
+ if (wlen > room ||
+ (newl && wlen < 4 && sp
+ && wlen + 1 + strlen(sp) > room
+ && (!(sp2 = strpbrk(sp, "\n "))
+ || wlen + 1 + (sp2 - sp) > room))) {
+ cur_y++;
+ cur_x = x;
+ }
+ wmove(win, cur_y, cur_x);
+ waddstr(win, word);
+ getyx(win, cur_y, cur_x);
+
+ /* Move to the next line if the word separator was a newline */
+ if (newline_separator) {
+ cur_y++;
+ cur_x = x;
+ newline_separator = 0;
+ } else
+ cur_x++;
+
+ if (sp && *sp == ' ') {
+ cur_x++; /* double space */
+ while (*++sp == ' ') ;
+ newl = 1;
+ } else
+ newl = 0;
+ word = sp;
+ }
+ }
+}
+
+/*
+ * Print a button
+ */
+void print_button(WINDOW * win, const char *label, int y, int x, int selected)
+{
+ int i, temp;
+
+ wmove(win, y, x);
+ wattrset(win, selected ? dlg.button_active.atr
+ : dlg.button_inactive.atr);
+ waddstr(win, "<");
+ temp = strspn(label, " ");
+ label += temp;
+ wattrset(win, selected ? dlg.button_label_active.atr
+ : dlg.button_label_inactive.atr);
+ for (i = 0; i < temp; i++)
+ waddch(win, ' ');
+ wattrset(win, selected ? dlg.button_key_active.atr
+ : dlg.button_key_inactive.atr);
+ waddch(win, label[0]);
+ wattrset(win, selected ? dlg.button_label_active.atr
+ : dlg.button_label_inactive.atr);
+ waddstr(win, (char *)label + 1);
+ wattrset(win, selected ? dlg.button_active.atr
+ : dlg.button_inactive.atr);
+ waddstr(win, ">");
+ wmove(win, y, x + temp + 1);
+}
+
+/*
+ * Draw a rectangular box with line drawing characters
+ */
+void
+draw_box(WINDOW * win, int y, int x, int height, int width,
+ chtype box, chtype border)
+{
+ int i, j;
+
+ wattrset(win, 0);
+ for (i = 0; i < height; i++) {
+ wmove(win, y + i, x);
+ for (j = 0; j < width; j++)
+ if (!i && !j)
+ waddch(win, border | ACS_ULCORNER);
+ else if (i == height - 1 && !j)
+ waddch(win, border | ACS_LLCORNER);
+ else if (!i && j == width - 1)
+ waddch(win, box | ACS_URCORNER);
+ else if (i == height - 1 && j == width - 1)
+ waddch(win, box | ACS_LRCORNER);
+ else if (!i)
+ waddch(win, border | ACS_HLINE);
+ else if (i == height - 1)
+ waddch(win, box | ACS_HLINE);
+ else if (!j)
+ waddch(win, border | ACS_VLINE);
+ else if (j == width - 1)
+ waddch(win, box | ACS_VLINE);
+ else
+ waddch(win, box | ' ');
+ }
+}
+
+/*
+ * Draw shadows along the right and bottom edge to give a more 3D look
+ * to the boxes
+ */
+void draw_shadow(WINDOW * win, int y, int x, int height, int width)
+{
+ int i;
+
+ if (has_colors()) { /* Whether terminal supports color? */
+ wattrset(win, dlg.shadow.atr);
+ wmove(win, y + height, x + 2);
+ for (i = 0; i < width; i++)
+ waddch(win, winch(win) & A_CHARTEXT);
+ for (i = y + 1; i < y + height + 1; i++) {
+ wmove(win, i, x + width);
+ waddch(win, winch(win) & A_CHARTEXT);
+ waddch(win, winch(win) & A_CHARTEXT);
+ }
+ wnoutrefresh(win);
+ }
+}
+
+/*
+ * Return the position of the first alphabetic character in a string.
+ */
+int first_alpha(const char *string, const char *exempt)
+{
+ int i, in_paren = 0, c;
+
+ for (i = 0; i < strlen(string); i++) {
+ c = tolower(string[i]);
+
+ if (strchr("<[(", c))
+ ++in_paren;
+ if (strchr(">])", c) && in_paren > 0)
+ --in_paren;
+
+ if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
+ return i;
+ }
+
+ return 0;
+}
+
+/*
+ * ncurses uses ESC to detect escaped char sequences. This resutl in
+ * a small timeout before ESC is actually delivered to the application.
+ * lxdialog suggest <ESC> <ESC> which is correctly translated to two
+ * times esc. But then we need to ignore the second esc to avoid stepping
+ * out one menu too much. Filter away all escaped key sequences since
+ * keypad(FALSE) turn off ncurses support for escape sequences - and thats
+ * needed to make notimeout() do as expected.
+ */
+int on_key_esc(WINDOW *win)
+{
+ int key;
+ int key2;
+ int key3;
+
+ nodelay(win, TRUE);
+ keypad(win, FALSE);
+ key = wgetch(win);
+ key2 = wgetch(win);
+ do {
+ key3 = wgetch(win);
+ } while (key3 != ERR);
+ nodelay(win, FALSE);
+ keypad(win, TRUE);
+ if (key == KEY_ESC && key2 == ERR)
+ return KEY_ESC;
+ else if (key != ERR && key != KEY_ESC && key2 == ERR)
+ ungetch(key);
+
+ return -1;
+}
+
+/* redraw screen in new size */
+int on_key_resize(void)
+{
+ dialog_clear();
+ return KEY_RESIZE;
+}
+
+struct dialog_list *item_cur;
+struct dialog_list item_nil;
+struct dialog_list *item_head;
+
+void item_reset(void)
+{
+ struct dialog_list *p, *next;
+
+ for (p = item_head; p; p = next) {
+ next = p->next;
+ free(p);
+ }
+ item_head = NULL;
+ item_cur = &item_nil;
+}
+
+void item_make(const char *fmt, ...)
+{
+ va_list ap;
+ struct dialog_list *p = malloc(sizeof(*p));
+
+ if (item_head)
+ item_cur->next = p;
+ else
+ item_head = p;
+ item_cur = p;
+ memset(p, 0, sizeof(*p));
+
+ va_start(ap, fmt);
+ vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
+ va_end(ap);
+}
+
+void item_add_str(const char *fmt, ...)
+{
+ va_list ap;
+ size_t avail;
+
+ avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
+
+ va_start(ap, fmt);
+ vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
+ avail, fmt, ap);
+ item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
+ va_end(ap);
+}
+
+void item_set_tag(char tag)
+{
+ item_cur->node.tag = tag;
+}
+void item_set_data(void *ptr)
+{
+ item_cur->node.data = ptr;
+}
+
+void item_set_selected(int val)
+{
+ item_cur->node.selected = val;
+}
+
+int item_activate_selected(void)
+{
+ item_foreach()
+ if (item_is_selected())
+ return 1;
+ return 0;
+}
+
+void *item_data(void)
+{
+ return item_cur->node.data;
+}
+
+char item_tag(void)
+{
+ return item_cur->node.tag;
+}
+
+int item_count(void)
+{
+ int n = 0;
+ struct dialog_list *p;
+
+ for (p = item_head; p; p = p->next)
+ n++;
+ return n;
+}
+
+void item_set(int n)
+{
+ int i = 0;
+ item_foreach()
+ if (i++ == n)
+ return;
+}
+
+int item_n(void)
+{
+ int n = 0;
+ struct dialog_list *p;
+
+ for (p = item_head; p; p = p->next) {
+ if (p == item_cur)
+ return n;
+ n++;
+ }
+ return 0;
+}
+
+const char *item_str(void)
+{
+ return item_cur->node.str;
+}
+
+int item_is_selected(void)
+{
+ return (item_cur->node.selected != 0);
+}
+
+int item_is_tag(char tag)
+{
+ return (item_cur->node.tag == tag);
+}
diff --git a/roms/seabios/scripts/kconfig/lxdialog/yesno.c b/roms/seabios/scripts/kconfig/lxdialog/yesno.c
new file mode 100644
index 00000000..676fb2f8
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/lxdialog/yesno.c
@@ -0,0 +1,114 @@
+/*
+ * yesno.c -- implements the yes/no box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+/*
+ * Display termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+ int x = width / 2 - 10;
+ int y = height - 2;
+
+ print_button(dialog, gettext(" Yes "), y, x, selected == 0);
+ print_button(dialog, gettext(" No "), y, x + 13, selected == 1);
+
+ wmove(dialog, y, x + 1 + 13 * selected);
+ wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with two buttons - Yes and No
+ */
+int dialog_yesno(const char *title, const char *prompt, int height, int width)
+{
+ int i, x, y, key = 0, button = 0;
+ WINDOW *dialog;
+
+do_resize:
+ if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN))
+ return -ERRDISPLAYTOOSMALL;
+
+ /* center dialog box on screen */
+ x = (getmaxx(stdscr) - width) / 2;
+ y = (getmaxy(stdscr) - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ print_buttons(dialog, height, width, 0);
+
+ while (key != KEY_ESC) {
+ key = wgetch(dialog);
+ switch (key) {
+ case 'Y':
+ case 'y':
+ delwin(dialog);
+ return 0;
+ case 'N':
+ case 'n':
+ delwin(dialog);
+ return 1;
+
+ case TAB:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
+
+ print_buttons(dialog, height, width, button);
+ wrefresh(dialog);
+ break;
+ case ' ':
+ case '\n':
+ delwin(dialog);
+ return button;
+ case KEY_ESC:
+ key = on_key_esc(dialog);
+ break;
+ case KEY_RESIZE:
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
+ }
+ }
+
+ delwin(dialog);
+ return key; /* ESC pressed */
+}
diff --git a/roms/seabios/scripts/kconfig/mconf.c b/roms/seabios/scripts/kconfig/mconf.c
new file mode 100644
index 00000000..14cea746
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/mconf.c
@@ -0,0 +1,1036 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Introduced single menu mode (show all sub-menus in one large tree).
+ * 2002-11-06 Petr Baudis <pasky@ucw.cz>
+ *
+ * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <locale.h>
+
+#include "lkc.h"
+#include "lxdialog/dialog.h"
+
+static const char mconf_readme[] = N_(
+"Overview\n"
+"--------\n"
+"This interface lets you select features and parameters for the build.\n"
+"Features can either be built-in, modularized, or ignored. Parameters\n"
+"must be entered in as decimal or hexadecimal numbers or text.\n"
+"\n"
+"Menu items beginning with following braces represent features that\n"
+" [ ] can be built in or removed\n"
+" < > can be built in, modularized or removed\n"
+" { } can be built in or modularized (selected by other feature)\n"
+" - - are selected by other feature,\n"
+"while *, M or whitespace inside braces means to build in, build as\n"
+"a module or to exclude the feature respectively.\n"
+"\n"
+"To change any of these features, highlight it with the cursor\n"
+"keys and press <Y> to build it in, <M> to make it a module or\n"
+"<N> to remove it. You may also press the <Space Bar> to cycle\n"
+"through the available options (i.e. Y->N->M->Y).\n"
+"\n"
+"Some additional keyboard hints:\n"
+"\n"
+"Menus\n"
+"----------\n"
+"o Use the Up/Down arrow keys (cursor keys) to highlight the item you\n"
+" wish to change or the submenu you wish to select and press <Enter>.\n"
+" Submenus are designated by \"--->\", empty ones by \"----\".\n"
+"\n"
+" Shortcut: Press the option's highlighted letter (hotkey).\n"
+" Pressing a hotkey more than once will sequence\n"
+" through all visible items which use that hotkey.\n"
+"\n"
+" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+" unseen options into view.\n"
+"\n"
+"o To exit a menu use the cursor keys to highlight the <Exit> button\n"
+" and press <ENTER>.\n"
+"\n"
+" Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
+" using those letters. You may press a single <ESC>, but\n"
+" there is a delayed response which you may find annoying.\n"
+"\n"
+" Also, the <TAB> and cursor keys will cycle between <Select>,\n"
+" <Exit>, <Help>, <Save>, and <Load>.\n"
+"\n"
+"o To get help with an item, use the cursor keys to highlight <Help>\n"
+" and press <ENTER>.\n"
+"\n"
+" Shortcut: Press <H> or <?>.\n"
+"\n"
+"o To toggle the display of hidden options, press <Z>.\n"
+"\n"
+"\n"
+"Radiolists (Choice lists)\n"
+"-----------\n"
+"o Use the cursor keys to select the option you wish to set and press\n"
+" <S> or the <SPACE BAR>.\n"
+"\n"
+" Shortcut: Press the first letter of the option you wish to set then\n"
+" press <S> or <SPACE BAR>.\n"
+"\n"
+"o To see available help for the item, use the cursor keys to highlight\n"
+" <Help> and Press <ENTER>.\n"
+"\n"
+" Shortcut: Press <H> or <?>.\n"
+"\n"
+" Also, the <TAB> and cursor keys will cycle between <Select> and\n"
+" <Help>\n"
+"\n"
+"\n"
+"Data Entry\n"
+"-----------\n"
+"o Enter the requested information and press <ENTER>\n"
+" If you are entering hexadecimal values, it is not necessary to\n"
+" add the '0x' prefix to the entry.\n"
+"\n"
+"o For help, use the <TAB> or cursor keys to highlight the help option\n"
+" and press <ENTER>. You can try <TAB><H> as well.\n"
+"\n"
+"\n"
+"Text Box (Help Window)\n"
+"--------\n"
+"o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
+" keys h,j,k,l function here as do <u>, <d>, <SPACE BAR> and <B> for\n"
+" those who are familiar with less and lynx.\n"
+"\n"
+"o Press <E>, <X>, <q>, <Enter> or <Esc><Esc> to exit.\n"
+"\n"
+"\n"
+"Alternate Configuration Files\n"
+"-----------------------------\n"
+"Menuconfig supports the use of alternate configuration files for\n"
+"those who, for various reasons, find it necessary to switch\n"
+"between different configurations.\n"
+"\n"
+"The <Save> button will let you save the current configuration to\n"
+"a file of your choosing. Use the <Load> button to load a previously\n"
+"saved alternate configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you find\n"
+"during a Menuconfig session that you have completely messed up your\n"
+"settings, you may use the <Load> button to restore your previously\n"
+"saved settings from \".config\" without restarting Menuconfig.\n"
+"\n"
+"Other information\n"
+"-----------------\n"
+"If you use Menuconfig in an XTERM window, make sure you have your\n"
+"$TERM variable set to point to an xterm definition which supports\n"
+"color. Otherwise, Menuconfig will look rather bad. Menuconfig will\n"
+"not display correctly in an RXVT window because rxvt displays only one\n"
+"intensity of color, bright.\n"
+"\n"
+"Menuconfig will display larger menus on screens or xterms which are\n"
+"set to display more than the standard 25 row by 80 column geometry.\n"
+"In order for this to work, the \"stty size\" command must be able to\n"
+"display the screen's current row and column geometry. I STRONGLY\n"
+"RECOMMEND that you make sure you do NOT have the shell variables\n"
+"LINES and COLUMNS exported into your environment. Some distributions\n"
+"export those variables via /etc/profile. Some ncurses programs can\n"
+"become confused when those variables (LINES & COLUMNS) don't reflect\n"
+"the true screen size.\n"
+"\n"
+"Optional personality available\n"
+"------------------------------\n"
+"If you prefer to have all of the options listed in a single menu,\n"
+"rather than the default multimenu hierarchy, run the menuconfig with\n"
+"MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
+"\n"
+"make MENUCONFIG_MODE=single_menu menuconfig\n"
+"\n"
+"<Enter> will then unroll the appropriate category, or enfold it if it\n"
+"is already unrolled.\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive\n"
+"(especially with a larger number of unrolled categories) than the\n"
+"default mode.\n"
+"\n"
+"Different color themes available\n"
+"--------------------------------\n"
+"It is possible to select different color themes using the variable\n"
+"MENUCONFIG_COLOR. To select a theme use:\n"
+"\n"
+"make MENUCONFIG_COLOR=<theme> menuconfig\n"
+"\n"
+"Available themes are\n"
+" mono => selects colors suitable for monochrome displays\n"
+" blackbg => selects a color scheme with black background\n"
+" classic => theme with blue background. The classic look\n"
+" bluetitle => an LCD friendly version of classic. (default)\n"
+"\n"),
+menu_instructions[] = N_(
+ "Arrow keys navigate the menu. "
+ "<Enter> selects submenus ---> (or empty submenus ----). "
+ "Highlighted letters are hotkeys. "
+ "Pressing <Y> includes, <N> excludes, <M> modularizes features. "
+ "Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
+ "Legend: [*] built-in [ ] excluded <M> module < > module capable"),
+radiolist_instructions[] = N_(
+ "Use the arrow keys to navigate this window or "
+ "press the hotkey of the item you wish to select "
+ "followed by the <SPACE BAR>. "
+ "Press <?> for additional information about this option."),
+inputbox_instructions_int[] = N_(
+ "Please enter a decimal value. "
+ "Fractions will not be accepted. "
+ "Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_hex[] = N_(
+ "Please enter a hexadecimal value. "
+ "Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_string[] = N_(
+ "Please enter a string value. "
+ "Use the <TAB> key to move from the input field to the buttons below it."),
+setmod_text[] = N_(
+ "This feature depends on another which has been configured as a module.\n"
+ "As a result, this feature will be built as a module."),
+load_config_text[] = N_(
+ "Enter the name of the configuration file you wish to load. "
+ "Accept the name shown to restore the configuration you "
+ "last retrieved. Leave blank to abort."),
+load_config_help[] = N_(
+ "\n"
+ "For various reasons, one may wish to keep several different\n"
+ "configurations available on a single machine.\n"
+ "\n"
+ "If you have saved a previous configuration in a file other than the\n"
+ "default one, entering its name here will allow you to modify that\n"
+ "configuration.\n"
+ "\n"
+ "If you are uncertain, then you have probably never used alternate\n"
+ "configuration files. You should therefore leave this blank to abort.\n"),
+save_config_text[] = N_(
+ "Enter a filename to which this configuration should be saved "
+ "as an alternate. Leave blank to abort."),
+save_config_help[] = N_(
+ "\n"
+ "For various reasons, one may wish to keep different configurations\n"
+ "available on a single machine.\n"
+ "\n"
+ "Entering a file name here will allow you to later retrieve, modify\n"
+ "and use the current configuration as an alternate to whatever\n"
+ "configuration options you have selected at that time.\n"
+ "\n"
+ "If you are uncertain what all this means then you should probably\n"
+ "leave this blank.\n"),
+search_help[] = N_(
+ "\n"
+ "Search for symbols and display their relations.\n"
+ "Regular expressions are allowed.\n"
+ "Example: search for \"^FOO\"\n"
+ "Result:\n"
+ "-----------------------------------------------------------------\n"
+ "Symbol: FOO [=m]\n"
+ "Type : tristate\n"
+ "Prompt: Foo bus is used to drive the bar HW\n"
+ " Location:\n"
+ " -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
+ " -> PCI support (PCI [=y])\n"
+ "(1) -> PCI access mode (<choice> [=y])\n"
+ " Defined at drivers/pci/Kconfig:47\n"
+ " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+ " Selects: LIBCRC32\n"
+ " Selected by: BAR [=n]\n"
+ "-----------------------------------------------------------------\n"
+ "o The line 'Type:' shows the type of the configuration option for\n"
+ " this symbol (boolean, tristate, string, ...)\n"
+ "o The line 'Prompt:' shows the text used in the menu structure for\n"
+ " this symbol\n"
+ "o The 'Defined at' line tells at what file / line number the symbol\n"
+ " is defined\n"
+ "o The 'Depends on:' line tells what symbols need to be defined for\n"
+ " this symbol to be visible in the menu (selectable)\n"
+ "o The 'Location:' lines tells where in the menu structure this symbol\n"
+ " is located\n"
+ " A location followed by a [=y] indicates that this is a\n"
+ " selectable menu item - and the current value is displayed inside\n"
+ " brackets.\n"
+ " Press the key in the (#) prefix to jump directly to that\n"
+ " location. You will be returned to the current search results\n"
+ " after exiting this new menu.\n"
+ "o The 'Selects:' line tells what symbols will be automatically\n"
+ " selected if this symbol is selected (y or m)\n"
+ "o The 'Selected by' line tells what symbol has selected this symbol\n"
+ "\n"
+ "Only relevant lines are shown.\n"
+ "\n\n"
+ "Search examples:\n"
+ "Examples: USB => find all symbols containing USB\n"
+ " ^USB => find all symbols starting with USB\n"
+ " USB$ => find all symbols ending with USB\n"
+ "\n");
+
+static int indent;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+static int show_all_options;
+static int save_and_exit;
+
+static void conf(struct menu *menu, struct menu *active_menu);
+static void conf_choice(struct menu *menu);
+static void conf_string(struct menu *menu);
+static void conf_load(void);
+static void conf_save(void);
+static int show_textbox_ext(const char *title, char *text, int r, int c,
+ int *keys, int *vscroll, int *hscroll,
+ update_text_fn update_text, void *data);
+static void show_textbox(const char *title, const char *text, int r, int c);
+static void show_helptext(const char *title, const char *text);
+static void show_help(struct menu *menu);
+
+static char filename[PATH_MAX+1];
+static void set_config_filename(const char *config_filename)
+{
+ static char menu_backtitle[PATH_MAX+128];
+ int size;
+
+ size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+ "%s - %s", config_filename, rootmenu.prompt->text);
+ if (size >= sizeof(menu_backtitle))
+ menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+ set_dialog_backtitle(menu_backtitle);
+
+ size = snprintf(filename, sizeof(filename), "%s", config_filename);
+ if (size >= sizeof(filename))
+ filename[sizeof(filename)-1] = '\0';
+}
+
+struct subtitle_part {
+ struct list_head entries;
+ const char *text;
+};
+static LIST_HEAD(trail);
+
+static struct subtitle_list *subtitles;
+static void set_subtitle(void)
+{
+ struct subtitle_part *sp;
+ struct subtitle_list *pos, *tmp;
+
+ for (pos = subtitles; pos != NULL; pos = tmp) {
+ tmp = pos->next;
+ free(pos);
+ }
+
+ subtitles = NULL;
+ list_for_each_entry(sp, &trail, entries) {
+ if (sp->text) {
+ if (pos) {
+ pos->next = xcalloc(sizeof(*pos), 1);
+ pos = pos->next;
+ } else {
+ subtitles = pos = xcalloc(sizeof(*pos), 1);
+ }
+ pos->text = sp->text;
+ }
+ }
+
+ set_dialog_subtitles(subtitles);
+}
+
+static void reset_subtitle(void)
+{
+ struct subtitle_list *pos, *tmp;
+
+ for (pos = subtitles; pos != NULL; pos = tmp) {
+ tmp = pos->next;
+ free(pos);
+ }
+ subtitles = NULL;
+ set_dialog_subtitles(subtitles);
+}
+
+struct search_data {
+ struct list_head *head;
+ struct menu **targets;
+ int *keys;
+};
+
+static void update_text(char *buf, size_t start, size_t end, void *_data)
+{
+ struct search_data *data = _data;
+ struct jump_key *pos;
+ int k = 0;
+
+ list_for_each_entry(pos, data->head, entries) {
+ if (pos->offset >= start && pos->offset < end) {
+ char header[4];
+
+ if (k < JUMP_NB) {
+ int key = '0' + (pos->index % JUMP_NB) + 1;
+
+ sprintf(header, "(%c)", key);
+ data->keys[k] = key;
+ data->targets[k] = pos->target;
+ k++;
+ } else {
+ sprintf(header, " ");
+ }
+
+ memcpy(buf + pos->offset, header, sizeof(header) - 1);
+ }
+ }
+ data->keys[k] = 0;
+}
+
+static void search_conf(void)
+{
+ struct symbol **sym_arr;
+ struct gstr res;
+ struct gstr title;
+ char *dialog_input;
+ int dres, vscroll = 0, hscroll = 0;
+ bool again;
+ struct gstr sttext;
+ struct subtitle_part stpart;
+
+ title = str_new();
+ str_printf( &title, _("Enter (sub)string or regexp to search for "
+ "(with or without \"%s\")"), CONFIG_);
+
+again:
+ dialog_clear();
+ dres = dialog_inputbox(_("Search Configuration Parameter"),
+ str_get(&title),
+ 10, 75, "");
+ switch (dres) {
+ case 0:
+ break;
+ case 1:
+ show_helptext(_("Search Configuration"), search_help);
+ goto again;
+ default:
+ str_free(&title);
+ return;
+ }
+
+ /* strip the prefix if necessary */
+ dialog_input = dialog_input_result;
+ if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
+ dialog_input += strlen(CONFIG_);
+
+ sttext = str_new();
+ str_printf(&sttext, "Search (%s)", dialog_input_result);
+ stpart.text = str_get(&sttext);
+ list_add_tail(&stpart.entries, &trail);
+
+ sym_arr = sym_re_search(dialog_input);
+ do {
+ LIST_HEAD(head);
+ struct menu *targets[JUMP_NB];
+ int keys[JUMP_NB + 1], i;
+ struct search_data data = {
+ .head = &head,
+ .targets = targets,
+ .keys = keys,
+ };
+ struct jump_key *pos, *tmp;
+
+ res = get_relations_str(sym_arr, &head);
+ set_subtitle();
+ dres = show_textbox_ext(_("Search Results"), (char *)
+ str_get(&res), 0, 0, keys, &vscroll,
+ &hscroll, &update_text, (void *)
+ &data);
+ again = false;
+ for (i = 0; i < JUMP_NB && keys[i]; i++)
+ if (dres == keys[i]) {
+ conf(targets[i]->parent, targets[i]);
+ again = true;
+ }
+ str_free(&res);
+ list_for_each_entry_safe(pos, tmp, &head, entries)
+ free(pos);
+ } while (again);
+ free(sym_arr);
+ str_free(&title);
+ list_del(trail.prev);
+ str_free(&sttext);
+}
+
+static void build_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+ int type, tmp, doint = 2;
+ tristate val;
+ char ch;
+ bool visible;
+
+ /*
+ * note: menu_is_visible() has side effect that it will
+ * recalc the value of the symbol.
+ */
+ visible = menu_is_visible(menu);
+ if (show_all_options && !menu_has_prompt(menu))
+ return;
+ else if (!show_all_options && !visible)
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (!sym) {
+ if (prop && menu != current_menu) {
+ const char *prompt = menu_get_prompt(menu);
+ switch (prop->type) {
+ case P_MENU:
+ child_count++;
+ prompt = _(prompt);
+ if (single_menu_mode) {
+ item_make("%s%*c%s",
+ menu->data ? "-->" : "++>",
+ indent + 1, ' ', prompt);
+ } else
+ item_make(" %*c%s %s",
+ indent + 1, ' ', prompt,
+ menu_is_empty(menu) ? "----" : "--->");
+ item_set_tag('m');
+ item_set_data(menu);
+ if (single_menu_mode && menu->data)
+ goto conf_childs;
+ return;
+ case P_COMMENT:
+ if (prompt) {
+ child_count++;
+ item_make(" %*c*** %s ***", indent + 1, ' ', _(prompt));
+ item_set_tag(':');
+ item_set_data(menu);
+ }
+ break;
+ default:
+ if (prompt) {
+ child_count++;
+ item_make("---%*c%s", indent + 1, ' ', _(prompt));
+ item_set_tag(':');
+ item_set_data(menu);
+ }
+ }
+ } else
+ doint = 0;
+ goto conf_childs;
+ }
+
+ type = sym_get_type(sym);
+ if (sym_is_choice(sym)) {
+ struct symbol *def_sym = sym_get_choice_value(sym);
+ struct menu *def_menu = NULL;
+
+ child_count++;
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child) && child->sym == def_sym)
+ def_menu = child;
+ }
+
+ val = sym_get_tristate_value(sym);
+ if (sym_is_changable(sym)) {
+ switch (type) {
+ case S_BOOLEAN:
+ item_make("[%c]", val == no ? ' ' : '*');
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes: ch = '*'; break;
+ case mod: ch = 'M'; break;
+ default: ch = ' '; break;
+ }
+ item_make("<%c>", ch);
+ break;
+ }
+ item_set_tag('t');
+ item_set_data(menu);
+ } else {
+ item_make(" ");
+ item_set_tag(def_menu ? 't' : ':');
+ item_set_data(menu);
+ }
+
+ item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
+ if (val == yes) {
+ if (def_menu) {
+ item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
+ item_add_str(" --->");
+ if (def_menu->list) {
+ indent += 2;
+ build_conf(def_menu);
+ indent -= 2;
+ }
+ }
+ return;
+ }
+ } else {
+ if (menu == current_menu) {
+ item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
+ item_set_tag(':');
+ item_set_data(menu);
+ goto conf_childs;
+ }
+ child_count++;
+ val = sym_get_tristate_value(sym);
+ if (sym_is_choice_value(sym) && val == yes) {
+ item_make(" ");
+ item_set_tag(':');
+ item_set_data(menu);
+ } else {
+ switch (type) {
+ case S_BOOLEAN:
+ if (sym_is_changable(sym))
+ item_make("[%c]", val == no ? ' ' : '*');
+ else
+ item_make("-%c-", val == no ? ' ' : '*');
+ item_set_tag('t');
+ item_set_data(menu);
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes: ch = '*'; break;
+ case mod: ch = 'M'; break;
+ default: ch = ' '; break;
+ }
+ if (sym_is_changable(sym)) {
+ if (sym->rev_dep.tri == mod)
+ item_make("{%c}", ch);
+ else
+ item_make("<%c>", ch);
+ } else
+ item_make("-%c-", ch);
+ item_set_tag('t');
+ item_set_data(menu);
+ break;
+ default:
+ tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
+ item_make("(%s)", sym_get_string_value(sym));
+ tmp = indent - tmp + 4;
+ if (tmp < 0)
+ tmp = 0;
+ item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
+ (sym_has_value(sym) || !sym_is_changable(sym)) ?
+ "" : _(" (NEW)"));
+ item_set_tag('s');
+ item_set_data(menu);
+ goto conf_childs;
+ }
+ }
+ item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
+ (sym_has_value(sym) || !sym_is_changable(sym)) ?
+ "" : _(" (NEW)"));
+ if (menu->prompt->type == P_MENU) {
+ item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->");
+ return;
+ }
+ }
+
+conf_childs:
+ indent += doint;
+ for (child = menu->list; child; child = child->next)
+ build_conf(child);
+ indent -= doint;
+}
+
+static void conf(struct menu *menu, struct menu *active_menu)
+{
+ struct menu *submenu;
+ const char *prompt = menu_get_prompt(menu);
+ struct subtitle_part stpart;
+ struct symbol *sym;
+ int res;
+ int s_scroll = 0;
+
+ if (menu != &rootmenu)
+ stpart.text = menu_get_prompt(menu);
+ else
+ stpart.text = NULL;
+ list_add_tail(&stpart.entries, &trail);
+
+ while (1) {
+ item_reset();
+ current_menu = menu;
+ build_conf(menu);
+ if (!child_count)
+ break;
+ set_subtitle();
+ dialog_clear();
+ res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
+ _(menu_instructions),
+ active_menu, &s_scroll);
+ if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
+ break;
+ if (item_count() != 0) {
+ if (!item_activate_selected())
+ continue;
+ if (!item_tag())
+ continue;
+ }
+ submenu = item_data();
+ active_menu = item_data();
+ if (submenu)
+ sym = submenu->sym;
+ else
+ sym = NULL;
+
+ switch (res) {
+ case 0:
+ switch (item_tag()) {
+ case 'm':
+ if (single_menu_mode)
+ submenu->data = (void *) (long) !submenu->data;
+ else
+ conf(submenu, NULL);
+ break;
+ case 't':
+ if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
+ conf_choice(submenu);
+ else if (submenu->prompt->type == P_MENU)
+ conf(submenu, NULL);
+ break;
+ case 's':
+ conf_string(submenu);
+ break;
+ }
+ break;
+ case 2:
+ if (sym)
+ show_help(submenu);
+ else {
+ reset_subtitle();
+ show_helptext(_("README"), _(mconf_readme));
+ }
+ break;
+ case 3:
+ reset_subtitle();
+ conf_save();
+ break;
+ case 4:
+ reset_subtitle();
+ conf_load();
+ break;
+ case 5:
+ if (item_is_tag('t')) {
+ if (sym_set_tristate_value(sym, yes))
+ break;
+ if (sym_set_tristate_value(sym, mod))
+ show_textbox(NULL, setmod_text, 6, 74);
+ }
+ break;
+ case 6:
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, no);
+ break;
+ case 7:
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, mod);
+ break;
+ case 8:
+ if (item_is_tag('t'))
+ sym_toggle_tristate_value(sym);
+ else if (item_is_tag('m'))
+ conf(submenu, NULL);
+ break;
+ case 9:
+ search_conf();
+ break;
+ case 10:
+ show_all_options = !show_all_options;
+ break;
+ }
+ }
+
+ list_del(trail.prev);
+}
+
+static int show_textbox_ext(const char *title, char *text, int r, int c, int
+ *keys, int *vscroll, int *hscroll, update_text_fn
+ update_text, void *data)
+{
+ dialog_clear();
+ return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
+ update_text, data);
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+ show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
+ NULL, NULL);
+}
+
+static void show_helptext(const char *title, const char *text)
+{
+ show_textbox(title, text, 0, 0);
+}
+
+static void conf_message_callback(const char *fmt, va_list ap)
+{
+ char buf[PATH_MAX+1];
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ if (save_and_exit)
+ printf("%s", buf);
+ else
+ show_textbox(NULL, buf, 6, 60);
+}
+
+static void show_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+
+ help.max_width = getmaxx(stdscr) - 10;
+ menu_get_ext_help(menu, &help);
+
+ show_helptext(_(menu_get_prompt(menu)), str_get(&help));
+ str_free(&help);
+}
+
+static void conf_choice(struct menu *menu)
+{
+ const char *prompt = _(menu_get_prompt(menu));
+ struct menu *child;
+ struct symbol *active;
+
+ active = sym_get_choice_value(menu->sym);
+ while (1) {
+ int res;
+ int selected;
+ item_reset();
+
+ current_menu = menu;
+ for (child = menu->list; child; child = child->next) {
+ if (!menu_is_visible(child))
+ continue;
+ if (child->sym)
+ item_make("%s", _(menu_get_prompt(child)));
+ else {
+ item_make("*** %s ***", _(menu_get_prompt(child)));
+ item_set_tag(':');
+ }
+ item_set_data(child);
+ if (child->sym == active)
+ item_set_selected(1);
+ if (child->sym == sym_get_choice_value(menu->sym))
+ item_set_tag('X');
+ }
+ dialog_clear();
+ res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
+ _(radiolist_instructions),
+ MENUBOX_HEIGTH_MIN,
+ MENUBOX_WIDTH_MIN,
+ CHECKLIST_HEIGTH_MIN);
+ selected = item_activate_selected();
+ switch (res) {
+ case 0:
+ if (selected) {
+ child = item_data();
+ if (!child->sym)
+ break;
+
+ sym_set_tristate_value(child->sym, yes);
+ }
+ return;
+ case 1:
+ if (selected) {
+ child = item_data();
+ show_help(child);
+ active = child->sym;
+ } else
+ show_help(menu);
+ break;
+ case KEY_ESC:
+ return;
+ case -ERRDISPLAYTOOSMALL:
+ return;
+ }
+ }
+}
+
+static void conf_string(struct menu *menu)
+{
+ const char *prompt = menu_get_prompt(menu);
+
+ while (1) {
+ int res;
+ const char *heading;
+
+ switch (sym_get_type(menu->sym)) {
+ case S_INT:
+ heading = _(inputbox_instructions_int);
+ break;
+ case S_HEX:
+ heading = _(inputbox_instructions_hex);
+ break;
+ case S_STRING:
+ heading = _(inputbox_instructions_string);
+ break;
+ default:
+ heading = _("Internal mconf error!");
+ }
+ dialog_clear();
+ res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
+ heading, 10, 75,
+ sym_get_string_value(menu->sym));
+ switch (res) {
+ case 0:
+ if (sym_set_string_value(menu->sym, dialog_input_result))
+ return;
+ show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
+ break;
+ case 1:
+ show_help(menu);
+ break;
+ case KEY_ESC:
+ return;
+ }
+ }
+}
+
+static void conf_load(void)
+{
+
+ while (1) {
+ int res;
+ dialog_clear();
+ res = dialog_inputbox(NULL, load_config_text,
+ 11, 55, filename);
+ switch(res) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ if (!conf_read(dialog_input_result)) {
+ set_config_filename(dialog_input_result);
+ sym_set_change_count(1);
+ return;
+ }
+ show_textbox(NULL, _("File does not exist!"), 5, 38);
+ break;
+ case 1:
+ show_helptext(_("Load Alternate Configuration"), load_config_help);
+ break;
+ case KEY_ESC:
+ return;
+ }
+ }
+}
+
+static void conf_save(void)
+{
+ while (1) {
+ int res;
+ dialog_clear();
+ res = dialog_inputbox(NULL, save_config_text,
+ 11, 55, filename);
+ switch(res) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ if (!conf_write(dialog_input_result)) {
+ set_config_filename(dialog_input_result);
+ return;
+ }
+ show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
+ break;
+ case 1:
+ show_helptext(_("Save Alternate Configuration"), save_config_help);
+ break;
+ case KEY_ESC:
+ return;
+ }
+ }
+}
+
+static int handle_exit(void)
+{
+ int res;
+
+ save_and_exit = 1;
+ reset_subtitle();
+ dialog_clear();
+ if (conf_get_changed())
+ res = dialog_yesno(NULL,
+ _("Do you wish to save your new configuration?\n"
+ "(Press <ESC><ESC> to continue kernel configuration.)"),
+ 6, 60);
+ else
+ res = -1;
+
+ end_dialog(saved_x, saved_y);
+
+ switch (res) {
+ case 0:
+ if (conf_write(filename)) {
+ fprintf(stderr, _("\n\n"
+ "Error while writing of the configuration.\n"
+ "Your configuration changes were NOT saved."
+ "\n\n"));
+ return 1;
+ }
+ /* fall through */
+ case -1:
+ printf(_("\n\n"
+ "*** End of the configuration.\n"
+ "*** Execute 'make' to start the build or try 'make help'."
+ "\n\n"));
+ res = 0;
+ break;
+ default:
+ fprintf(stderr, _("\n\n"
+ "Your configuration changes were NOT saved."
+ "\n\n"));
+ if (res != KEY_ESC)
+ res = 0;
+ }
+
+ return res;
+}
+
+static void sig_handler(int signo)
+{
+ exit(handle_exit());
+}
+
+int main(int ac, char **av)
+{
+ char *mode;
+ int res;
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ signal(SIGINT, sig_handler);
+
+ conf_parse(av[1]);
+ conf_read(NULL);
+
+ mode = getenv("MENUCONFIG_MODE");
+ if (mode) {
+ if (!strcasecmp(mode, "single_menu"))
+ single_menu_mode = 1;
+ }
+
+ if (init_dialog(NULL)) {
+ fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
+ fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
+ return 1;
+ }
+
+ set_config_filename(conf_get_configname());
+ conf_set_message_callback(conf_message_callback);
+ do {
+ conf(&rootmenu, NULL);
+ res = handle_exit();
+ } while (res == KEY_ESC);
+
+ return res;
+}
diff --git a/roms/seabios/scripts/kconfig/menu.c b/roms/seabios/scripts/kconfig/menu.c
new file mode 100644
index 00000000..a26cc5d2
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/menu.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lkc.h"
+
+static const char nohelp_text[] = "There is no help available for this option.";
+
+struct menu rootmenu;
+static struct menu **last_entry_ptr;
+
+struct file *file_list;
+struct file *current_file;
+
+void menu_warn(struct menu *menu, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+static void prop_warn(struct property *prop, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+void _menu_init(void)
+{
+ current_entry = current_menu = &rootmenu;
+ last_entry_ptr = &rootmenu.list;
+}
+
+void menu_add_entry(struct symbol *sym)
+{
+ struct menu *menu;
+
+ menu = xmalloc(sizeof(*menu));
+ memset(menu, 0, sizeof(*menu));
+ menu->sym = sym;
+ menu->parent = current_menu;
+ menu->file = current_file;
+ menu->lineno = zconf_lineno();
+
+ *last_entry_ptr = menu;
+ last_entry_ptr = &menu->next;
+ current_entry = menu;
+ if (sym)
+ menu_add_symbol(P_SYMBOL, sym, NULL);
+}
+
+void menu_end_entry(void)
+{
+}
+
+struct menu *menu_add_menu(void)
+{
+ menu_end_entry();
+ last_entry_ptr = &current_entry->list;
+ return current_menu = current_entry;
+}
+
+void menu_end_menu(void)
+{
+ last_entry_ptr = &current_menu->next;
+ current_menu = current_menu->parent;
+}
+
+static struct expr *menu_check_dep(struct expr *e)
+{
+ if (!e)
+ return e;
+
+ switch (e->type) {
+ case E_NOT:
+ e->left.expr = menu_check_dep(e->left.expr);
+ break;
+ case E_OR:
+ case E_AND:
+ e->left.expr = menu_check_dep(e->left.expr);
+ e->right.expr = menu_check_dep(e->right.expr);
+ break;
+ case E_SYMBOL:
+ /* change 'm' into 'm' && MODULES */
+ if (e->left.sym == &symbol_mod)
+ return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
+ break;
+ default:
+ break;
+ }
+ return e;
+}
+
+void menu_add_dep(struct expr *dep)
+{
+ current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
+}
+
+void menu_set_type(int type)
+{
+ struct symbol *sym = current_entry->sym;
+
+ if (sym->type == type)
+ return;
+ if (sym->type == S_UNKNOWN) {
+ sym->type = type;
+ return;
+ }
+ menu_warn(current_entry,
+ "ignoring type redefinition of '%s' from '%s' to '%s'",
+ sym->name ? sym->name : "<choice>",
+ sym_type_name(sym->type), sym_type_name(type));
+}
+
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
+{
+ struct property *prop = prop_alloc(type, current_entry->sym);
+
+ prop->menu = current_entry;
+ prop->expr = expr;
+ prop->visible.expr = menu_check_dep(dep);
+
+ if (prompt) {
+ if (isspace(*prompt)) {
+ prop_warn(prop, "leading whitespace ignored");
+ while (isspace(*prompt))
+ prompt++;
+ }
+ if (current_entry->prompt && current_entry != &rootmenu)
+ prop_warn(prop, "prompt redefined");
+
+ /* Apply all upper menus' visibilities to actual prompts. */
+ if(type == P_PROMPT) {
+ struct menu *menu = current_entry;
+
+ while ((menu = menu->parent) != NULL) {
+ struct expr *dup_expr;
+
+ if (!menu->visibility)
+ continue;
+ /*
+ * Do not add a reference to the
+ * menu's visibility expression but
+ * use a copy of it. Otherwise the
+ * expression reduction functions
+ * will modify expressions that have
+ * multiple references which can
+ * cause unwanted side effects.
+ */
+ dup_expr = expr_copy(menu->visibility);
+
+ prop->visible.expr
+ = expr_alloc_and(prop->visible.expr,
+ dup_expr);
+ }
+ }
+
+ current_entry->prompt = prop;
+ }
+ prop->text = prompt;
+
+ return prop;
+}
+
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
+{
+ return menu_add_prop(type, prompt, NULL, dep);
+}
+
+void menu_add_visibility(struct expr *expr)
+{
+ current_entry->visibility = expr_alloc_and(current_entry->visibility,
+ expr);
+}
+
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
+{
+ menu_add_prop(type, NULL, expr, dep);
+}
+
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
+{
+ menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
+}
+
+void menu_add_option(int token, char *arg)
+{
+ switch (token) {
+ case T_OPT_MODULES:
+ if (modules_sym)
+ zconf_error("symbol '%s' redefines option 'modules'"
+ " already defined by symbol '%s'",
+ current_entry->sym->name,
+ modules_sym->name
+ );
+ modules_sym = current_entry->sym;
+ break;
+ case T_OPT_DEFCONFIG_LIST:
+ if (!sym_defconfig_list)
+ sym_defconfig_list = current_entry->sym;
+ else if (sym_defconfig_list != current_entry->sym)
+ zconf_error("trying to redefine defconfig symbol");
+ break;
+ case T_OPT_ENV:
+ prop_add_env(arg);
+ break;
+ case T_OPT_ALLNOCONFIG_Y:
+ current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
+ break;
+ }
+}
+
+static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
+{
+ return sym2->type == S_INT || sym2->type == S_HEX ||
+ (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
+}
+
+static void sym_check_prop(struct symbol *sym)
+{
+ struct property *prop;
+ struct symbol *sym2;
+ for (prop = sym->prop; prop; prop = prop->next) {
+ switch (prop->type) {
+ case P_DEFAULT:
+ if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
+ prop->expr->type != E_SYMBOL)
+ prop_warn(prop,
+ "default for config symbol '%s'"
+ " must be a single symbol", sym->name);
+ if (prop->expr->type != E_SYMBOL)
+ break;
+ sym2 = prop_get_symbol(prop);
+ if (sym->type == S_HEX || sym->type == S_INT) {
+ if (!menu_validate_number(sym, sym2))
+ prop_warn(prop,
+ "'%s': number is invalid",
+ sym->name);
+ }
+ break;
+ case P_SELECT:
+ sym2 = prop_get_symbol(prop);
+ if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
+ prop_warn(prop,
+ "config symbol '%s' uses select, but is "
+ "not boolean or tristate", sym->name);
+ else if (sym2->type != S_UNKNOWN &&
+ sym2->type != S_BOOLEAN &&
+ sym2->type != S_TRISTATE)
+ prop_warn(prop,
+ "'%s' has wrong type. 'select' only "
+ "accept arguments of boolean and "
+ "tristate type", sym2->name);
+ break;
+ case P_RANGE:
+ if (sym->type != S_INT && sym->type != S_HEX)
+ prop_warn(prop, "range is only allowed "
+ "for int or hex symbols");
+ if (!menu_validate_number(sym, prop->expr->left.sym) ||
+ !menu_validate_number(sym, prop->expr->right.sym))
+ prop_warn(prop, "range is invalid");
+ break;
+ default:
+ ;
+ }
+ }
+}
+
+void menu_finalize(struct menu *parent)
+{
+ struct menu *menu, *last_menu;
+ struct symbol *sym;
+ struct property *prop;
+ struct expr *parentdep, *basedep, *dep, *dep2, **ep;
+
+ sym = parent->sym;
+ if (parent->list) {
+ if (sym && sym_is_choice(sym)) {
+ if (sym->type == S_UNKNOWN) {
+ /* find the first choice value to find out choice type */
+ current_entry = parent;
+ for (menu = parent->list; menu; menu = menu->next) {
+ if (menu->sym && menu->sym->type != S_UNKNOWN) {
+ menu_set_type(menu->sym->type);
+ break;
+ }
+ }
+ }
+ /* set the type of the remaining choice values */
+ for (menu = parent->list; menu; menu = menu->next) {
+ current_entry = menu;
+ if (menu->sym && menu->sym->type == S_UNKNOWN)
+ menu_set_type(sym->type);
+ }
+ parentdep = expr_alloc_symbol(sym);
+ } else if (parent->prompt)
+ parentdep = parent->prompt->visible.expr;
+ else
+ parentdep = parent->dep;
+
+ for (menu = parent->list; menu; menu = menu->next) {
+ basedep = expr_transform(menu->dep);
+ basedep = expr_alloc_and(expr_copy(parentdep), basedep);
+ basedep = expr_eliminate_dups(basedep);
+ menu->dep = basedep;
+ if (menu->sym)
+ prop = menu->sym->prop;
+ else
+ prop = menu->prompt;
+ for (; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ dep = expr_transform(prop->visible.expr);
+ dep = expr_alloc_and(expr_copy(basedep), dep);
+ dep = expr_eliminate_dups(dep);
+ if (menu->sym && menu->sym->type != S_TRISTATE)
+ dep = expr_trans_bool(dep);
+ prop->visible.expr = dep;
+ if (prop->type == P_SELECT) {
+ struct symbol *es = prop_get_symbol(prop);
+ es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
+ expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
+ }
+ }
+ }
+ for (menu = parent->list; menu; menu = menu->next)
+ menu_finalize(menu);
+ } else if (sym) {
+ basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
+ basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
+ basedep = expr_eliminate_dups(expr_transform(basedep));
+ last_menu = NULL;
+ for (menu = parent->next; menu; menu = menu->next) {
+ dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
+ if (!expr_contains_symbol(dep, sym))
+ break;
+ if (expr_depends_symbol(dep, sym))
+ goto next;
+ dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
+ dep = expr_eliminate_dups(expr_transform(dep));
+ dep2 = expr_copy(basedep);
+ expr_eliminate_eq(&dep, &dep2);
+ expr_free(dep);
+ if (!expr_is_yes(dep2)) {
+ expr_free(dep2);
+ break;
+ }
+ expr_free(dep2);
+ next:
+ menu_finalize(menu);
+ menu->parent = parent;
+ last_menu = menu;
+ }
+ if (last_menu) {
+ parent->list = parent->next;
+ parent->next = last_menu->next;
+ last_menu->next = NULL;
+ }
+
+ sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
+ }
+ for (menu = parent->list; menu; menu = menu->next) {
+ if (sym && sym_is_choice(sym) &&
+ menu->sym && !sym_is_choice_value(menu->sym)) {
+ current_entry = menu;
+ menu->sym->flags |= SYMBOL_CHOICEVAL;
+ if (!menu->prompt)
+ menu_warn(menu, "choice value must have a prompt");
+ for (prop = menu->sym->prop; prop; prop = prop->next) {
+ if (prop->type == P_DEFAULT)
+ prop_warn(prop, "defaults for choice "
+ "values not supported");
+ if (prop->menu == menu)
+ continue;
+ if (prop->type == P_PROMPT &&
+ prop->menu->parent->sym != sym)
+ prop_warn(prop, "choice value used outside its choice group");
+ }
+ /* Non-tristate choice values of tristate choices must
+ * depend on the choice being set to Y. The choice
+ * values' dependencies were propagated to their
+ * properties above, so the change here must be re-
+ * propagated.
+ */
+ if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
+ basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
+ menu->dep = expr_alloc_and(basedep, menu->dep);
+ for (prop = menu->sym->prop; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ prop->visible.expr = expr_alloc_and(expr_copy(basedep),
+ prop->visible.expr);
+ }
+ }
+ menu_add_symbol(P_CHOICE, sym, NULL);
+ prop = sym_get_choice_prop(sym);
+ for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
+ ;
+ *ep = expr_alloc_one(E_LIST, NULL);
+ (*ep)->right.sym = menu->sym;
+ }
+ if (menu->list && (!menu->prompt || !menu->prompt->text)) {
+ for (last_menu = menu->list; ; last_menu = last_menu->next) {
+ last_menu->parent = parent;
+ if (!last_menu->next)
+ break;
+ }
+ last_menu->next = menu->next;
+ menu->next = menu->list;
+ menu->list = NULL;
+ }
+ }
+
+ if (sym && !(sym->flags & SYMBOL_WARNED)) {
+ if (sym->type == S_UNKNOWN)
+ menu_warn(parent, "config symbol defined without type");
+
+ if (sym_is_choice(sym) && !parent->prompt)
+ menu_warn(parent, "choice must have a prompt");
+
+ /* Check properties connected to this symbol */
+ sym_check_prop(sym);
+ sym->flags |= SYMBOL_WARNED;
+ }
+
+ if (sym && !sym_is_optional(sym) && parent->prompt) {
+ sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
+ expr_alloc_and(parent->prompt->visible.expr,
+ expr_alloc_symbol(&symbol_mod)));
+ }
+}
+
+bool menu_has_prompt(struct menu *menu)
+{
+ if (!menu->prompt)
+ return false;
+ return true;
+}
+
+/*
+ * Determine if a menu is empty.
+ * A menu is considered empty if it contains no or only
+ * invisible entries.
+ */
+bool menu_is_empty(struct menu *menu)
+{
+ struct menu *child;
+
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child))
+ return(false);
+ }
+ return(true);
+}
+
+bool menu_is_visible(struct menu *menu)
+{
+ struct menu *child;
+ struct symbol *sym;
+ tristate visible;
+
+ if (!menu->prompt)
+ return false;
+
+ if (menu->visibility) {
+ if (expr_calc_value(menu->visibility) == no)
+ return no;
+ }
+
+ sym = menu->sym;
+ if (sym) {
+ sym_calc_value(sym);
+ visible = menu->prompt->visible.tri;
+ } else
+ visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
+
+ if (visible != no)
+ return true;
+
+ if (!sym || sym_get_tristate_value(menu->sym) == no)
+ return false;
+
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child)) {
+ if (sym)
+ sym->flags |= SYMBOL_DEF_USER;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const char *menu_get_prompt(struct menu *menu)
+{
+ if (menu->prompt)
+ return menu->prompt->text;
+ else if (menu->sym)
+ return menu->sym->name;
+ return NULL;
+}
+
+struct menu *menu_get_root_menu(struct menu *menu)
+{
+ return &rootmenu;
+}
+
+struct menu *menu_get_parent_menu(struct menu *menu)
+{
+ enum prop_type type;
+
+ for (; menu != &rootmenu; menu = menu->parent) {
+ type = menu->prompt ? menu->prompt->type : 0;
+ if (type == P_MENU)
+ break;
+ }
+ return menu;
+}
+
+bool menu_has_help(struct menu *menu)
+{
+ return menu->help != NULL;
+}
+
+const char *menu_get_help(struct menu *menu)
+{
+ if (menu->help)
+ return menu->help;
+ else
+ return "";
+}
+
+static void get_prompt_str(struct gstr *r, struct property *prop,
+ struct list_head *head)
+{
+ int i, j;
+ struct menu *submenu[8], *menu, *location = NULL;
+ struct jump_key *jump;
+
+ str_printf(r, _("Prompt: %s\n"), _(prop->text));
+ menu = prop->menu->parent;
+ for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
+ bool accessible = menu_is_visible(menu);
+
+ submenu[i++] = menu;
+ if (location == NULL && accessible)
+ location = menu;
+ }
+ if (head && location) {
+ jump = xmalloc(sizeof(struct jump_key));
+
+ if (menu_is_visible(prop->menu)) {
+ /*
+ * There is not enough room to put the hint at the
+ * beginning of the "Prompt" line. Put the hint on the
+ * last "Location" line even when it would belong on
+ * the former.
+ */
+ jump->target = prop->menu;
+ } else
+ jump->target = location;
+
+ if (list_empty(head))
+ jump->index = 0;
+ else
+ jump->index = list_entry(head->prev, struct jump_key,
+ entries)->index + 1;
+
+ list_add_tail(&jump->entries, head);
+ }
+
+ if (i > 0) {
+ str_printf(r, _(" Location:\n"));
+ for (j = 4; --i >= 0; j += 2) {
+ menu = submenu[i];
+ if (head && location && menu == location)
+ jump->offset = strlen(r->s);
+ str_printf(r, "%*c-> %s", j, ' ',
+ _(menu_get_prompt(menu)));
+ if (menu->sym) {
+ str_printf(r, " (%s [=%s])", menu->sym->name ?
+ menu->sym->name : _("<choice>"),
+ sym_get_string_value(menu->sym));
+ }
+ str_append(r, "\n");
+ }
+ }
+}
+
+/*
+ * get property of type P_SYMBOL
+ */
+static struct property *get_symbol_prop(struct symbol *sym)
+{
+ struct property *prop = NULL;
+
+ for_all_properties(sym, prop, P_SYMBOL)
+ break;
+ return prop;
+}
+
+/*
+ * head is optional and may be NULL
+ */
+void get_symbol_str(struct gstr *r, struct symbol *sym,
+ struct list_head *head)
+{
+ bool hit;
+ struct property *prop;
+
+ if (sym && sym->name) {
+ str_printf(r, "Symbol: %s [=%s]\n", sym->name,
+ sym_get_string_value(sym));
+ str_printf(r, "Type : %s\n", sym_type_name(sym->type));
+ if (sym->type == S_INT || sym->type == S_HEX) {
+ prop = sym_get_range_prop(sym);
+ if (prop) {
+ str_printf(r, "Range : ");
+ expr_gstr_print(prop->expr, r);
+ str_append(r, "\n");
+ }
+ }
+ }
+ for_all_prompts(sym, prop)
+ get_prompt_str(r, prop, head);
+
+ prop = get_symbol_prop(sym);
+ if (prop) {
+ str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
+ prop->menu->lineno);
+ if (!expr_is_yes(prop->visible.expr)) {
+ str_append(r, _(" Depends on: "));
+ expr_gstr_print(prop->visible.expr, r);
+ str_append(r, "\n");
+ }
+ }
+
+ hit = false;
+ for_all_properties(sym, prop, P_SELECT) {
+ if (!hit) {
+ str_append(r, " Selects: ");
+ hit = true;
+ } else
+ str_printf(r, " && ");
+ expr_gstr_print(prop->expr, r);
+ }
+ if (hit)
+ str_append(r, "\n");
+ if (sym->rev_dep.expr) {
+ str_append(r, _(" Selected by: "));
+ expr_gstr_print(sym->rev_dep.expr, r);
+ str_append(r, "\n");
+ }
+ str_append(r, "\n\n");
+}
+
+struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
+{
+ struct symbol *sym;
+ struct gstr res = str_new();
+ int i;
+
+ for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
+ get_symbol_str(&res, sym, head);
+ if (!i)
+ str_append(&res, _("No matches found.\n"));
+ return res;
+}
+
+
+void menu_get_ext_help(struct menu *menu, struct gstr *help)
+{
+ struct symbol *sym = menu->sym;
+ const char *help_text = nohelp_text;
+
+ if (menu_has_help(menu)) {
+ if (sym->name)
+ str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
+ help_text = menu_get_help(menu);
+ }
+ str_printf(help, "%s\n", _(help_text));
+ if (sym)
+ get_symbol_str(help, sym, NULL);
+}
diff --git a/roms/seabios/scripts/kconfig/merge_config.sh b/roms/seabios/scripts/kconfig/merge_config.sh
new file mode 100755
index 00000000..81b0c61b
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/merge_config.sh
@@ -0,0 +1,150 @@
+#!/bin/sh
+# merge_config.sh - Takes a list of config fragment values, and merges
+# them one by one. Provides warnings on overridden values, and specified
+# values that did not make it to the resulting .config file (due to missed
+# dependencies or config symbol removal).
+#
+# Portions reused from kconf_check and generate_cfg:
+# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/kconf_check
+# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/generate_cfg
+#
+# Copyright (c) 2009-2010 Wind River Systems, Inc.
+# Copyright 2011 Linaro
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+
+clean_up() {
+ rm -f $TMP_FILE
+ exit
+}
+trap clean_up HUP INT TERM
+
+usage() {
+ echo "Usage: $0 [OPTIONS] [CONFIG [...]]"
+ echo " -h display this help text"
+ echo " -m only merge the fragments, do not execute the make command"
+ echo " -n use allnoconfig instead of alldefconfig"
+ echo " -r list redundant entries when merging fragments"
+ echo " -O dir to put generated output files"
+}
+
+MAKE=true
+ALLTARGET=alldefconfig
+WARNREDUN=false
+OUTPUT=.
+
+while true; do
+ case $1 in
+ "-n")
+ ALLTARGET=allnoconfig
+ shift
+ continue
+ ;;
+ "-m")
+ MAKE=false
+ shift
+ continue
+ ;;
+ "-h")
+ usage
+ exit
+ ;;
+ "-r")
+ WARNREDUN=true
+ shift
+ continue
+ ;;
+ "-O")
+ if [ -d $2 ];then
+ OUTPUT=$(echo $2 | sed 's/\/*$//')
+ else
+ echo "output directory $2 does not exist" 1>&2
+ exit 1
+ fi
+ shift 2
+ continue
+ ;;
+ *)
+ break
+ ;;
+ esac
+done
+
+INITFILE=$1
+shift;
+
+MERGE_LIST=$*
+SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p"
+TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
+
+echo "Using $INITFILE as base"
+cat $INITFILE > $TMP_FILE
+
+# Merge files, printing warnings on overrided values
+for MERGE_FILE in $MERGE_LIST ; do
+ echo "Merging $MERGE_FILE"
+ CFG_LIST=$(sed -n "$SED_CONFIG_EXP" $MERGE_FILE)
+
+ for CFG in $CFG_LIST ; do
+ grep -q -w $CFG $TMP_FILE
+ if [ $? -eq 0 ] ; then
+ PREV_VAL=$(grep -w $CFG $TMP_FILE)
+ NEW_VAL=$(grep -w $CFG $MERGE_FILE)
+ if [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then
+ echo Value of $CFG is redefined by fragment $MERGE_FILE:
+ echo Previous value: $PREV_VAL
+ echo New value: $NEW_VAL
+ echo
+ elif [ "$WARNREDUN" = "true" ]; then
+ echo Value of $CFG is redundant by fragment $MERGE_FILE:
+ fi
+ sed -i "/$CFG[ =]/d" $TMP_FILE
+ fi
+ done
+ cat $MERGE_FILE >> $TMP_FILE
+done
+
+if [ "$MAKE" = "false" ]; then
+ cp $TMP_FILE $OUTPUT/.config
+ echo "#"
+ echo "# merged configuration written to $OUTPUT/.config (needs make)"
+ echo "#"
+ clean_up
+ exit
+fi
+
+# If we have an output dir, setup the O= argument, otherwise leave
+# it blank, since O=. will create an unnecessary ./source softlink
+OUTPUT_ARG=""
+if [ "$OUTPUT" != "." ] ; then
+ OUTPUT_ARG="O=$OUTPUT"
+fi
+
+
+# Use the merged file as the starting point for:
+# alldefconfig: Fills in any missing symbols with Kconfig default
+# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set
+make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
+
+
+# Check all specified config values took (might have missed-dependency issues)
+for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do
+
+ REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE)
+ ACTUAL_VAL=$(grep -w -e "$CFG" $OUTPUT/.config)
+ if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then
+ echo "Value requested for $CFG not in final .config"
+ echo "Requested value: $REQUESTED_VAL"
+ echo "Actual value: $ACTUAL_VAL"
+ echo ""
+ fi
+done
+
+clean_up
diff --git a/roms/seabios/scripts/kconfig/nconf.c b/roms/seabios/scripts/kconfig/nconf.c
new file mode 100644
index 00000000..984489ef
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/nconf.c
@@ -0,0 +1,1556 @@
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+
+#include "lkc.h"
+#include "nconf.h"
+#include <ctype.h>
+
+static const char nconf_global_help[] = N_(
+"Help windows\n"
+"------------\n"
+"o Global help: Unless in a data entry window, pressing <F1> will give \n"
+" you the global help window, which you are just reading.\n"
+"\n"
+"o A short version of the global help is available by pressing <F3>.\n"
+"\n"
+"o Local help: To get help related to the current menu entry, use any\n"
+" of <?> <h>, or if in a data entry window then press <F1>.\n"
+"\n"
+"\n"
+"Menu entries\n"
+"------------\n"
+"This interface lets you select features and parameters for the kernel\n"
+"build. Kernel features can either be built-in, modularized, or removed.\n"
+"Parameters must be entered as text or decimal or hexadecimal numbers.\n"
+"\n"
+"Menu entries beginning with following braces represent features that\n"
+" [ ] can be built in or removed\n"
+" < > can be built in, modularized or removed\n"
+" { } can be built in or modularized, are selected by another feature\n"
+" - - are selected by another feature\n"
+" XXX cannot be selected. Symbol Info <F2> tells you why.\n"
+"*, M or whitespace inside braces means to build in, build as a module\n"
+"or to exclude the feature respectively.\n"
+"\n"
+"To change any of these features, highlight it with the movement keys\n"
+"listed below and press <y> to build it in, <m> to make it a module or\n"
+"<n> to remove it. You may press the <Space> key to cycle through the\n"
+"available options.\n"
+"\n"
+"A trailing \"--->\" designates a submenu, a trailing \"----\" an\n"
+"empty submenu.\n"
+"\n"
+"Menu navigation keys\n"
+"----------------------------------------------------------------------\n"
+"Linewise up <Up>\n"
+"Linewise down <Down>\n"
+"Pagewise up <Page Up>\n"
+"Pagewise down <Page Down>\n"
+"First entry <Home>\n"
+"Last entry <End>\n"
+"Enter a submenu <Right> <Enter>\n"
+"Go back to parent menu <Left> <Esc> <F5>\n"
+"Close a help window <Enter> <Esc> <F5>\n"
+"Close entry window, apply <Enter>\n"
+"Close entry window, forget <Esc> <F5>\n"
+"Start incremental, case-insensitive search for STRING in menu entries,\n"
+" no regex support, STRING is displayed in upper left corner\n"
+" </>STRING\n"
+" Remove last character <Backspace>\n"
+" Jump to next hit <Down>\n"
+" Jump to previous hit <Up>\n"
+"Exit menu search mode </> <Esc>\n"
+"Search for configuration variables with or without leading CONFIG_\n"
+" <F8>RegExpr<Enter>\n"
+"Verbose search help <F8><F1>\n"
+"----------------------------------------------------------------------\n"
+"\n"
+"Unless in a data entry window, key <1> may be used instead of <F1>,\n"
+"<2> instead of <F2>, etc.\n"
+"\n"
+"\n"
+"Radiolist (Choice list)\n"
+"-----------------------\n"
+"Use the movement keys listed above to select the option you wish to set\n"
+"and press <Space>.\n"
+"\n"
+"\n"
+"Data entry\n"
+"----------\n"
+"Enter the requested information and press <Enter>. Hexadecimal values\n"
+"may be entered without the \"0x\" prefix.\n"
+"\n"
+"\n"
+"Text Box (Help Window)\n"
+"----------------------\n"
+"Use movement keys as listed in table above.\n"
+"\n"
+"Press any of <Enter> <Esc> <q> <F5> <F9> to exit.\n"
+"\n"
+"\n"
+"Alternate configuration files\n"
+"-----------------------------\n"
+"nconfig supports switching between different configurations.\n"
+"Press <F6> to save your current configuration. Press <F7> and enter\n"
+"a file name to load a previously saved configuration.\n"
+"\n"
+"\n"
+"Terminal configuration\n"
+"----------------------\n"
+"If you use nconfig in a xterm window, make sure your TERM environment\n"
+"variable specifies a terminal configuration which supports at least\n"
+"16 colors. Otherwise nconfig will look rather bad.\n"
+"\n"
+"If the \"stty size\" command reports the current terminalsize correctly,\n"
+"nconfig will adapt to sizes larger than the traditional 80x25 \"standard\"\n"
+"and display longer menus properly.\n"
+"\n"
+"\n"
+"Single menu mode\n"
+"----------------\n"
+"If you prefer to have all of the menu entries listed in a single menu,\n"
+"rather than the default multimenu hierarchy, run nconfig with\n"
+"NCONFIG_MODE environment variable set to single_menu. Example:\n"
+"\n"
+"make NCONFIG_MODE=single_menu nconfig\n"
+"\n"
+"<Enter> will then unfold the appropriate category, or fold it if it\n"
+"is already unfolded. Folded menu entries will be designated by a\n"
+"leading \"++>\" and unfolded entries by a leading \"-->\".\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive than\n"
+"the default mode, especially with a larger number of unfolded submenus.\n"
+"\n"),
+menu_no_f_instructions[] = N_(
+"Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
+"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
+"\n"
+"Use the following keys to navigate the menus:\n"
+"Move up or down with <Up> and <Down>.\n"
+"Enter a submenu with <Enter> or <Right>.\n"
+"Exit a submenu to its parent menu with <Esc> or <Left>.\n"
+"Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
+"Pressing <Space> cycles through the available options.\n"
+"To search for menu entries press </>.\n"
+"<Esc> always leaves the current window.\n"
+"\n"
+"You do not have function keys support.\n"
+"Press <1> instead of <F1>, <2> instead of <F2>, etc.\n"
+"For verbose global help use key <1>.\n"
+"For help related to the current menu entry press <?> or <h>.\n"),
+menu_instructions[] = N_(
+"Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
+"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
+"\n"
+"Use the following keys to navigate the menus:\n"
+"Move up or down with <Up> or <Down>.\n"
+"Enter a submenu with <Enter> or <Right>.\n"
+"Exit a submenu to its parent menu with <Esc> or <Left>.\n"
+"Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
+"Pressing <Space> cycles through the available options.\n"
+"To search for menu entries press </>.\n"
+"<Esc> always leaves the current window.\n"
+"\n"
+"Pressing <1> may be used instead of <F1>, <2> instead of <F2>, etc.\n"
+"For verbose global help press <F1>.\n"
+"For help related to the current menu entry press <?> or <h>.\n"),
+radiolist_instructions[] = N_(
+"Press <Up>, <Down>, <Home> or <End> to navigate a radiolist, select\n"
+"with <Space>.\n"
+"For help related to the current entry press <?> or <h>.\n"
+"For global help press <F1>.\n"),
+inputbox_instructions_int[] = N_(
+"Please enter a decimal value.\n"
+"Fractions will not be accepted.\n"
+"Press <Enter> to apply, <Esc> to cancel."),
+inputbox_instructions_hex[] = N_(
+"Please enter a hexadecimal value.\n"
+"Press <Enter> to apply, <Esc> to cancel."),
+inputbox_instructions_string[] = N_(
+"Please enter a string value.\n"
+"Press <Enter> to apply, <Esc> to cancel."),
+setmod_text[] = N_(
+"This feature depends on another feature which has been configured as a\n"
+"module. As a result, the current feature will be built as a module too."),
+load_config_text[] = N_(
+"Enter the name of the configuration file you wish to load.\n"
+"Accept the name shown to restore the configuration you last\n"
+"retrieved. Leave empty to abort."),
+load_config_help[] = N_(
+"For various reasons, one may wish to keep several different\n"
+"configurations available on a single machine.\n"
+"\n"
+"If you have saved a previous configuration in a file other than the\n"
+"default one, entering its name here will allow you to load and modify\n"
+"that configuration.\n"
+"\n"
+"Leave empty to abort.\n"),
+save_config_text[] = N_(
+"Enter a filename to which this configuration should be saved\n"
+"as an alternate. Leave empty to abort."),
+save_config_help[] = N_(
+"For various reasons, one may wish to keep several different\n"
+"configurations available on a single machine.\n"
+"\n"
+"Entering a file name here will allow you to later retrieve, modify\n"
+"and use the current configuration as an alternate to whatever\n"
+"configuration options you have selected at that time.\n"
+"\n"
+"Leave empty to abort.\n"),
+search_help[] = N_(
+"Search for symbols (configuration variable names CONFIG_*) and display\n"
+"their relations. Regular expressions are supported.\n"
+"Example: Search for \"^FOO\".\n"
+"Result:\n"
+"-----------------------------------------------------------------\n"
+"Symbol: FOO [ = m]\n"
+"Prompt: Foo bus is used to drive the bar HW\n"
+"Defined at drivers/pci/Kconfig:47\n"
+"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+"Location:\n"
+" -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
+" -> PCI support (PCI [ = y])\n"
+" -> PCI access mode (<choice> [ = y])\n"
+"Selects: LIBCRC32\n"
+"Selected by: BAR\n"
+"-----------------------------------------------------------------\n"
+"o The line 'Prompt:' shows the text displayed for this symbol in\n"
+" the menu hierarchy.\n"
+"o The 'Defined at' line tells at what file / line number the symbol is\n"
+" defined.\n"
+"o The 'Depends on:' line lists symbols that need to be defined for\n"
+" this symbol to be visible and selectable in the menu.\n"
+"o The 'Location:' lines tell, where in the menu structure this symbol\n"
+" is located. A location followed by a [ = y] indicates that this is\n"
+" a selectable menu item, and the current value is displayed inside\n"
+" brackets.\n"
+"o The 'Selects:' line tells, what symbol will be automatically selected\n"
+" if this symbol is selected (y or m).\n"
+"o The 'Selected by' line tells what symbol has selected this symbol.\n"
+"\n"
+"Only relevant lines are shown.\n"
+"\n\n"
+"Search examples:\n"
+"USB => find all symbols containing USB\n"
+"^USB => find all symbols starting with USB\n"
+"USB$ => find all symbols ending with USB\n"
+"\n");
+
+struct mitem {
+ char str[256];
+ char tag;
+ void *usrptr;
+ int is_visible;
+};
+
+#define MAX_MENU_ITEMS 4096
+static int show_all_items;
+static int indent;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+/* the window in which all information appears */
+static WINDOW *main_window;
+/* the largest size of the menu window */
+static int mwin_max_lines;
+static int mwin_max_cols;
+/* the window in which we show option buttons */
+static MENU *curses_menu;
+static ITEM *curses_menu_items[MAX_MENU_ITEMS];
+static struct mitem k_menu_items[MAX_MENU_ITEMS];
+static int items_num;
+static int global_exit;
+/* the currently selected button */
+const char *current_instructions = menu_instructions;
+
+static char *dialog_input_result;
+static int dialog_input_result_len;
+
+static void conf(struct menu *menu);
+static void conf_choice(struct menu *menu);
+static void conf_string(struct menu *menu);
+static void conf_load(void);
+static void conf_save(void);
+static void show_help(struct menu *menu);
+static int do_exit(void);
+static void setup_windows(void);
+static void search_conf(void);
+
+typedef void (*function_key_handler_t)(int *key, struct menu *menu);
+static void handle_f1(int *key, struct menu *current_item);
+static void handle_f2(int *key, struct menu *current_item);
+static void handle_f3(int *key, struct menu *current_item);
+static void handle_f4(int *key, struct menu *current_item);
+static void handle_f5(int *key, struct menu *current_item);
+static void handle_f6(int *key, struct menu *current_item);
+static void handle_f7(int *key, struct menu *current_item);
+static void handle_f8(int *key, struct menu *current_item);
+static void handle_f9(int *key, struct menu *current_item);
+
+struct function_keys {
+ const char *key_str;
+ const char *func;
+ function_key key;
+ function_key_handler_t handler;
+};
+
+static const int function_keys_num = 9;
+struct function_keys function_keys[] = {
+ {
+ .key_str = "F1",
+ .func = "Help",
+ .key = F_HELP,
+ .handler = handle_f1,
+ },
+ {
+ .key_str = "F2",
+ .func = "SymInfo",
+ .key = F_SYMBOL,
+ .handler = handle_f2,
+ },
+ {
+ .key_str = "F3",
+ .func = "Help 2",
+ .key = F_INSTS,
+ .handler = handle_f3,
+ },
+ {
+ .key_str = "F4",
+ .func = "ShowAll",
+ .key = F_CONF,
+ .handler = handle_f4,
+ },
+ {
+ .key_str = "F5",
+ .func = "Back",
+ .key = F_BACK,
+ .handler = handle_f5,
+ },
+ {
+ .key_str = "F6",
+ .func = "Save",
+ .key = F_SAVE,
+ .handler = handle_f6,
+ },
+ {
+ .key_str = "F7",
+ .func = "Load",
+ .key = F_LOAD,
+ .handler = handle_f7,
+ },
+ {
+ .key_str = "F8",
+ .func = "SymSearch",
+ .key = F_SEARCH,
+ .handler = handle_f8,
+ },
+ {
+ .key_str = "F9",
+ .func = "Exit",
+ .key = F_EXIT,
+ .handler = handle_f9,
+ },
+};
+
+static void print_function_line(void)
+{
+ int i;
+ int offset = 1;
+ const int skip = 1;
+ int lines = getmaxy(stdscr);
+
+ for (i = 0; i < function_keys_num; i++) {
+ (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
+ mvwprintw(main_window, lines-3, offset,
+ "%s",
+ function_keys[i].key_str);
+ (void) wattrset(main_window, attributes[FUNCTION_TEXT]);
+ offset += strlen(function_keys[i].key_str);
+ mvwprintw(main_window, lines-3,
+ offset, "%s",
+ function_keys[i].func);
+ offset += strlen(function_keys[i].func) + skip;
+ }
+ (void) wattrset(main_window, attributes[NORMAL]);
+}
+
+/* help */
+static void handle_f1(int *key, struct menu *current_item)
+{
+ show_scroll_win(main_window,
+ _("Global help"), _(nconf_global_help));
+ return;
+}
+
+/* symbole help */
+static void handle_f2(int *key, struct menu *current_item)
+{
+ show_help(current_item);
+ return;
+}
+
+/* instructions */
+static void handle_f3(int *key, struct menu *current_item)
+{
+ show_scroll_win(main_window,
+ _("Short help"),
+ _(current_instructions));
+ return;
+}
+
+/* config */
+static void handle_f4(int *key, struct menu *current_item)
+{
+ int res = btn_dialog(main_window,
+ _("Show all symbols?"),
+ 2,
+ " <Show All> ",
+ "<Don't show all>");
+ if (res == 0)
+ show_all_items = 1;
+ else if (res == 1)
+ show_all_items = 0;
+
+ return;
+}
+
+/* back */
+static void handle_f5(int *key, struct menu *current_item)
+{
+ *key = KEY_LEFT;
+ return;
+}
+
+/* save */
+static void handle_f6(int *key, struct menu *current_item)
+{
+ conf_save();
+ return;
+}
+
+/* load */
+static void handle_f7(int *key, struct menu *current_item)
+{
+ conf_load();
+ return;
+}
+
+/* search */
+static void handle_f8(int *key, struct menu *current_item)
+{
+ search_conf();
+ return;
+}
+
+/* exit */
+static void handle_f9(int *key, struct menu *current_item)
+{
+ do_exit();
+ return;
+}
+
+/* return != 0 to indicate the key was handles */
+static int process_special_keys(int *key, struct menu *menu)
+{
+ int i;
+
+ if (*key == KEY_RESIZE) {
+ setup_windows();
+ return 1;
+ }
+
+ for (i = 0; i < function_keys_num; i++) {
+ if (*key == KEY_F(function_keys[i].key) ||
+ *key == '0' + function_keys[i].key){
+ function_keys[i].handler(key, menu);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void clean_items(void)
+{
+ int i;
+ for (i = 0; curses_menu_items[i]; i++)
+ free_item(curses_menu_items[i]);
+ bzero(curses_menu_items, sizeof(curses_menu_items));
+ bzero(k_menu_items, sizeof(k_menu_items));
+ items_num = 0;
+}
+
+typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
+ FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
+
+/* return the index of the matched item, or -1 if no such item exists */
+static int get_mext_match(const char *match_str, match_f flag)
+{
+ int match_start = item_index(current_item(curses_menu));
+ int index;
+
+ if (flag == FIND_NEXT_MATCH_DOWN)
+ ++match_start;
+ else if (flag == FIND_NEXT_MATCH_UP)
+ --match_start;
+
+ index = match_start;
+ index = (index + items_num) % items_num;
+ while (true) {
+ char *str = k_menu_items[index].str;
+ if (strcasestr(str, match_str) != 0)
+ return index;
+ if (flag == FIND_NEXT_MATCH_UP ||
+ flag == MATCH_TINKER_PATTERN_UP)
+ --index;
+ else
+ ++index;
+ index = (index + items_num) % items_num;
+ if (index == match_start)
+ return -1;
+ }
+}
+
+/* Make a new item. */
+static void item_make(struct menu *menu, char tag, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (items_num > MAX_MENU_ITEMS-1)
+ return;
+
+ bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
+ k_menu_items[items_num].tag = tag;
+ k_menu_items[items_num].usrptr = menu;
+ if (menu != NULL)
+ k_menu_items[items_num].is_visible =
+ menu_is_visible(menu);
+ else
+ k_menu_items[items_num].is_visible = 1;
+
+ va_start(ap, fmt);
+ vsnprintf(k_menu_items[items_num].str,
+ sizeof(k_menu_items[items_num].str),
+ fmt, ap);
+ va_end(ap);
+
+ if (!k_menu_items[items_num].is_visible)
+ memcpy(k_menu_items[items_num].str, "XXX", 3);
+
+ curses_menu_items[items_num] = new_item(
+ k_menu_items[items_num].str,
+ k_menu_items[items_num].str);
+ set_item_userptr(curses_menu_items[items_num],
+ &k_menu_items[items_num]);
+ /*
+ if (!k_menu_items[items_num].is_visible)
+ item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
+ */
+
+ items_num++;
+ curses_menu_items[items_num] = NULL;
+}
+
+/* very hackish. adds a string to the last item added */
+static void item_add_str(const char *fmt, ...)
+{
+ va_list ap;
+ int index = items_num-1;
+ char new_str[256];
+ char tmp_str[256];
+
+ if (index < 0)
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(new_str, sizeof(new_str), fmt, ap);
+ va_end(ap);
+ snprintf(tmp_str, sizeof(tmp_str), "%s%s",
+ k_menu_items[index].str, new_str);
+ strncpy(k_menu_items[index].str,
+ tmp_str,
+ sizeof(k_menu_items[index].str));
+
+ free_item(curses_menu_items[index]);
+ curses_menu_items[index] = new_item(
+ k_menu_items[index].str,
+ k_menu_items[index].str);
+ set_item_userptr(curses_menu_items[index],
+ &k_menu_items[index]);
+}
+
+/* get the tag of the currently selected item */
+static char item_tag(void)
+{
+ ITEM *cur;
+ struct mitem *mcur;
+
+ cur = current_item(curses_menu);
+ if (cur == NULL)
+ return 0;
+ mcur = (struct mitem *) item_userptr(cur);
+ return mcur->tag;
+}
+
+static int curses_item_index(void)
+{
+ return item_index(current_item(curses_menu));
+}
+
+static void *item_data(void)
+{
+ ITEM *cur;
+ struct mitem *mcur;
+
+ cur = current_item(curses_menu);
+ if (!cur)
+ return NULL;
+ mcur = (struct mitem *) item_userptr(cur);
+ return mcur->usrptr;
+
+}
+
+static int item_is_tag(char tag)
+{
+ return item_tag() == tag;
+}
+
+static char filename[PATH_MAX+1];
+static char menu_backtitle[PATH_MAX+128];
+static const char *set_config_filename(const char *config_filename)
+{
+ int size;
+
+ size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+ "%s - %s", config_filename, rootmenu.prompt->text);
+ if (size >= sizeof(menu_backtitle))
+ menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+
+ size = snprintf(filename, sizeof(filename), "%s", config_filename);
+ if (size >= sizeof(filename))
+ filename[sizeof(filename)-1] = '\0';
+ return menu_backtitle;
+}
+
+/* return = 0 means we are successful.
+ * -1 means go on doing what you were doing
+ */
+static int do_exit(void)
+{
+ int res;
+ if (!conf_get_changed()) {
+ global_exit = 1;
+ return 0;
+ }
+ res = btn_dialog(main_window,
+ _("Do you wish to save your new configuration?\n"
+ "<ESC> to cancel and resume nconfig."),
+ 2,
+ " <save> ",
+ "<don't save>");
+ if (res == KEY_EXIT) {
+ global_exit = 0;
+ return -1;
+ }
+
+ /* if we got here, the user really wants to exit */
+ switch (res) {
+ case 0:
+ res = conf_write(filename);
+ if (res)
+ btn_dialog(
+ main_window,
+ _("Error during writing of configuration.\n"
+ "Your configuration changes were NOT saved."),
+ 1,
+ "<OK>");
+ break;
+ default:
+ btn_dialog(
+ main_window,
+ _("Your configuration changes were NOT saved."),
+ 1,
+ "<OK>");
+ break;
+ }
+ global_exit = 1;
+ return 0;
+}
+
+
+static void search_conf(void)
+{
+ struct symbol **sym_arr;
+ struct gstr res;
+ struct gstr title;
+ char *dialog_input;
+ int dres;
+
+ title = str_new();
+ str_printf( &title, _("Enter (sub)string or regexp to search for "
+ "(with or without \"%s\")"), CONFIG_);
+
+again:
+ dres = dialog_inputbox(main_window,
+ _("Search Configuration Parameter"),
+ str_get(&title),
+ "", &dialog_input_result, &dialog_input_result_len);
+ switch (dres) {
+ case 0:
+ break;
+ case 1:
+ show_scroll_win(main_window,
+ _("Search Configuration"), search_help);
+ goto again;
+ default:
+ str_free(&title);
+ return;
+ }
+
+ /* strip the prefix if necessary */
+ dialog_input = dialog_input_result;
+ if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
+ dialog_input += strlen(CONFIG_);
+
+ sym_arr = sym_re_search(dialog_input);
+ res = get_relations_str(sym_arr, NULL);
+ free(sym_arr);
+ show_scroll_win(main_window,
+ _("Search Results"), str_get(&res));
+ str_free(&res);
+ str_free(&title);
+}
+
+
+static void build_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+ int type, tmp, doint = 2;
+ tristate val;
+ char ch;
+
+ if (!menu || (!show_all_items && !menu_is_visible(menu)))
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (!sym) {
+ if (prop && menu != current_menu) {
+ const char *prompt = menu_get_prompt(menu);
+ enum prop_type ptype;
+ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ switch (ptype) {
+ case P_MENU:
+ child_count++;
+ prompt = _(prompt);
+ if (single_menu_mode) {
+ item_make(menu, 'm',
+ "%s%*c%s",
+ menu->data ? "-->" : "++>",
+ indent + 1, ' ', prompt);
+ } else
+ item_make(menu, 'm',
+ " %*c%s %s",
+ indent + 1, ' ', prompt,
+ menu_is_empty(menu) ? "----" : "--->");
+
+ if (single_menu_mode && menu->data)
+ goto conf_childs;
+ return;
+ case P_COMMENT:
+ if (prompt) {
+ child_count++;
+ item_make(menu, ':',
+ " %*c*** %s ***",
+ indent + 1, ' ',
+ _(prompt));
+ }
+ break;
+ default:
+ if (prompt) {
+ child_count++;
+ item_make(menu, ':', "---%*c%s",
+ indent + 1, ' ',
+ _(prompt));
+ }
+ }
+ } else
+ doint = 0;
+ goto conf_childs;
+ }
+
+ type = sym_get_type(sym);
+ if (sym_is_choice(sym)) {
+ struct symbol *def_sym = sym_get_choice_value(sym);
+ struct menu *def_menu = NULL;
+
+ child_count++;
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child) && child->sym == def_sym)
+ def_menu = child;
+ }
+
+ val = sym_get_tristate_value(sym);
+ if (sym_is_changable(sym)) {
+ switch (type) {
+ case S_BOOLEAN:
+ item_make(menu, 't', "[%c]",
+ val == no ? ' ' : '*');
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes:
+ ch = '*';
+ break;
+ case mod:
+ ch = 'M';
+ break;
+ default:
+ ch = ' ';
+ break;
+ }
+ item_make(menu, 't', "<%c>", ch);
+ break;
+ }
+ } else {
+ item_make(menu, def_menu ? 't' : ':', " ");
+ }
+
+ item_add_str("%*c%s", indent + 1,
+ ' ', _(menu_get_prompt(menu)));
+ if (val == yes) {
+ if (def_menu) {
+ item_add_str(" (%s)",
+ _(menu_get_prompt(def_menu)));
+ item_add_str(" --->");
+ if (def_menu->list) {
+ indent += 2;
+ build_conf(def_menu);
+ indent -= 2;
+ }
+ }
+ return;
+ }
+ } else {
+ if (menu == current_menu) {
+ item_make(menu, ':',
+ "---%*c%s", indent + 1,
+ ' ', _(menu_get_prompt(menu)));
+ goto conf_childs;
+ }
+ child_count++;
+ val = sym_get_tristate_value(sym);
+ if (sym_is_choice_value(sym) && val == yes) {
+ item_make(menu, ':', " ");
+ } else {
+ switch (type) {
+ case S_BOOLEAN:
+ if (sym_is_changable(sym))
+ item_make(menu, 't', "[%c]",
+ val == no ? ' ' : '*');
+ else
+ item_make(menu, 't', "-%c-",
+ val == no ? ' ' : '*');
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes:
+ ch = '*';
+ break;
+ case mod:
+ ch = 'M';
+ break;
+ default:
+ ch = ' ';
+ break;
+ }
+ if (sym_is_changable(sym)) {
+ if (sym->rev_dep.tri == mod)
+ item_make(menu,
+ 't', "{%c}", ch);
+ else
+ item_make(menu,
+ 't', "<%c>", ch);
+ } else
+ item_make(menu, 't', "-%c-", ch);
+ break;
+ default:
+ tmp = 2 + strlen(sym_get_string_value(sym));
+ item_make(menu, 's', " (%s)",
+ sym_get_string_value(sym));
+ tmp = indent - tmp + 4;
+ if (tmp < 0)
+ tmp = 0;
+ item_add_str("%*c%s%s", tmp, ' ',
+ _(menu_get_prompt(menu)),
+ (sym_has_value(sym) ||
+ !sym_is_changable(sym)) ? "" :
+ _(" (NEW)"));
+ goto conf_childs;
+ }
+ }
+ item_add_str("%*c%s%s", indent + 1, ' ',
+ _(menu_get_prompt(menu)),
+ (sym_has_value(sym) || !sym_is_changable(sym)) ?
+ "" : _(" (NEW)"));
+ if (menu->prompt && menu->prompt->type == P_MENU) {
+ item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->");
+ return;
+ }
+ }
+
+conf_childs:
+ indent += doint;
+ for (child = menu->list; child; child = child->next)
+ build_conf(child);
+ indent -= doint;
+}
+
+static void reset_menu(void)
+{
+ unpost_menu(curses_menu);
+ clean_items();
+}
+
+/* adjust the menu to show this item.
+ * prefer not to scroll the menu if possible*/
+static void center_item(int selected_index, int *last_top_row)
+{
+ int toprow;
+
+ set_top_row(curses_menu, *last_top_row);
+ toprow = top_row(curses_menu);
+ if (selected_index < toprow ||
+ selected_index >= toprow+mwin_max_lines) {
+ toprow = max(selected_index-mwin_max_lines/2, 0);
+ if (toprow >= item_count(curses_menu)-mwin_max_lines)
+ toprow = item_count(curses_menu)-mwin_max_lines;
+ set_top_row(curses_menu, toprow);
+ }
+ set_current_item(curses_menu,
+ curses_menu_items[selected_index]);
+ *last_top_row = toprow;
+ post_menu(curses_menu);
+ refresh_all_windows(main_window);
+}
+
+/* this function assumes reset_menu has been called before */
+static void show_menu(const char *prompt, const char *instructions,
+ int selected_index, int *last_top_row)
+{
+ int maxx, maxy;
+ WINDOW *menu_window;
+
+ current_instructions = instructions;
+
+ clear();
+ (void) wattrset(main_window, attributes[NORMAL]);
+ print_in_middle(stdscr, 1, 0, getmaxx(stdscr),
+ menu_backtitle,
+ attributes[MAIN_HEADING]);
+
+ (void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
+ box(main_window, 0, 0);
+ (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
+ mvwprintw(main_window, 0, 3, " %s ", prompt);
+ (void) wattrset(main_window, attributes[NORMAL]);
+
+ set_menu_items(curses_menu, curses_menu_items);
+
+ /* position the menu at the middle of the screen */
+ scale_menu(curses_menu, &maxy, &maxx);
+ maxx = min(maxx, mwin_max_cols-2);
+ maxy = mwin_max_lines;
+ menu_window = derwin(main_window,
+ maxy,
+ maxx,
+ 2,
+ (mwin_max_cols-maxx)/2);
+ keypad(menu_window, TRUE);
+ set_menu_win(curses_menu, menu_window);
+ set_menu_sub(curses_menu, menu_window);
+
+ /* must reassert this after changing items, otherwise returns to a
+ * default of 16
+ */
+ set_menu_format(curses_menu, maxy, 1);
+ center_item(selected_index, last_top_row);
+ set_menu_format(curses_menu, maxy, 1);
+
+ print_function_line();
+
+ /* Post the menu */
+ post_menu(curses_menu);
+ refresh_all_windows(main_window);
+}
+
+static void adj_match_dir(match_f *match_direction)
+{
+ if (*match_direction == FIND_NEXT_MATCH_DOWN)
+ *match_direction =
+ MATCH_TINKER_PATTERN_DOWN;
+ else if (*match_direction == FIND_NEXT_MATCH_UP)
+ *match_direction =
+ MATCH_TINKER_PATTERN_UP;
+ /* else, do no change.. */
+}
+
+struct match_state
+{
+ int in_search;
+ match_f match_direction;
+ char pattern[256];
+};
+
+/* Return 0 means I have handled the key. In such a case, ans should hold the
+ * item to center, or -1 otherwise.
+ * Else return -1 .
+ */
+static int do_match(int key, struct match_state *state, int *ans)
+{
+ char c = (char) key;
+ int terminate_search = 0;
+ *ans = -1;
+ if (key == '/' || (state->in_search && key == 27)) {
+ move(0, 0);
+ refresh();
+ clrtoeol();
+ state->in_search = 1-state->in_search;
+ bzero(state->pattern, sizeof(state->pattern));
+ state->match_direction = MATCH_TINKER_PATTERN_DOWN;
+ return 0;
+ } else if (!state->in_search)
+ return 1;
+
+ if (isalnum(c) || isgraph(c) || c == ' ') {
+ state->pattern[strlen(state->pattern)] = c;
+ state->pattern[strlen(state->pattern)] = '\0';
+ adj_match_dir(&state->match_direction);
+ *ans = get_mext_match(state->pattern,
+ state->match_direction);
+ } else if (key == KEY_DOWN) {
+ state->match_direction = FIND_NEXT_MATCH_DOWN;
+ *ans = get_mext_match(state->pattern,
+ state->match_direction);
+ } else if (key == KEY_UP) {
+ state->match_direction = FIND_NEXT_MATCH_UP;
+ *ans = get_mext_match(state->pattern,
+ state->match_direction);
+ } else if (key == KEY_BACKSPACE || key == 127) {
+ state->pattern[strlen(state->pattern)-1] = '\0';
+ adj_match_dir(&state->match_direction);
+ } else
+ terminate_search = 1;
+
+ if (terminate_search) {
+ state->in_search = 0;
+ bzero(state->pattern, sizeof(state->pattern));
+ move(0, 0);
+ refresh();
+ clrtoeol();
+ return -1;
+ }
+ return 0;
+}
+
+static void conf(struct menu *menu)
+{
+ struct menu *submenu = 0;
+ const char *prompt = menu_get_prompt(menu);
+ struct symbol *sym;
+ int res;
+ int current_index = 0;
+ int last_top_row = 0;
+ struct match_state match_state = {
+ .in_search = 0,
+ .match_direction = MATCH_TINKER_PATTERN_DOWN,
+ .pattern = "",
+ };
+
+ while (!global_exit) {
+ reset_menu();
+ current_menu = menu;
+ build_conf(menu);
+ if (!child_count)
+ break;
+
+ show_menu(prompt ? _(prompt) : _("Main Menu"),
+ _(menu_instructions),
+ current_index, &last_top_row);
+ keypad((menu_win(curses_menu)), TRUE);
+ while (!global_exit) {
+ if (match_state.in_search) {
+ mvprintw(0, 0,
+ "searching: %s", match_state.pattern);
+ clrtoeol();
+ }
+ refresh_all_windows(main_window);
+ res = wgetch(menu_win(curses_menu));
+ if (!res)
+ break;
+ if (do_match(res, &match_state, &current_index) == 0) {
+ if (current_index != -1)
+ center_item(current_index,
+ &last_top_row);
+ continue;
+ }
+ if (process_special_keys(&res,
+ (struct menu *) item_data()))
+ break;
+ switch (res) {
+ case KEY_DOWN:
+ menu_driver(curses_menu, REQ_DOWN_ITEM);
+ break;
+ case KEY_UP:
+ menu_driver(curses_menu, REQ_UP_ITEM);
+ break;
+ case KEY_NPAGE:
+ menu_driver(curses_menu, REQ_SCR_DPAGE);
+ break;
+ case KEY_PPAGE:
+ menu_driver(curses_menu, REQ_SCR_UPAGE);
+ break;
+ case KEY_HOME:
+ menu_driver(curses_menu, REQ_FIRST_ITEM);
+ break;
+ case KEY_END:
+ menu_driver(curses_menu, REQ_LAST_ITEM);
+ break;
+ case 'h':
+ case '?':
+ show_help((struct menu *) item_data());
+ break;
+ }
+ if (res == 10 || res == 27 ||
+ res == 32 || res == 'n' || res == 'y' ||
+ res == KEY_LEFT || res == KEY_RIGHT ||
+ res == 'm')
+ break;
+ refresh_all_windows(main_window);
+ }
+
+ refresh_all_windows(main_window);
+ /* if ESC or left*/
+ if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
+ break;
+
+ /* remember location in the menu */
+ last_top_row = top_row(curses_menu);
+ current_index = curses_item_index();
+
+ if (!item_tag())
+ continue;
+
+ submenu = (struct menu *) item_data();
+ if (!submenu || !menu_is_visible(submenu))
+ continue;
+ sym = submenu->sym;
+
+ switch (res) {
+ case ' ':
+ if (item_is_tag('t'))
+ sym_toggle_tristate_value(sym);
+ else if (item_is_tag('m'))
+ conf(submenu);
+ break;
+ case KEY_RIGHT:
+ case 10: /* ENTER WAS PRESSED */
+ switch (item_tag()) {
+ case 'm':
+ if (single_menu_mode)
+ submenu->data =
+ (void *) (long) !submenu->data;
+ else
+ conf(submenu);
+ break;
+ case 't':
+ if (sym_is_choice(sym) &&
+ sym_get_tristate_value(sym) == yes)
+ conf_choice(submenu);
+ else if (submenu->prompt &&
+ submenu->prompt->type == P_MENU)
+ conf(submenu);
+ else if (res == 10)
+ sym_toggle_tristate_value(sym);
+ break;
+ case 's':
+ conf_string(submenu);
+ break;
+ }
+ break;
+ case 'y':
+ if (item_is_tag('t')) {
+ if (sym_set_tristate_value(sym, yes))
+ break;
+ if (sym_set_tristate_value(sym, mod))
+ btn_dialog(main_window, setmod_text, 0);
+ }
+ break;
+ case 'n':
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, no);
+ break;
+ case 'm':
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, mod);
+ break;
+ }
+ }
+}
+
+static void conf_message_callback(const char *fmt, va_list ap)
+{
+ char buf[1024];
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ btn_dialog(main_window, buf, 1, "<OK>");
+}
+
+static void show_help(struct menu *menu)
+{
+ struct gstr help;
+
+ if (!menu)
+ return;
+
+ help = str_new();
+ menu_get_ext_help(menu, &help);
+ show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
+ str_free(&help);
+}
+
+static void conf_choice(struct menu *menu)
+{
+ const char *prompt = _(menu_get_prompt(menu));
+ struct menu *child = 0;
+ struct symbol *active;
+ int selected_index = 0;
+ int last_top_row = 0;
+ int res, i = 0;
+ struct match_state match_state = {
+ .in_search = 0,
+ .match_direction = MATCH_TINKER_PATTERN_DOWN,
+ .pattern = "",
+ };
+
+ active = sym_get_choice_value(menu->sym);
+ /* this is mostly duplicated from the conf() function. */
+ while (!global_exit) {
+ reset_menu();
+
+ for (i = 0, child = menu->list; child; child = child->next) {
+ if (!show_all_items && !menu_is_visible(child))
+ continue;
+
+ if (child->sym == sym_get_choice_value(menu->sym))
+ item_make(child, ':', "<X> %s",
+ _(menu_get_prompt(child)));
+ else if (child->sym)
+ item_make(child, ':', " %s",
+ _(menu_get_prompt(child)));
+ else
+ item_make(child, ':', "*** %s ***",
+ _(menu_get_prompt(child)));
+
+ if (child->sym == active){
+ last_top_row = top_row(curses_menu);
+ selected_index = i;
+ }
+ i++;
+ }
+ show_menu(prompt ? _(prompt) : _("Choice Menu"),
+ _(radiolist_instructions),
+ selected_index,
+ &last_top_row);
+ while (!global_exit) {
+ if (match_state.in_search) {
+ mvprintw(0, 0, "searching: %s",
+ match_state.pattern);
+ clrtoeol();
+ }
+ refresh_all_windows(main_window);
+ res = wgetch(menu_win(curses_menu));
+ if (!res)
+ break;
+ if (do_match(res, &match_state, &selected_index) == 0) {
+ if (selected_index != -1)
+ center_item(selected_index,
+ &last_top_row);
+ continue;
+ }
+ if (process_special_keys(
+ &res,
+ (struct menu *) item_data()))
+ break;
+ switch (res) {
+ case KEY_DOWN:
+ menu_driver(curses_menu, REQ_DOWN_ITEM);
+ break;
+ case KEY_UP:
+ menu_driver(curses_menu, REQ_UP_ITEM);
+ break;
+ case KEY_NPAGE:
+ menu_driver(curses_menu, REQ_SCR_DPAGE);
+ break;
+ case KEY_PPAGE:
+ menu_driver(curses_menu, REQ_SCR_UPAGE);
+ break;
+ case KEY_HOME:
+ menu_driver(curses_menu, REQ_FIRST_ITEM);
+ break;
+ case KEY_END:
+ menu_driver(curses_menu, REQ_LAST_ITEM);
+ break;
+ case 'h':
+ case '?':
+ show_help((struct menu *) item_data());
+ break;
+ }
+ if (res == 10 || res == 27 || res == ' ' ||
+ res == KEY_LEFT){
+ break;
+ }
+ refresh_all_windows(main_window);
+ }
+ /* if ESC or left */
+ if (res == 27 || res == KEY_LEFT)
+ break;
+
+ child = item_data();
+ if (!child || !menu_is_visible(child) || !child->sym)
+ continue;
+ switch (res) {
+ case ' ':
+ case 10:
+ case KEY_RIGHT:
+ sym_set_tristate_value(child->sym, yes);
+ return;
+ case 'h':
+ case '?':
+ show_help(child);
+ active = child->sym;
+ break;
+ case KEY_EXIT:
+ return;
+ }
+ }
+}
+
+static void conf_string(struct menu *menu)
+{
+ const char *prompt = menu_get_prompt(menu);
+
+ while (1) {
+ int res;
+ const char *heading;
+
+ switch (sym_get_type(menu->sym)) {
+ case S_INT:
+ heading = _(inputbox_instructions_int);
+ break;
+ case S_HEX:
+ heading = _(inputbox_instructions_hex);
+ break;
+ case S_STRING:
+ heading = _(inputbox_instructions_string);
+ break;
+ default:
+ heading = _("Internal nconf error!");
+ }
+ res = dialog_inputbox(main_window,
+ prompt ? _(prompt) : _("Main Menu"),
+ heading,
+ sym_get_string_value(menu->sym),
+ &dialog_input_result,
+ &dialog_input_result_len);
+ switch (res) {
+ case 0:
+ if (sym_set_string_value(menu->sym,
+ dialog_input_result))
+ return;
+ btn_dialog(main_window,
+ _("You have made an invalid entry."), 0);
+ break;
+ case 1:
+ show_help(menu);
+ break;
+ case KEY_EXIT:
+ return;
+ }
+ }
+}
+
+static void conf_load(void)
+{
+ while (1) {
+ int res;
+ res = dialog_inputbox(main_window,
+ NULL, load_config_text,
+ filename,
+ &dialog_input_result,
+ &dialog_input_result_len);
+ switch (res) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ if (!conf_read(dialog_input_result)) {
+ set_config_filename(dialog_input_result);
+ sym_set_change_count(1);
+ return;
+ }
+ btn_dialog(main_window, _("File does not exist!"), 0);
+ break;
+ case 1:
+ show_scroll_win(main_window,
+ _("Load Alternate Configuration"),
+ load_config_help);
+ break;
+ case KEY_EXIT:
+ return;
+ }
+ }
+}
+
+static void conf_save(void)
+{
+ while (1) {
+ int res;
+ res = dialog_inputbox(main_window,
+ NULL, save_config_text,
+ filename,
+ &dialog_input_result,
+ &dialog_input_result_len);
+ switch (res) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ res = conf_write(dialog_input_result);
+ if (!res) {
+ set_config_filename(dialog_input_result);
+ return;
+ }
+ btn_dialog(main_window, _("Can't create file! "
+ "Probably a nonexistent directory."),
+ 1, "<OK>");
+ break;
+ case 1:
+ show_scroll_win(main_window,
+ _("Save Alternate Configuration"),
+ save_config_help);
+ break;
+ case KEY_EXIT:
+ return;
+ }
+ }
+}
+
+void setup_windows(void)
+{
+ int lines, columns;
+
+ getmaxyx(stdscr, lines, columns);
+
+ if (main_window != NULL)
+ delwin(main_window);
+
+ /* set up the menu and menu window */
+ main_window = newwin(lines-2, columns-2, 2, 1);
+ keypad(main_window, TRUE);
+ mwin_max_lines = lines-7;
+ mwin_max_cols = columns-6;
+
+ /* panels order is from bottom to top */
+ new_panel(main_window);
+}
+
+int main(int ac, char **av)
+{
+ int lines, columns;
+ char *mode;
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ conf_parse(av[1]);
+ conf_read(NULL);
+
+ mode = getenv("NCONFIG_MODE");
+ if (mode) {
+ if (!strcasecmp(mode, "single_menu"))
+ single_menu_mode = 1;
+ }
+
+ /* Initialize curses */
+ initscr();
+ /* set color theme */
+ set_colors();
+
+ cbreak();
+ noecho();
+ keypad(stdscr, TRUE);
+ curs_set(0);
+
+ getmaxyx(stdscr, lines, columns);
+ if (columns < 75 || lines < 20) {
+ endwin();
+ printf("Your terminal should have at "
+ "least 20 lines and 75 columns\n");
+ return 1;
+ }
+
+ notimeout(stdscr, FALSE);
+#if NCURSES_REENTRANT
+ set_escdelay(1);
+#else
+ ESCDELAY = 1;
+#endif
+
+ /* set btns menu */
+ curses_menu = new_menu(curses_menu_items);
+ menu_opts_off(curses_menu, O_SHOWDESC);
+ menu_opts_on(curses_menu, O_SHOWMATCH);
+ menu_opts_on(curses_menu, O_ONEVALUE);
+ menu_opts_on(curses_menu, O_NONCYCLIC);
+ menu_opts_on(curses_menu, O_IGNORECASE);
+ set_menu_mark(curses_menu, " ");
+ set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
+ set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
+ set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
+
+ set_config_filename(conf_get_configname());
+ setup_windows();
+
+ /* check for KEY_FUNC(1) */
+ if (has_key(KEY_F(1)) == FALSE) {
+ show_scroll_win(main_window,
+ _("Instructions"),
+ _(menu_no_f_instructions));
+ }
+
+ conf_set_message_callback(conf_message_callback);
+ /* do the work */
+ while (!global_exit) {
+ conf(&rootmenu);
+ if (!global_exit && do_exit() == 0)
+ break;
+ }
+ /* ok, we are done */
+ unpost_menu(curses_menu);
+ free_menu(curses_menu);
+ delwin(main_window);
+ clear();
+ refresh();
+ endwin();
+ return 0;
+}
diff --git a/roms/seabios/scripts/kconfig/nconf.gui.c b/roms/seabios/scripts/kconfig/nconf.gui.c
new file mode 100644
index 00000000..8275f0e5
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/nconf.gui.c
@@ -0,0 +1,656 @@
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+#include "nconf.h"
+
+/* a list of all the different widgets we use */
+attributes_t attributes[ATTR_MAX+1] = {0};
+
+/* available colors:
+ COLOR_BLACK 0
+ COLOR_RED 1
+ COLOR_GREEN 2
+ COLOR_YELLOW 3
+ COLOR_BLUE 4
+ COLOR_MAGENTA 5
+ COLOR_CYAN 6
+ COLOR_WHITE 7
+ */
+static void set_normal_colors(void)
+{
+ init_pair(NORMAL, -1, -1);
+ init_pair(MAIN_HEADING, COLOR_MAGENTA, -1);
+
+ /* FORE is for the selected item */
+ init_pair(MAIN_MENU_FORE, -1, -1);
+ /* BACK for all the rest */
+ init_pair(MAIN_MENU_BACK, -1, -1);
+ init_pair(MAIN_MENU_GREY, -1, -1);
+ init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1);
+ init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1);
+
+ init_pair(SCROLLWIN_TEXT, -1, -1);
+ init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1);
+ init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1);
+
+ init_pair(DIALOG_TEXT, -1, -1);
+ init_pair(DIALOG_BOX, COLOR_YELLOW, -1);
+ init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1);
+ init_pair(DIALOG_MENU_FORE, COLOR_RED, -1);
+
+ init_pair(INPUT_BOX, COLOR_YELLOW, -1);
+ init_pair(INPUT_HEADING, COLOR_GREEN, -1);
+ init_pair(INPUT_TEXT, -1, -1);
+ init_pair(INPUT_FIELD, -1, -1);
+
+ init_pair(FUNCTION_HIGHLIGHT, -1, -1);
+ init_pair(FUNCTION_TEXT, COLOR_YELLOW, -1);
+}
+
+/* available attributes:
+ A_NORMAL Normal display (no highlight)
+ A_STANDOUT Best highlighting mode of the terminal.
+ A_UNDERLINE Underlining
+ A_REVERSE Reverse video
+ A_BLINK Blinking
+ A_DIM Half bright
+ A_BOLD Extra bright or bold
+ A_PROTECT Protected mode
+ A_INVIS Invisible or blank mode
+ A_ALTCHARSET Alternate character set
+ A_CHARTEXT Bit-mask to extract a character
+ COLOR_PAIR(n) Color-pair number n
+ */
+static void normal_color_theme(void)
+{
+ /* automatically add color... */
+#define mkattr(name, attr) do { \
+attributes[name] = attr | COLOR_PAIR(name); } while (0)
+ mkattr(NORMAL, NORMAL);
+ mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE);
+
+ mkattr(MAIN_MENU_FORE, A_REVERSE);
+ mkattr(MAIN_MENU_BACK, A_NORMAL);
+ mkattr(MAIN_MENU_GREY, A_NORMAL);
+ mkattr(MAIN_MENU_HEADING, A_BOLD);
+ mkattr(MAIN_MENU_BOX, A_NORMAL);
+
+ mkattr(SCROLLWIN_TEXT, A_NORMAL);
+ mkattr(SCROLLWIN_HEADING, A_BOLD);
+ mkattr(SCROLLWIN_BOX, A_BOLD);
+
+ mkattr(DIALOG_TEXT, A_BOLD);
+ mkattr(DIALOG_BOX, A_BOLD);
+ mkattr(DIALOG_MENU_FORE, A_STANDOUT);
+ mkattr(DIALOG_MENU_BACK, A_NORMAL);
+
+ mkattr(INPUT_BOX, A_NORMAL);
+ mkattr(INPUT_HEADING, A_BOLD);
+ mkattr(INPUT_TEXT, A_NORMAL);
+ mkattr(INPUT_FIELD, A_UNDERLINE);
+
+ mkattr(FUNCTION_HIGHLIGHT, A_BOLD);
+ mkattr(FUNCTION_TEXT, A_REVERSE);
+}
+
+static void no_colors_theme(void)
+{
+ /* automatically add highlight, no color */
+#define mkattrn(name, attr) { attributes[name] = attr; }
+
+ mkattrn(NORMAL, NORMAL);
+ mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE);
+
+ mkattrn(MAIN_MENU_FORE, A_STANDOUT);
+ mkattrn(MAIN_MENU_BACK, A_NORMAL);
+ mkattrn(MAIN_MENU_GREY, A_NORMAL);
+ mkattrn(MAIN_MENU_HEADING, A_BOLD);
+ mkattrn(MAIN_MENU_BOX, A_NORMAL);
+
+ mkattrn(SCROLLWIN_TEXT, A_NORMAL);
+ mkattrn(SCROLLWIN_HEADING, A_BOLD);
+ mkattrn(SCROLLWIN_BOX, A_BOLD);
+
+ mkattrn(DIALOG_TEXT, A_NORMAL);
+ mkattrn(DIALOG_BOX, A_BOLD);
+ mkattrn(DIALOG_MENU_FORE, A_STANDOUT);
+ mkattrn(DIALOG_MENU_BACK, A_NORMAL);
+
+ mkattrn(INPUT_BOX, A_BOLD);
+ mkattrn(INPUT_HEADING, A_BOLD);
+ mkattrn(INPUT_TEXT, A_NORMAL);
+ mkattrn(INPUT_FIELD, A_UNDERLINE);
+
+ mkattrn(FUNCTION_HIGHLIGHT, A_BOLD);
+ mkattrn(FUNCTION_TEXT, A_REVERSE);
+}
+
+void set_colors()
+{
+ start_color();
+ use_default_colors();
+ set_normal_colors();
+ if (has_colors()) {
+ normal_color_theme();
+ } else {
+ /* give defaults */
+ no_colors_theme();
+ }
+}
+
+
+/* this changes the windows attributes !!! */
+void print_in_middle(WINDOW *win,
+ int starty,
+ int startx,
+ int width,
+ const char *string,
+ chtype color)
+{ int length, x, y;
+ float temp;
+
+
+ if (win == NULL)
+ win = stdscr;
+ getyx(win, y, x);
+ if (startx != 0)
+ x = startx;
+ if (starty != 0)
+ y = starty;
+ if (width == 0)
+ width = 80;
+
+ length = strlen(string);
+ temp = (width - length) / 2;
+ x = startx + (int)temp;
+ (void) wattrset(win, color);
+ mvwprintw(win, y, x, "%s", string);
+ refresh();
+}
+
+int get_line_no(const char *text)
+{
+ int i;
+ int total = 1;
+
+ if (!text)
+ return 0;
+
+ for (i = 0; text[i] != '\0'; i++)
+ if (text[i] == '\n')
+ total++;
+ return total;
+}
+
+const char *get_line(const char *text, int line_no)
+{
+ int i;
+ int lines = 0;
+
+ if (!text)
+ return 0;
+
+ for (i = 0; text[i] != '\0' && lines < line_no; i++)
+ if (text[i] == '\n')
+ lines++;
+ return text+i;
+}
+
+int get_line_length(const char *line)
+{
+ int res = 0;
+ while (*line != '\0' && *line != '\n') {
+ line++;
+ res++;
+ }
+ return res;
+}
+
+/* print all lines to the window. */
+void fill_window(WINDOW *win, const char *text)
+{
+ int x, y;
+ int total_lines = get_line_no(text);
+ int i;
+
+ getmaxyx(win, y, x);
+ /* do not go over end of line */
+ total_lines = min(total_lines, y);
+ for (i = 0; i < total_lines; i++) {
+ char tmp[x+10];
+ const char *line = get_line(text, i);
+ int len = get_line_length(line);
+ strncpy(tmp, line, min(len, x));
+ tmp[len] = '\0';
+ mvwprintw(win, i, 0, "%s", tmp);
+ }
+}
+
+/* get the message, and buttons.
+ * each button must be a char*
+ * return the selected button
+ *
+ * this dialog is used for 2 different things:
+ * 1) show a text box, no buttons.
+ * 2) show a dialog, with horizontal buttons
+ */
+int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
+{
+ va_list ap;
+ char *btn;
+ int btns_width = 0;
+ int msg_lines = 0;
+ int msg_width = 0;
+ int total_width;
+ int win_rows = 0;
+ WINDOW *win;
+ WINDOW *msg_win;
+ WINDOW *menu_win;
+ MENU *menu;
+ ITEM *btns[btn_num+1];
+ int i, x, y;
+ int res = -1;
+
+
+ va_start(ap, btn_num);
+ for (i = 0; i < btn_num; i++) {
+ btn = va_arg(ap, char *);
+ btns[i] = new_item(btn, "");
+ btns_width += strlen(btn)+1;
+ }
+ va_end(ap);
+ btns[btn_num] = NULL;
+
+ /* find the widest line of msg: */
+ msg_lines = get_line_no(msg);
+ for (i = 0; i < msg_lines; i++) {
+ const char *line = get_line(msg, i);
+ int len = get_line_length(line);
+ if (msg_width < len)
+ msg_width = len;
+ }
+
+ total_width = max(msg_width, btns_width);
+ /* place dialog in middle of screen */
+ y = (getmaxy(stdscr)-(msg_lines+4))/2;
+ x = (getmaxx(stdscr)-(total_width+4))/2;
+
+
+ /* create the windows */
+ if (btn_num > 0)
+ win_rows = msg_lines+4;
+ else
+ win_rows = msg_lines+2;
+
+ win = newwin(win_rows, total_width+4, y, x);
+ keypad(win, TRUE);
+ menu_win = derwin(win, 1, btns_width, win_rows-2,
+ 1+(total_width+2-btns_width)/2);
+ menu = new_menu(btns);
+ msg_win = derwin(win, win_rows-2, msg_width, 1,
+ 1+(total_width+2-msg_width)/2);
+
+ set_menu_fore(menu, attributes[DIALOG_MENU_FORE]);
+ set_menu_back(menu, attributes[DIALOG_MENU_BACK]);
+
+ (void) wattrset(win, attributes[DIALOG_BOX]);
+ box(win, 0, 0);
+
+ /* print message */
+ (void) wattrset(msg_win, attributes[DIALOG_TEXT]);
+ fill_window(msg_win, msg);
+
+ set_menu_win(menu, win);
+ set_menu_sub(menu, menu_win);
+ set_menu_format(menu, 1, btn_num);
+ menu_opts_off(menu, O_SHOWDESC);
+ menu_opts_off(menu, O_SHOWMATCH);
+ menu_opts_on(menu, O_ONEVALUE);
+ menu_opts_on(menu, O_NONCYCLIC);
+ set_menu_mark(menu, "");
+ post_menu(menu);
+
+
+ touchwin(win);
+ refresh_all_windows(main_window);
+ while ((res = wgetch(win))) {
+ switch (res) {
+ case KEY_LEFT:
+ menu_driver(menu, REQ_LEFT_ITEM);
+ break;
+ case KEY_RIGHT:
+ menu_driver(menu, REQ_RIGHT_ITEM);
+ break;
+ case 10: /* ENTER */
+ case 27: /* ESCAPE */
+ case ' ':
+ case KEY_F(F_BACK):
+ case KEY_F(F_EXIT):
+ break;
+ }
+ touchwin(win);
+ refresh_all_windows(main_window);
+
+ if (res == 10 || res == ' ') {
+ res = item_index(current_item(menu));
+ break;
+ } else if (res == 27 || res == KEY_F(F_BACK) ||
+ res == KEY_F(F_EXIT)) {
+ res = KEY_EXIT;
+ break;
+ }
+ }
+
+ unpost_menu(menu);
+ free_menu(menu);
+ for (i = 0; i < btn_num; i++)
+ free_item(btns[i]);
+
+ delwin(win);
+ return res;
+}
+
+int dialog_inputbox(WINDOW *main_window,
+ const char *title, const char *prompt,
+ const char *init, char **resultp, int *result_len)
+{
+ int prompt_lines = 0;
+ int prompt_width = 0;
+ WINDOW *win;
+ WINDOW *prompt_win;
+ WINDOW *form_win;
+ PANEL *panel;
+ int i, x, y;
+ int res = -1;
+ int cursor_position = strlen(init);
+ int cursor_form_win;
+ char *result = *resultp;
+
+ if (strlen(init)+1 > *result_len) {
+ *result_len = strlen(init)+1;
+ *resultp = result = realloc(result, *result_len);
+ }
+
+ /* find the widest line of msg: */
+ prompt_lines = get_line_no(prompt);
+ for (i = 0; i < prompt_lines; i++) {
+ const char *line = get_line(prompt, i);
+ int len = get_line_length(line);
+ prompt_width = max(prompt_width, len);
+ }
+
+ if (title)
+ prompt_width = max(prompt_width, strlen(title));
+
+ /* place dialog in middle of screen */
+ y = (getmaxy(stdscr)-(prompt_lines+4))/2;
+ x = (getmaxx(stdscr)-(prompt_width+4))/2;
+
+ strncpy(result, init, *result_len);
+
+ /* create the windows */
+ win = newwin(prompt_lines+6, prompt_width+7, y, x);
+ prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
+ form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
+ keypad(form_win, TRUE);
+
+ (void) wattrset(form_win, attributes[INPUT_FIELD]);
+
+ (void) wattrset(win, attributes[INPUT_BOX]);
+ box(win, 0, 0);
+ (void) wattrset(win, attributes[INPUT_HEADING]);
+ if (title)
+ mvwprintw(win, 0, 3, "%s", title);
+
+ /* print message */
+ (void) wattrset(prompt_win, attributes[INPUT_TEXT]);
+ fill_window(prompt_win, prompt);
+
+ mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
+ cursor_form_win = min(cursor_position, prompt_width-1);
+ mvwprintw(form_win, 0, 0, "%s",
+ result + cursor_position-cursor_form_win);
+
+ /* create panels */
+ panel = new_panel(win);
+
+ /* show the cursor */
+ curs_set(1);
+
+ touchwin(win);
+ refresh_all_windows(main_window);
+ while ((res = wgetch(form_win))) {
+ int len = strlen(result);
+ switch (res) {
+ case 10: /* ENTER */
+ case 27: /* ESCAPE */
+ case KEY_F(F_HELP):
+ case KEY_F(F_EXIT):
+ case KEY_F(F_BACK):
+ break;
+ case 127:
+ case KEY_BACKSPACE:
+ if (cursor_position > 0) {
+ memmove(&result[cursor_position-1],
+ &result[cursor_position],
+ len-cursor_position+1);
+ cursor_position--;
+ cursor_form_win--;
+ len--;
+ }
+ break;
+ case KEY_DC:
+ if (cursor_position >= 0 && cursor_position < len) {
+ memmove(&result[cursor_position],
+ &result[cursor_position+1],
+ len-cursor_position+1);
+ len--;
+ }
+ break;
+ case KEY_UP:
+ case KEY_RIGHT:
+ if (cursor_position < len) {
+ cursor_position++;
+ cursor_form_win++;
+ }
+ break;
+ case KEY_DOWN:
+ case KEY_LEFT:
+ if (cursor_position > 0) {
+ cursor_position--;
+ cursor_form_win--;
+ }
+ break;
+ case KEY_HOME:
+ cursor_position = 0;
+ cursor_form_win = 0;
+ break;
+ case KEY_END:
+ cursor_position = len;
+ cursor_form_win = min(cursor_position, prompt_width-1);
+ break;
+ default:
+ if ((isgraph(res) || isspace(res))) {
+ /* one for new char, one for '\0' */
+ if (len+2 > *result_len) {
+ *result_len = len+2;
+ *resultp = result = realloc(result,
+ *result_len);
+ }
+ /* insert the char at the proper position */
+ memmove(&result[cursor_position+1],
+ &result[cursor_position],
+ len-cursor_position+1);
+ result[cursor_position] = res;
+ cursor_position++;
+ cursor_form_win++;
+ len++;
+ } else {
+ mvprintw(0, 0, "unknown key: %d\n", res);
+ }
+ break;
+ }
+ if (cursor_form_win < 0)
+ cursor_form_win = 0;
+ else if (cursor_form_win > prompt_width-1)
+ cursor_form_win = prompt_width-1;
+
+ wmove(form_win, 0, 0);
+ wclrtoeol(form_win);
+ mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
+ mvwprintw(form_win, 0, 0, "%s",
+ result + cursor_position-cursor_form_win);
+ wmove(form_win, 0, cursor_form_win);
+ touchwin(win);
+ refresh_all_windows(main_window);
+
+ if (res == 10) {
+ res = 0;
+ break;
+ } else if (res == 27 || res == KEY_F(F_BACK) ||
+ res == KEY_F(F_EXIT)) {
+ res = KEY_EXIT;
+ break;
+ } else if (res == KEY_F(F_HELP)) {
+ res = 1;
+ break;
+ }
+ }
+
+ /* hide the cursor */
+ curs_set(0);
+ del_panel(panel);
+ delwin(prompt_win);
+ delwin(form_win);
+ delwin(win);
+ return res;
+}
+
+/* refresh all windows in the correct order */
+void refresh_all_windows(WINDOW *main_window)
+{
+ update_panels();
+ touchwin(main_window);
+ refresh();
+}
+
+/* layman's scrollable window... */
+void show_scroll_win(WINDOW *main_window,
+ const char *title,
+ const char *text)
+{
+ int res;
+ int total_lines = get_line_no(text);
+ int x, y, lines, columns;
+ int start_x = 0, start_y = 0;
+ int text_lines = 0, text_cols = 0;
+ int total_cols = 0;
+ int win_cols = 0;
+ int win_lines = 0;
+ int i = 0;
+ WINDOW *win;
+ WINDOW *pad;
+ PANEL *panel;
+
+ getmaxyx(stdscr, lines, columns);
+
+ /* find the widest line of msg: */
+ total_lines = get_line_no(text);
+ for (i = 0; i < total_lines; i++) {
+ const char *line = get_line(text, i);
+ int len = get_line_length(line);
+ total_cols = max(total_cols, len+2);
+ }
+
+ /* create the pad */
+ pad = newpad(total_lines+10, total_cols+10);
+ (void) wattrset(pad, attributes[SCROLLWIN_TEXT]);
+ fill_window(pad, text);
+
+ win_lines = min(total_lines+4, lines-2);
+ win_cols = min(total_cols+2, columns-2);
+ text_lines = max(win_lines-4, 0);
+ text_cols = max(win_cols-2, 0);
+
+ /* place window in middle of screen */
+ y = (lines-win_lines)/2;
+ x = (columns-win_cols)/2;
+
+ win = newwin(win_lines, win_cols, y, x);
+ keypad(win, TRUE);
+ /* show the help in the help window, and show the help panel */
+ (void) wattrset(win, attributes[SCROLLWIN_BOX]);
+ box(win, 0, 0);
+ (void) wattrset(win, attributes[SCROLLWIN_HEADING]);
+ mvwprintw(win, 0, 3, " %s ", title);
+ panel = new_panel(win);
+
+ /* handle scrolling */
+ do {
+
+ copywin(pad, win, start_y, start_x, 2, 2, text_lines,
+ text_cols, 0);
+ print_in_middle(win,
+ text_lines+2,
+ 0,
+ text_cols,
+ "<OK>",
+ attributes[DIALOG_MENU_FORE]);
+ wrefresh(win);
+
+ res = wgetch(win);
+ switch (res) {
+ case KEY_NPAGE:
+ case ' ':
+ case 'd':
+ start_y += text_lines-2;
+ break;
+ case KEY_PPAGE:
+ case 'u':
+ start_y -= text_lines+2;
+ break;
+ case KEY_HOME:
+ start_y = 0;
+ break;
+ case KEY_END:
+ start_y = total_lines-text_lines;
+ break;
+ case KEY_DOWN:
+ case 'j':
+ start_y++;
+ break;
+ case KEY_UP:
+ case 'k':
+ start_y--;
+ break;
+ case KEY_LEFT:
+ case 'h':
+ start_x--;
+ break;
+ case KEY_RIGHT:
+ case 'l':
+ start_x++;
+ break;
+ }
+ if (res == 10 || res == 27 || res == 'q' ||
+ res == KEY_F(F_HELP) || res == KEY_F(F_BACK) ||
+ res == KEY_F(F_EXIT))
+ break;
+ if (start_y < 0)
+ start_y = 0;
+ if (start_y >= total_lines-text_lines)
+ start_y = total_lines-text_lines;
+ if (start_x < 0)
+ start_x = 0;
+ if (start_x >= total_cols-text_cols)
+ start_x = total_cols-text_cols;
+ } while (res);
+
+ del_panel(panel);
+ delwin(win);
+ refresh_all_windows(main_window);
+}
diff --git a/roms/seabios/scripts/kconfig/nconf.h b/roms/seabios/scripts/kconfig/nconf.h
new file mode 100644
index 00000000..0d526170
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/nconf.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+#include <curses.h>
+#include <menu.h>
+#include <panel.h>
+#include <form.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "ncurses.h"
+
+#define max(a, b) ({\
+ typeof(a) _a = a;\
+ typeof(b) _b = b;\
+ _a > _b ? _a : _b; })
+
+#define min(a, b) ({\
+ typeof(a) _a = a;\
+ typeof(b) _b = b;\
+ _a < _b ? _a : _b; })
+
+typedef enum {
+ NORMAL = 1,
+ MAIN_HEADING,
+ MAIN_MENU_BOX,
+ MAIN_MENU_FORE,
+ MAIN_MENU_BACK,
+ MAIN_MENU_GREY,
+ MAIN_MENU_HEADING,
+ SCROLLWIN_TEXT,
+ SCROLLWIN_HEADING,
+ SCROLLWIN_BOX,
+ DIALOG_TEXT,
+ DIALOG_MENU_FORE,
+ DIALOG_MENU_BACK,
+ DIALOG_BOX,
+ INPUT_BOX,
+ INPUT_HEADING,
+ INPUT_TEXT,
+ INPUT_FIELD,
+ FUNCTION_TEXT,
+ FUNCTION_HIGHLIGHT,
+ ATTR_MAX
+} attributes_t;
+extern attributes_t attributes[];
+
+typedef enum {
+ F_HELP = 1,
+ F_SYMBOL = 2,
+ F_INSTS = 3,
+ F_CONF = 4,
+ F_BACK = 5,
+ F_SAVE = 6,
+ F_LOAD = 7,
+ F_SEARCH = 8,
+ F_EXIT = 9,
+} function_key;
+
+void set_colors(void);
+
+/* this changes the windows attributes !!! */
+void print_in_middle(WINDOW *win,
+ int starty,
+ int startx,
+ int width,
+ const char *string,
+ chtype color);
+int get_line_length(const char *line);
+int get_line_no(const char *text);
+const char *get_line(const char *text, int line_no);
+void fill_window(WINDOW *win, const char *text);
+int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...);
+int dialog_inputbox(WINDOW *main_window,
+ const char *title, const char *prompt,
+ const char *init, char **resultp, int *result_len);
+void refresh_all_windows(WINDOW *main_window);
+void show_scroll_win(WINDOW *main_window,
+ const char *title,
+ const char *text);
diff --git a/roms/seabios/scripts/kconfig/qconf.cc b/roms/seabios/scripts/kconfig/qconf.cc
new file mode 100644
index 00000000..9d3b04b0
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/qconf.cc
@@ -0,0 +1,1795 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <qglobal.h>
+
+#if QT_VERSION < 0x040000
+#include <stddef.h>
+#include <qmainwindow.h>
+#include <qvbox.h>
+#include <qvaluelist.h>
+#include <qtextbrowser.h>
+#include <qaction.h>
+#include <qheader.h>
+#include <qfiledialog.h>
+#include <qdragobject.h>
+#include <qpopupmenu.h>
+#else
+#include <q3mainwindow.h>
+#include <q3vbox.h>
+#include <q3valuelist.h>
+#include <q3textbrowser.h>
+#include <q3action.h>
+#include <q3header.h>
+#include <q3filedialog.h>
+#include <q3dragobject.h>
+#include <q3popupmenu.h>
+#endif
+
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#include <qtoolbar.h>
+#include <qlayout.h>
+#include <qsplitter.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qmenubar.h>
+#include <qmessagebox.h>
+#include <qregexp.h>
+#include <qevent.h>
+
+#include <stdlib.h>
+
+#include "lkc.h"
+#include "qconf.h"
+
+#include "qconf.moc"
+#include "images.c"
+
+#ifdef _
+# undef _
+# define _ qgettext
+#endif
+
+static QApplication *configApp;
+static ConfigSettings *configSettings;
+
+Q3Action *ConfigMainWindow::saveAction;
+
+static inline QString qgettext(const char* str)
+{
+ return QString::fromLocal8Bit(gettext(str));
+}
+
+static inline QString qgettext(const QString& str)
+{
+ return QString::fromLocal8Bit(gettext(str.latin1()));
+}
+
+ConfigSettings::ConfigSettings()
+ : QSettings("kernel.org", "qconf")
+{
+}
+
+/**
+ * Reads a list of integer values from the application settings.
+ */
+Q3ValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
+{
+ Q3ValueList<int> result;
+ QStringList entryList = readListEntry(key, ok);
+ QStringList::Iterator it;
+
+ for (it = entryList.begin(); it != entryList.end(); ++it)
+ result.push_back((*it).toInt());
+
+ return result;
+}
+
+/**
+ * Writes a list of integer values to the application settings.
+ */
+bool ConfigSettings::writeSizes(const QString& key, const Q3ValueList<int>& value)
+{
+ QStringList stringList;
+ Q3ValueList<int>::ConstIterator it;
+
+ for (it = value.begin(); it != value.end(); ++it)
+ stringList.push_back(QString::number(*it));
+ return writeEntry(key, stringList);
+}
+
+
+/*
+ * set the new data
+ * TODO check the value
+ */
+void ConfigItem::okRename(int col)
+{
+ Parent::okRename(col);
+ sym_set_string_value(menu->sym, text(dataColIdx).latin1());
+ listView()->updateList(this);
+}
+
+/*
+ * update the displayed of a menu entry
+ */
+void ConfigItem::updateMenu(void)
+{
+ ConfigList* list;
+ struct symbol* sym;
+ struct property *prop;
+ QString prompt;
+ int type;
+ tristate expr;
+
+ list = listView();
+ if (goParent) {
+ setPixmap(promptColIdx, list->menuBackPix);
+ prompt = "..";
+ goto set_prompt;
+ }
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ prompt = _(menu_get_prompt(menu));
+
+ if (prop) switch (prop->type) {
+ case P_MENU:
+ if (list->mode == singleMode || list->mode == symbolMode) {
+ /* a menuconfig entry is displayed differently
+ * depending whether it's at the view root or a child.
+ */
+ if (sym && list->rootEntry == menu)
+ break;
+ setPixmap(promptColIdx, list->menuPix);
+ } else {
+ if (sym)
+ break;
+ setPixmap(promptColIdx, 0);
+ }
+ goto set_prompt;
+ case P_COMMENT:
+ setPixmap(promptColIdx, 0);
+ goto set_prompt;
+ default:
+ ;
+ }
+ if (!sym)
+ goto set_prompt;
+
+ setText(nameColIdx, QString::fromLocal8Bit(sym->name));
+
+ type = sym_get_type(sym);
+ switch (type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ char ch;
+
+ if (!sym_is_changable(sym) && list->optMode == normalOpt) {
+ setPixmap(promptColIdx, 0);
+ setText(noColIdx, QString::null);
+ setText(modColIdx, QString::null);
+ setText(yesColIdx, QString::null);
+ break;
+ }
+ expr = sym_get_tristate_value(sym);
+ switch (expr) {
+ case yes:
+ if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+ setPixmap(promptColIdx, list->choiceYesPix);
+ else
+ setPixmap(promptColIdx, list->symbolYesPix);
+ setText(yesColIdx, "Y");
+ ch = 'Y';
+ break;
+ case mod:
+ setPixmap(promptColIdx, list->symbolModPix);
+ setText(modColIdx, "M");
+ ch = 'M';
+ break;
+ default:
+ if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+ setPixmap(promptColIdx, list->choiceNoPix);
+ else
+ setPixmap(promptColIdx, list->symbolNoPix);
+ setText(noColIdx, "N");
+ ch = 'N';
+ break;
+ }
+ if (expr != no)
+ setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
+ if (expr != mod)
+ setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
+ if (expr != yes)
+ setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
+
+ setText(dataColIdx, QChar(ch));
+ break;
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ const char* data;
+
+ data = sym_get_string_value(sym);
+
+ int i = list->mapIdx(dataColIdx);
+ if (i >= 0)
+ setRenameEnabled(i, TRUE);
+ setText(dataColIdx, data);
+ if (type == S_STRING)
+ prompt = QString("%1: %2").arg(prompt).arg(data);
+ else
+ prompt = QString("(%2) %1").arg(prompt).arg(data);
+ break;
+ }
+ if (!sym_has_value(sym) && visible)
+ prompt += _(" (NEW)");
+set_prompt:
+ setText(promptColIdx, prompt);
+}
+
+void ConfigItem::testUpdateMenu(bool v)
+{
+ ConfigItem* i;
+
+ visible = v;
+ if (!menu)
+ return;
+
+ sym_calc_value(menu->sym);
+ if (menu->flags & MENU_CHANGED) {
+ /* the menu entry changed, so update all list items */
+ menu->flags &= ~MENU_CHANGED;
+ for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
+ i->updateMenu();
+ } else if (listView()->updateAll)
+ updateMenu();
+}
+
+void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align)
+{
+ ConfigList* list = listView();
+
+ if (visible) {
+ if (isSelected() && !list->hasFocus() && list->mode == menuMode)
+ Parent::paintCell(p, list->inactivedColorGroup, column, width, align);
+ else
+ Parent::paintCell(p, cg, column, width, align);
+ } else
+ Parent::paintCell(p, list->disabledColorGroup, column, width, align);
+}
+
+/*
+ * construct a menu entry
+ */
+void ConfigItem::init(void)
+{
+ if (menu) {
+ ConfigList* list = listView();
+ nextItem = (ConfigItem*)menu->data;
+ menu->data = this;
+
+ if (list->mode != fullMode)
+ setOpen(TRUE);
+ sym_calc_value(menu->sym);
+ }
+ updateMenu();
+}
+
+/*
+ * destruct a menu entry
+ */
+ConfigItem::~ConfigItem(void)
+{
+ if (menu) {
+ ConfigItem** ip = (ConfigItem**)&menu->data;
+ for (; *ip; ip = &(*ip)->nextItem) {
+ if (*ip == this) {
+ *ip = nextItem;
+ break;
+ }
+ }
+ }
+}
+
+ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
+ : Parent(parent)
+{
+ connect(this, SIGNAL(lostFocus()), SLOT(hide()));
+}
+
+void ConfigLineEdit::show(ConfigItem* i)
+{
+ item = i;
+ if (sym_get_string_value(item->menu->sym))
+ setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
+ else
+ setText(QString::null);
+ Parent::show();
+ setFocus();
+}
+
+void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
+{
+ switch (e->key()) {
+ case Qt::Key_Escape:
+ break;
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ sym_set_string_value(item->menu->sym, text().latin1());
+ parent()->updateList(item);
+ break;
+ default:
+ Parent::keyPressEvent(e);
+ return;
+ }
+ e->accept();
+ parent()->list->setFocus();
+ hide();
+}
+
+ConfigList::ConfigList(ConfigView* p, const char *name)
+ : Parent(p, name),
+ updateAll(false),
+ symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
+ choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
+ menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
+ showName(false), showRange(false), showData(false), optMode(normalOpt),
+ rootEntry(0), headerPopup(0)
+{
+ int i;
+
+ setSorting(-1);
+ setRootIsDecorated(TRUE);
+ disabledColorGroup = palette().active();
+ disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text());
+ inactivedColorGroup = palette().active();
+ inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight());
+
+ connect(this, SIGNAL(selectionChanged(void)),
+ SLOT(updateSelection(void)));
+
+ if (name) {
+ configSettings->beginGroup(name);
+ showName = configSettings->readBoolEntry("/showName", false);
+ showRange = configSettings->readBoolEntry("/showRange", false);
+ showData = configSettings->readBoolEntry("/showData", false);
+ optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", false);
+ configSettings->endGroup();
+ connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+ }
+
+ for (i = 0; i < colNr; i++)
+ colMap[i] = colRevMap[i] = -1;
+ addColumn(promptColIdx, _("Option"));
+
+ reinit();
+}
+
+bool ConfigList::menuSkip(struct menu *menu)
+{
+ if (optMode == normalOpt && menu_is_visible(menu))
+ return false;
+ if (optMode == promptOpt && menu_has_prompt(menu))
+ return false;
+ if (optMode == allOpt)
+ return false;
+ return true;
+}
+
+void ConfigList::reinit(void)
+{
+ removeColumn(dataColIdx);
+ removeColumn(yesColIdx);
+ removeColumn(modColIdx);
+ removeColumn(noColIdx);
+ removeColumn(nameColIdx);
+
+ if (showName)
+ addColumn(nameColIdx, _("Name"));
+ if (showRange) {
+ addColumn(noColIdx, "N");
+ addColumn(modColIdx, "M");
+ addColumn(yesColIdx, "Y");
+ }
+ if (showData)
+ addColumn(dataColIdx, _("Value"));
+
+ updateListAll();
+}
+
+void ConfigList::saveSettings(void)
+{
+ if (name()) {
+ configSettings->beginGroup(name());
+ configSettings->writeEntry("/showName", showName);
+ configSettings->writeEntry("/showRange", showRange);
+ configSettings->writeEntry("/showData", showData);
+ configSettings->writeEntry("/optionMode", (int)optMode);
+ configSettings->endGroup();
+ }
+}
+
+ConfigItem* ConfigList::findConfigItem(struct menu *menu)
+{
+ ConfigItem* item = (ConfigItem*)menu->data;
+
+ for (; item; item = item->nextItem) {
+ if (this == item->listView())
+ break;
+ }
+
+ return item;
+}
+
+void ConfigList::updateSelection(void)
+{
+ struct menu *menu;
+ enum prop_type type;
+
+ ConfigItem* item = (ConfigItem*)selectedItem();
+ if (!item)
+ return;
+
+ menu = item->menu;
+ emit menuChanged(menu);
+ if (!menu)
+ return;
+ type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ if (mode == menuMode && type == P_MENU)
+ emit menuSelected(menu);
+}
+
+void ConfigList::updateList(ConfigItem* item)
+{
+ ConfigItem* last = 0;
+
+ if (!rootEntry) {
+ if (mode != listMode)
+ goto update;
+ Q3ListViewItemIterator it(this);
+ ConfigItem* item;
+
+ for (; it.current(); ++it) {
+ item = (ConfigItem*)it.current();
+ if (!item->menu)
+ continue;
+ item->testUpdateMenu(menu_is_visible(item->menu));
+ }
+ return;
+ }
+
+ if (rootEntry != &rootmenu && (mode == singleMode ||
+ (mode == symbolMode && rootEntry->parent != &rootmenu))) {
+ item = firstChild();
+ if (!item)
+ item = new ConfigItem(this, 0, true);
+ last = item;
+ }
+ if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
+ rootEntry->sym && rootEntry->prompt) {
+ item = last ? last->nextSibling() : firstChild();
+ if (!item)
+ item = new ConfigItem(this, last, rootEntry, true);
+ else
+ item->testUpdateMenu(true);
+
+ updateMenuList(item, rootEntry);
+ triggerUpdate();
+ return;
+ }
+update:
+ updateMenuList(this, rootEntry);
+ triggerUpdate();
+}
+
+void ConfigList::setValue(ConfigItem* item, tristate val)
+{
+ struct symbol* sym;
+ int type;
+ tristate oldval;
+
+ sym = item->menu ? item->menu->sym : 0;
+ if (!sym)
+ return;
+
+ type = sym_get_type(sym);
+ switch (type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ oldval = sym_get_tristate_value(sym);
+
+ if (!sym_set_tristate_value(sym, val))
+ return;
+ if (oldval == no && item->menu->list)
+ item->setOpen(TRUE);
+ parent()->updateList(item);
+ break;
+ }
+}
+
+void ConfigList::changeValue(ConfigItem* item)
+{
+ struct symbol* sym;
+ struct menu* menu;
+ int type, oldexpr, newexpr;
+
+ menu = item->menu;
+ if (!menu)
+ return;
+ sym = menu->sym;
+ if (!sym) {
+ if (item->menu->list)
+ item->setOpen(!item->isOpen());
+ return;
+ }
+
+ type = sym_get_type(sym);
+ switch (type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ oldexpr = sym_get_tristate_value(sym);
+ newexpr = sym_toggle_tristate_value(sym);
+ if (item->menu->list) {
+ if (oldexpr == newexpr)
+ item->setOpen(!item->isOpen());
+ else if (oldexpr == no)
+ item->setOpen(TRUE);
+ }
+ if (oldexpr != newexpr)
+ parent()->updateList(item);
+ break;
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ if (colMap[dataColIdx] >= 0)
+ item->startRename(colMap[dataColIdx]);
+ else
+ parent()->lineEdit->show(item);
+ break;
+ }
+}
+
+void ConfigList::setRootMenu(struct menu *menu)
+{
+ enum prop_type type;
+
+ if (rootEntry == menu)
+ return;
+ type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ if (type != P_MENU)
+ return;
+ updateMenuList(this, 0);
+ rootEntry = menu;
+ updateListAll();
+ setSelected(currentItem(), hasFocus());
+ ensureItemVisible(currentItem());
+}
+
+void ConfigList::setParentMenu(void)
+{
+ ConfigItem* item;
+ struct menu *oldroot;
+
+ oldroot = rootEntry;
+ if (rootEntry == &rootmenu)
+ return;
+ setRootMenu(menu_get_parent_menu(rootEntry->parent));
+
+ Q3ListViewItemIterator it(this);
+ for (; (item = (ConfigItem*)it.current()); it++) {
+ if (item->menu == oldroot) {
+ setCurrentItem(item);
+ ensureItemVisible(item);
+ break;
+ }
+ }
+}
+
+/*
+ * update all the children of a menu entry
+ * removes/adds the entries from the parent widget as necessary
+ *
+ * parent: either the menu list widget or a menu entry widget
+ * menu: entry to be updated
+ */
+template <class P>
+void ConfigList::updateMenuList(P* parent, struct menu* menu)
+{
+ struct menu* child;
+ ConfigItem* item;
+ ConfigItem* last;
+ bool visible;
+ enum prop_type type;
+
+ if (!menu) {
+ while ((item = parent->firstChild()))
+ delete item;
+ return;
+ }
+
+ last = parent->firstChild();
+ if (last && !last->goParent)
+ last = 0;
+ for (child = menu->list; child; child = child->next) {
+ item = last ? last->nextSibling() : parent->firstChild();
+ type = child->prompt ? child->prompt->type : P_UNKNOWN;
+
+ switch (mode) {
+ case menuMode:
+ if (!(child->flags & MENU_ROOT))
+ goto hide;
+ break;
+ case symbolMode:
+ if (child->flags & MENU_ROOT)
+ goto hide;
+ break;
+ default:
+ break;
+ }
+
+ visible = menu_is_visible(child);
+ if (!menuSkip(child)) {
+ if (!child->sym && !child->list && !child->prompt)
+ continue;
+ if (!item || item->menu != child)
+ item = new ConfigItem(parent, last, child, visible);
+ else
+ item->testUpdateMenu(visible);
+
+ if (mode == fullMode || mode == menuMode || type != P_MENU)
+ updateMenuList(item, child);
+ else
+ updateMenuList(item, 0);
+ last = item;
+ continue;
+ }
+ hide:
+ if (item && item->menu == child) {
+ last = parent->firstChild();
+ if (last == item)
+ last = 0;
+ else while (last->nextSibling() != item)
+ last = last->nextSibling();
+ delete item;
+ }
+ }
+}
+
+void ConfigList::keyPressEvent(QKeyEvent* ev)
+{
+ Q3ListViewItem* i = currentItem();
+ ConfigItem* item;
+ struct menu *menu;
+ enum prop_type type;
+
+ if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
+ emit parentSelected();
+ ev->accept();
+ return;
+ }
+
+ if (!i) {
+ Parent::keyPressEvent(ev);
+ return;
+ }
+ item = (ConfigItem*)i;
+
+ switch (ev->key()) {
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ if (item->goParent) {
+ emit parentSelected();
+ break;
+ }
+ menu = item->menu;
+ if (!menu)
+ break;
+ type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ if (type == P_MENU && rootEntry != menu &&
+ mode != fullMode && mode != menuMode) {
+ emit menuSelected(menu);
+ break;
+ }
+ case Qt::Key_Space:
+ changeValue(item);
+ break;
+ case Qt::Key_N:
+ setValue(item, no);
+ break;
+ case Qt::Key_M:
+ setValue(item, mod);
+ break;
+ case Qt::Key_Y:
+ setValue(item, yes);
+ break;
+ default:
+ Parent::keyPressEvent(ev);
+ return;
+ }
+ ev->accept();
+}
+
+void ConfigList::contentsMousePressEvent(QMouseEvent* e)
+{
+ //QPoint p(contentsToViewport(e->pos()));
+ //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
+ Parent::contentsMousePressEvent(e);
+}
+
+void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
+{
+ QPoint p(contentsToViewport(e->pos()));
+ ConfigItem* item = (ConfigItem*)itemAt(p);
+ struct menu *menu;
+ enum prop_type ptype;
+ const QPixmap* pm;
+ int idx, x;
+
+ if (!item)
+ goto skip;
+
+ menu = item->menu;
+ x = header()->offset() + p.x();
+ idx = colRevMap[header()->sectionAt(x)];
+ switch (idx) {
+ case promptColIdx:
+ pm = item->pixmap(promptColIdx);
+ if (pm) {
+ int off = header()->sectionPos(0) + itemMargin() +
+ treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
+ if (x >= off && x < off + pm->width()) {
+ if (item->goParent) {
+ emit parentSelected();
+ break;
+ } else if (!menu)
+ break;
+ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ if (ptype == P_MENU && rootEntry != menu &&
+ mode != fullMode && mode != menuMode)
+ emit menuSelected(menu);
+ else
+ changeValue(item);
+ }
+ }
+ break;
+ case noColIdx:
+ setValue(item, no);
+ break;
+ case modColIdx:
+ setValue(item, mod);
+ break;
+ case yesColIdx:
+ setValue(item, yes);
+ break;
+ case dataColIdx:
+ changeValue(item);
+ break;
+ }
+
+skip:
+ //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
+ Parent::contentsMouseReleaseEvent(e);
+}
+
+void ConfigList::contentsMouseMoveEvent(QMouseEvent* e)
+{
+ //QPoint p(contentsToViewport(e->pos()));
+ //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
+ Parent::contentsMouseMoveEvent(e);
+}
+
+void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
+{
+ QPoint p(contentsToViewport(e->pos()));
+ ConfigItem* item = (ConfigItem*)itemAt(p);
+ struct menu *menu;
+ enum prop_type ptype;
+
+ if (!item)
+ goto skip;
+ if (item->goParent) {
+ emit parentSelected();
+ goto skip;
+ }
+ menu = item->menu;
+ if (!menu)
+ goto skip;
+ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
+ emit menuSelected(menu);
+ else if (menu->sym)
+ changeValue(item);
+
+skip:
+ //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
+ Parent::contentsMouseDoubleClickEvent(e);
+}
+
+void ConfigList::focusInEvent(QFocusEvent *e)
+{
+ struct menu *menu = NULL;
+
+ Parent::focusInEvent(e);
+
+ ConfigItem* item = (ConfigItem *)currentItem();
+ if (item) {
+ setSelected(item, TRUE);
+ menu = item->menu;
+ }
+ emit gotFocus(menu);
+}
+
+void ConfigList::contextMenuEvent(QContextMenuEvent *e)
+{
+ if (e->y() <= header()->geometry().bottom()) {
+ if (!headerPopup) {
+ Q3Action *action;
+
+ headerPopup = new Q3PopupMenu(this);
+ action = new Q3Action(NULL, _("Show Name"), 0, this);
+ action->setToggleAction(TRUE);
+ connect(action, SIGNAL(toggled(bool)),
+ parent(), SLOT(setShowName(bool)));
+ connect(parent(), SIGNAL(showNameChanged(bool)),
+ action, SLOT(setOn(bool)));
+ action->setOn(showName);
+ action->addTo(headerPopup);
+ action = new Q3Action(NULL, _("Show Range"), 0, this);
+ action->setToggleAction(TRUE);
+ connect(action, SIGNAL(toggled(bool)),
+ parent(), SLOT(setShowRange(bool)));
+ connect(parent(), SIGNAL(showRangeChanged(bool)),
+ action, SLOT(setOn(bool)));
+ action->setOn(showRange);
+ action->addTo(headerPopup);
+ action = new Q3Action(NULL, _("Show Data"), 0, this);
+ action->setToggleAction(TRUE);
+ connect(action, SIGNAL(toggled(bool)),
+ parent(), SLOT(setShowData(bool)));
+ connect(parent(), SIGNAL(showDataChanged(bool)),
+ action, SLOT(setOn(bool)));
+ action->setOn(showData);
+ action->addTo(headerPopup);
+ }
+ headerPopup->exec(e->globalPos());
+ e->accept();
+ } else
+ e->ignore();
+}
+
+ConfigView*ConfigView::viewList;
+QAction *ConfigView::showNormalAction;
+QAction *ConfigView::showAllAction;
+QAction *ConfigView::showPromptAction;
+
+ConfigView::ConfigView(QWidget* parent, const char *name)
+ : Parent(parent, name)
+{
+ list = new ConfigList(this, name);
+ lineEdit = new ConfigLineEdit(this);
+ lineEdit->hide();
+
+ this->nextView = viewList;
+ viewList = this;
+}
+
+ConfigView::~ConfigView(void)
+{
+ ConfigView** vp;
+
+ for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
+ if (*vp == this) {
+ *vp = nextView;
+ break;
+ }
+ }
+}
+
+void ConfigView::setOptionMode(QAction *act)
+{
+ if (act == showNormalAction)
+ list->optMode = normalOpt;
+ else if (act == showAllAction)
+ list->optMode = allOpt;
+ else
+ list->optMode = promptOpt;
+
+ list->updateListAll();
+}
+
+void ConfigView::setShowName(bool b)
+{
+ if (list->showName != b) {
+ list->showName = b;
+ list->reinit();
+ emit showNameChanged(b);
+ }
+}
+
+void ConfigView::setShowRange(bool b)
+{
+ if (list->showRange != b) {
+ list->showRange = b;
+ list->reinit();
+ emit showRangeChanged(b);
+ }
+}
+
+void ConfigView::setShowData(bool b)
+{
+ if (list->showData != b) {
+ list->showData = b;
+ list->reinit();
+ emit showDataChanged(b);
+ }
+}
+
+void ConfigList::setAllOpen(bool open)
+{
+ Q3ListViewItemIterator it(this);
+
+ for (; it.current(); it++)
+ it.current()->setOpen(open);
+}
+
+void ConfigView::updateList(ConfigItem* item)
+{
+ ConfigView* v;
+
+ for (v = viewList; v; v = v->nextView)
+ v->list->updateList(item);
+}
+
+void ConfigView::updateListAll(void)
+{
+ ConfigView* v;
+
+ for (v = viewList; v; v = v->nextView)
+ v->list->updateListAll();
+}
+
+ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
+ : Parent(parent, name), sym(0), _menu(0)
+{
+ if (name) {
+ configSettings->beginGroup(name);
+ _showDebug = configSettings->readBoolEntry("/showDebug", false);
+ configSettings->endGroup();
+ connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+ }
+}
+
+void ConfigInfoView::saveSettings(void)
+{
+ if (name()) {
+ configSettings->beginGroup(name());
+ configSettings->writeEntry("/showDebug", showDebug());
+ configSettings->endGroup();
+ }
+}
+
+void ConfigInfoView::setShowDebug(bool b)
+{
+ if (_showDebug != b) {
+ _showDebug = b;
+ if (_menu)
+ menuInfo();
+ else if (sym)
+ symbolInfo();
+ emit showDebugChanged(b);
+ }
+}
+
+void ConfigInfoView::setInfo(struct menu *m)
+{
+ if (_menu == m)
+ return;
+ _menu = m;
+ sym = NULL;
+ if (!_menu)
+ clear();
+ else
+ menuInfo();
+}
+
+void ConfigInfoView::symbolInfo(void)
+{
+ QString str;
+
+ str += "<big>Symbol: <b>";
+ str += print_filter(sym->name);
+ str += "</b></big><br><br>value: ";
+ str += print_filter(sym_get_string_value(sym));
+ str += "<br>visibility: ";
+ str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
+ str += "<br>";
+ str += debug_info(sym);
+
+ setText(str);
+}
+
+void ConfigInfoView::menuInfo(void)
+{
+ struct symbol* sym;
+ QString head, debug, help;
+
+ sym = _menu->sym;
+ if (sym) {
+ if (_menu->prompt) {
+ head += "<big><b>";
+ head += print_filter(_(_menu->prompt->text));
+ head += "</b></big>";
+ if (sym->name) {
+ head += " (";
+ if (showDebug())
+ head += QString().sprintf("<a href=\"s%p\">", sym);
+ head += print_filter(sym->name);
+ if (showDebug())
+ head += "</a>";
+ head += ")";
+ }
+ } else if (sym->name) {
+ head += "<big><b>";
+ if (showDebug())
+ head += QString().sprintf("<a href=\"s%p\">", sym);
+ head += print_filter(sym->name);
+ if (showDebug())
+ head += "</a>";
+ head += "</b></big>";
+ }
+ head += "<br><br>";
+
+ if (showDebug())
+ debug = debug_info(sym);
+
+ struct gstr help_gstr = str_new();
+ menu_get_ext_help(_menu, &help_gstr);
+ help = print_filter(str_get(&help_gstr));
+ str_free(&help_gstr);
+ } else if (_menu->prompt) {
+ head += "<big><b>";
+ head += print_filter(_(_menu->prompt->text));
+ head += "</b></big><br><br>";
+ if (showDebug()) {
+ if (_menu->prompt->visible.expr) {
+ debug += "&nbsp;&nbsp;dep: ";
+ expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
+ debug += "<br><br>";
+ }
+ }
+ }
+ if (showDebug())
+ debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
+
+ setText(head + debug + help);
+}
+
+QString ConfigInfoView::debug_info(struct symbol *sym)
+{
+ QString debug;
+
+ debug += "type: ";
+ debug += print_filter(sym_type_name(sym->type));
+ if (sym_is_choice(sym))
+ debug += " (choice)";
+ debug += "<br>";
+ if (sym->rev_dep.expr) {
+ debug += "reverse dep: ";
+ expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
+ debug += "<br>";
+ }
+ for (struct property *prop = sym->prop; prop; prop = prop->next) {
+ switch (prop->type) {
+ case P_PROMPT:
+ case P_MENU:
+ debug += QString().sprintf("prompt: <a href=\"m%p\">", prop->menu);
+ debug += print_filter(_(prop->text));
+ debug += "</a><br>";
+ break;
+ case P_DEFAULT:
+ case P_SELECT:
+ case P_RANGE:
+ case P_ENV:
+ debug += prop_get_type_name(prop->type);
+ debug += ": ";
+ expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+ debug += "<br>";
+ break;
+ case P_CHOICE:
+ if (sym_is_choice(sym)) {
+ debug += "choice: ";
+ expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+ debug += "<br>";
+ }
+ break;
+ default:
+ debug += "unknown property: ";
+ debug += prop_get_type_name(prop->type);
+ debug += "<br>";
+ }
+ if (prop->visible.expr) {
+ debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
+ expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
+ debug += "<br>";
+ }
+ }
+ debug += "<br>";
+
+ return debug;
+}
+
+QString ConfigInfoView::print_filter(const QString &str)
+{
+ QRegExp re("[<>&\"\\n]");
+ QString res = str;
+ for (int i = 0; (i = res.find(re, i)) >= 0;) {
+ switch (res[i].latin1()) {
+ case '<':
+ res.replace(i, 1, "&lt;");
+ i += 4;
+ break;
+ case '>':
+ res.replace(i, 1, "&gt;");
+ i += 4;
+ break;
+ case '&':
+ res.replace(i, 1, "&amp;");
+ i += 5;
+ break;
+ case '"':
+ res.replace(i, 1, "&quot;");
+ i += 6;
+ break;
+ case '\n':
+ res.replace(i, 1, "<br>");
+ i += 4;
+ break;
+ }
+ }
+ return res;
+}
+
+void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
+{
+ QString* text = reinterpret_cast<QString*>(data);
+ QString str2 = print_filter(str);
+
+ if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
+ *text += QString().sprintf("<a href=\"s%p\">", sym);
+ *text += str2;
+ *text += "</a>";
+ } else
+ *text += str2;
+}
+
+Q3PopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
+{
+ Q3PopupMenu* popup = Parent::createPopupMenu(pos);
+ Q3Action* action = new Q3Action(NULL, _("Show Debug Info"), 0, popup);
+ action->setToggleAction(TRUE);
+ connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
+ connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
+ action->setOn(showDebug());
+ popup->insertSeparator();
+ action->addTo(popup);
+ return popup;
+}
+
+void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e)
+{
+ Parent::contentsContextMenuEvent(e);
+}
+
+ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
+ : Parent(parent, name), result(NULL)
+{
+ setCaption("Search Config");
+
+ QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6);
+ QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6);
+ layout2->addWidget(new QLabel(_("Find:"), this));
+ editField = new QLineEdit(this);
+ connect(editField, SIGNAL(returnPressed()), SLOT(search()));
+ layout2->addWidget(editField);
+ searchButton = new QPushButton(_("Search"), this);
+ searchButton->setAutoDefault(FALSE);
+ connect(searchButton, SIGNAL(clicked()), SLOT(search()));
+ layout2->addWidget(searchButton);
+ layout1->addLayout(layout2);
+
+ split = new QSplitter(this);
+ split->setOrientation(Qt::Vertical);
+ list = new ConfigView(split, name);
+ list->list->mode = listMode;
+ info = new ConfigInfoView(split, name);
+ connect(list->list, SIGNAL(menuChanged(struct menu *)),
+ info, SLOT(setInfo(struct menu *)));
+ connect(list->list, SIGNAL(menuChanged(struct menu *)),
+ parent, SLOT(setMenuLink(struct menu *)));
+
+ layout1->addWidget(split);
+
+ if (name) {
+ int x, y, width, height;
+ bool ok;
+
+ configSettings->beginGroup(name);
+ width = configSettings->readNumEntry("/window width", parent->width() / 2);
+ height = configSettings->readNumEntry("/window height", parent->height() / 2);
+ resize(width, height);
+ x = configSettings->readNumEntry("/window x", 0, &ok);
+ if (ok)
+ y = configSettings->readNumEntry("/window y", 0, &ok);
+ if (ok)
+ move(x, y);
+ Q3ValueList<int> sizes = configSettings->readSizes("/split", &ok);
+ if (ok)
+ split->setSizes(sizes);
+ configSettings->endGroup();
+ connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+ }
+}
+
+void ConfigSearchWindow::saveSettings(void)
+{
+ if (name()) {
+ configSettings->beginGroup(name());
+ configSettings->writeEntry("/window x", pos().x());
+ configSettings->writeEntry("/window y", pos().y());
+ configSettings->writeEntry("/window width", size().width());
+ configSettings->writeEntry("/window height", size().height());
+ configSettings->writeSizes("/split", split->sizes());
+ configSettings->endGroup();
+ }
+}
+
+void ConfigSearchWindow::search(void)
+{
+ struct symbol **p;
+ struct property *prop;
+ ConfigItem *lastItem = NULL;
+
+ free(result);
+ list->list->clear();
+ info->clear();
+
+ result = sym_re_search(editField->text().latin1());
+ if (!result)
+ return;
+ for (p = result; *p; p++) {
+ for_all_prompts((*p), prop)
+ lastItem = new ConfigItem(list->list, lastItem, prop->menu,
+ menu_is_visible(prop->menu));
+ }
+}
+
+/*
+ * Construct the complete config widget
+ */
+ConfigMainWindow::ConfigMainWindow(void)
+ : searchWindow(0)
+{
+ QMenuBar* menu;
+ bool ok;
+ int x, y, width, height;
+ char title[256];
+
+ QDesktopWidget *d = configApp->desktop();
+ snprintf(title, sizeof(title), "%s%s",
+ rootmenu.prompt->text,
+#if QT_VERSION < 0x040000
+ " (Qt3)"
+#else
+ ""
+#endif
+ );
+ setCaption(title);
+
+ width = configSettings->readNumEntry("/window width", d->width() - 64);
+ height = configSettings->readNumEntry("/window height", d->height() - 64);
+ resize(width, height);
+ x = configSettings->readNumEntry("/window x", 0, &ok);
+ if (ok)
+ y = configSettings->readNumEntry("/window y", 0, &ok);
+ if (ok)
+ move(x, y);
+
+ split1 = new QSplitter(this);
+ split1->setOrientation(Qt::Horizontal);
+ setCentralWidget(split1);
+
+ menuView = new ConfigView(split1, "menu");
+ menuList = menuView->list;
+
+ split2 = new QSplitter(split1);
+ split2->setOrientation(Qt::Vertical);
+
+ // create config tree
+ configView = new ConfigView(split2, "config");
+ configList = configView->list;
+
+ helpText = new ConfigInfoView(split2, "help");
+ helpText->setTextFormat(Qt::RichText);
+
+ setTabOrder(configList, helpText);
+ configList->setFocus();
+
+ menu = menuBar();
+ toolBar = new Q3ToolBar("Tools", this);
+
+ backAction = new Q3Action("Back", QPixmap(xpm_back), _("Back"), 0, this);
+ connect(backAction, SIGNAL(activated()), SLOT(goBack()));
+ backAction->setEnabled(FALSE);
+ Q3Action *quitAction = new Q3Action("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this);
+ connect(quitAction, SIGNAL(activated()), SLOT(close()));
+ Q3Action *loadAction = new Q3Action("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this);
+ connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
+ saveAction = new Q3Action("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this);
+ connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
+ conf_set_changed_callback(conf_changed);
+ // Set saveAction's initial state
+ conf_changed();
+ Q3Action *saveAsAction = new Q3Action("Save As...", _("Save &As..."), 0, this);
+ connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
+ Q3Action *searchAction = new Q3Action("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this);
+ connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
+ Q3Action *singleViewAction = new Q3Action("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this);
+ connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
+ Q3Action *splitViewAction = new Q3Action("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this);
+ connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
+ Q3Action *fullViewAction = new Q3Action("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this);
+ connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
+
+ Q3Action *showNameAction = new Q3Action(NULL, _("Show Name"), 0, this);
+ showNameAction->setToggleAction(TRUE);
+ connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
+ connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
+ showNameAction->setOn(configView->showName());
+ Q3Action *showRangeAction = new Q3Action(NULL, _("Show Range"), 0, this);
+ showRangeAction->setToggleAction(TRUE);
+ connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
+ connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
+ showRangeAction->setOn(configList->showRange);
+ Q3Action *showDataAction = new Q3Action(NULL, _("Show Data"), 0, this);
+ showDataAction->setToggleAction(TRUE);
+ connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
+ connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
+ showDataAction->setOn(configList->showData);
+
+ QActionGroup *optGroup = new QActionGroup(this);
+ optGroup->setExclusive(TRUE);
+ connect(optGroup, SIGNAL(selected(QAction *)), configView,
+ SLOT(setOptionMode(QAction *)));
+ connect(optGroup, SIGNAL(selected(QAction *)), menuView,
+ SLOT(setOptionMode(QAction *)));
+
+#if QT_VERSION >= 0x040000
+ configView->showNormalAction = new QAction(_("Show Normal Options"), optGroup);
+ configView->showAllAction = new QAction(_("Show All Options"), optGroup);
+ configView->showPromptAction = new QAction(_("Show Prompt Options"), optGroup);
+#else
+ configView->showNormalAction = new QAction(_("Show Normal Options"), 0, optGroup);
+ configView->showAllAction = new QAction(_("Show All Options"), 0, optGroup);
+ configView->showPromptAction = new QAction(_("Show Prompt Options"), 0, optGroup);
+#endif
+ configView->showNormalAction->setToggleAction(TRUE);
+ configView->showNormalAction->setOn(configList->optMode == normalOpt);
+ configView->showAllAction->setToggleAction(TRUE);
+ configView->showAllAction->setOn(configList->optMode == allOpt);
+ configView->showPromptAction->setToggleAction(TRUE);
+ configView->showPromptAction->setOn(configList->optMode == promptOpt);
+
+ Q3Action *showDebugAction = new Q3Action(NULL, _("Show Debug Info"), 0, this);
+ showDebugAction->setToggleAction(TRUE);
+ connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
+ connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
+ showDebugAction->setOn(helpText->showDebug());
+
+ Q3Action *showIntroAction = new Q3Action(NULL, _("Introduction"), 0, this);
+ connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
+ Q3Action *showAboutAction = new Q3Action(NULL, _("About"), 0, this);
+ connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
+
+ // init tool bar
+ backAction->addTo(toolBar);
+ toolBar->addSeparator();
+ loadAction->addTo(toolBar);
+ saveAction->addTo(toolBar);
+ toolBar->addSeparator();
+ singleViewAction->addTo(toolBar);
+ splitViewAction->addTo(toolBar);
+ fullViewAction->addTo(toolBar);
+
+ // create config menu
+ Q3PopupMenu* config = new Q3PopupMenu(this);
+ menu->insertItem(_("&File"), config);
+ loadAction->addTo(config);
+ saveAction->addTo(config);
+ saveAsAction->addTo(config);
+ config->insertSeparator();
+ quitAction->addTo(config);
+
+ // create edit menu
+ Q3PopupMenu* editMenu = new Q3PopupMenu(this);
+ menu->insertItem(_("&Edit"), editMenu);
+ searchAction->addTo(editMenu);
+
+ // create options menu
+ Q3PopupMenu* optionMenu = new Q3PopupMenu(this);
+ menu->insertItem(_("&Option"), optionMenu);
+ showNameAction->addTo(optionMenu);
+ showRangeAction->addTo(optionMenu);
+ showDataAction->addTo(optionMenu);
+ optionMenu->insertSeparator();
+ optGroup->addTo(optionMenu);
+ optionMenu->insertSeparator();
+
+ // create help menu
+ Q3PopupMenu* helpMenu = new Q3PopupMenu(this);
+ menu->insertSeparator();
+ menu->insertItem(_("&Help"), helpMenu);
+ showIntroAction->addTo(helpMenu);
+ showAboutAction->addTo(helpMenu);
+
+ connect(configList, SIGNAL(menuChanged(struct menu *)),
+ helpText, SLOT(setInfo(struct menu *)));
+ connect(configList, SIGNAL(menuSelected(struct menu *)),
+ SLOT(changeMenu(struct menu *)));
+ connect(configList, SIGNAL(parentSelected()),
+ SLOT(goBack()));
+ connect(menuList, SIGNAL(menuChanged(struct menu *)),
+ helpText, SLOT(setInfo(struct menu *)));
+ connect(menuList, SIGNAL(menuSelected(struct menu *)),
+ SLOT(changeMenu(struct menu *)));
+
+ connect(configList, SIGNAL(gotFocus(struct menu *)),
+ helpText, SLOT(setInfo(struct menu *)));
+ connect(menuList, SIGNAL(gotFocus(struct menu *)),
+ helpText, SLOT(setInfo(struct menu *)));
+ connect(menuList, SIGNAL(gotFocus(struct menu *)),
+ SLOT(listFocusChanged(void)));
+ connect(helpText, SIGNAL(menuSelected(struct menu *)),
+ SLOT(setMenuLink(struct menu *)));
+
+ QString listMode = configSettings->readEntry("/listMode", "symbol");
+ if (listMode == "single")
+ showSingleView();
+ else if (listMode == "full")
+ showFullView();
+ else /*if (listMode == "split")*/
+ showSplitView();
+
+ // UI setup done, restore splitter positions
+ Q3ValueList<int> sizes = configSettings->readSizes("/split1", &ok);
+ if (ok)
+ split1->setSizes(sizes);
+
+ sizes = configSettings->readSizes("/split2", &ok);
+ if (ok)
+ split2->setSizes(sizes);
+}
+
+void ConfigMainWindow::loadConfig(void)
+{
+ QString s = Q3FileDialog::getOpenFileName(conf_get_configname(), NULL, this);
+ if (s.isNull())
+ return;
+ if (conf_read(QFile::encodeName(s)))
+ QMessageBox::information(this, "qconf", _("Unable to load configuration!"));
+ ConfigView::updateListAll();
+}
+
+bool ConfigMainWindow::saveConfig(void)
+{
+ if (conf_write(NULL)) {
+ QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+ return false;
+ }
+ return true;
+}
+
+void ConfigMainWindow::saveConfigAs(void)
+{
+ QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this);
+ if (s.isNull())
+ return;
+ saveConfig();
+}
+
+void ConfigMainWindow::searchConfig(void)
+{
+ if (!searchWindow)
+ searchWindow = new ConfigSearchWindow(this, "search");
+ searchWindow->show();
+}
+
+void ConfigMainWindow::changeMenu(struct menu *menu)
+{
+ configList->setRootMenu(menu);
+ if (configList->rootEntry->parent == &rootmenu)
+ backAction->setEnabled(FALSE);
+ else
+ backAction->setEnabled(TRUE);
+}
+
+void ConfigMainWindow::setMenuLink(struct menu *menu)
+{
+ struct menu *parent;
+ ConfigList* list = NULL;
+ ConfigItem* item;
+
+ if (configList->menuSkip(menu))
+ return;
+
+ switch (configList->mode) {
+ case singleMode:
+ list = configList;
+ parent = menu_get_parent_menu(menu);
+ if (!parent)
+ return;
+ list->setRootMenu(parent);
+ break;
+ case symbolMode:
+ if (menu->flags & MENU_ROOT) {
+ configList->setRootMenu(menu);
+ configList->clearSelection();
+ list = menuList;
+ } else {
+ list = configList;
+ parent = menu_get_parent_menu(menu->parent);
+ if (!parent)
+ return;
+ item = menuList->findConfigItem(parent);
+ if (item) {
+ menuList->setSelected(item, TRUE);
+ menuList->ensureItemVisible(item);
+ }
+ list->setRootMenu(parent);
+ }
+ break;
+ case fullMode:
+ list = configList;
+ break;
+ default:
+ break;
+ }
+
+ if (list) {
+ item = list->findConfigItem(menu);
+ if (item) {
+ list->setSelected(item, TRUE);
+ list->ensureItemVisible(item);
+ list->setFocus();
+ }
+ }
+}
+
+void ConfigMainWindow::listFocusChanged(void)
+{
+ if (menuList->mode == menuMode)
+ configList->clearSelection();
+}
+
+void ConfigMainWindow::goBack(void)
+{
+ ConfigItem* item;
+
+ configList->setParentMenu();
+ if (configList->rootEntry == &rootmenu)
+ backAction->setEnabled(FALSE);
+ item = (ConfigItem*)menuList->selectedItem();
+ while (item) {
+ if (item->menu == configList->rootEntry) {
+ menuList->setSelected(item, TRUE);
+ break;
+ }
+ item = (ConfigItem*)item->parent();
+ }
+}
+
+void ConfigMainWindow::showSingleView(void)
+{
+ menuView->hide();
+ menuList->setRootMenu(0);
+ configList->mode = singleMode;
+ if (configList->rootEntry == &rootmenu)
+ configList->updateListAll();
+ else
+ configList->setRootMenu(&rootmenu);
+ configList->setAllOpen(TRUE);
+ configList->setFocus();
+}
+
+void ConfigMainWindow::showSplitView(void)
+{
+ configList->mode = symbolMode;
+ if (configList->rootEntry == &rootmenu)
+ configList->updateListAll();
+ else
+ configList->setRootMenu(&rootmenu);
+ configList->setAllOpen(TRUE);
+ configApp->processEvents();
+ menuList->mode = menuMode;
+ menuList->setRootMenu(&rootmenu);
+ menuList->setAllOpen(TRUE);
+ menuView->show();
+ menuList->setFocus();
+}
+
+void ConfigMainWindow::showFullView(void)
+{
+ menuView->hide();
+ menuList->setRootMenu(0);
+ configList->mode = fullMode;
+ if (configList->rootEntry == &rootmenu)
+ configList->updateListAll();
+ else
+ configList->setRootMenu(&rootmenu);
+ configList->setAllOpen(FALSE);
+ configList->setFocus();
+}
+
+/*
+ * ask for saving configuration before quitting
+ * TODO ask only when something changed
+ */
+void ConfigMainWindow::closeEvent(QCloseEvent* e)
+{
+ if (!conf_get_changed()) {
+ e->accept();
+ return;
+ }
+ QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning,
+ QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
+ mb.setButtonText(QMessageBox::Yes, _("&Save Changes"));
+ mb.setButtonText(QMessageBox::No, _("&Discard Changes"));
+ mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
+ switch (mb.exec()) {
+ case QMessageBox::Yes:
+ if (saveConfig())
+ e->accept();
+ else
+ e->ignore();
+ break;
+ case QMessageBox::No:
+ e->accept();
+ break;
+ case QMessageBox::Cancel:
+ e->ignore();
+ break;
+ }
+}
+
+void ConfigMainWindow::showIntro(void)
+{
+ static const QString str = _("Welcome to the qconf graphical configuration tool.\n\n"
+ "For each option, a blank box indicates the feature is disabled, a check\n"
+ "indicates it is enabled, and a dot indicates that it is to be compiled\n"
+ "as a module. Clicking on the box will cycle through the three states.\n\n"
+ "If you do not see an option (e.g., a device driver) that you believe\n"
+ "should be present, try turning on Show All Options under the Options menu.\n"
+ "Although there is no cross reference yet to help you figure out what other\n"
+ "options must be enabled to support the option you are interested in, you can\n"
+ "still view the help of a grayed-out option.\n\n"
+ "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
+ "which you can then match by examining other options.\n\n");
+
+ QMessageBox::information(this, "qconf", str);
+}
+
+void ConfigMainWindow::showAbout(void)
+{
+ static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
+ "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n");
+
+ QMessageBox::information(this, "qconf", str);
+}
+
+void ConfigMainWindow::saveSettings(void)
+{
+ configSettings->writeEntry("/window x", pos().x());
+ configSettings->writeEntry("/window y", pos().y());
+ configSettings->writeEntry("/window width", size().width());
+ configSettings->writeEntry("/window height", size().height());
+
+ QString entry;
+ switch(configList->mode) {
+ case singleMode :
+ entry = "single";
+ break;
+
+ case symbolMode :
+ entry = "split";
+ break;
+
+ case fullMode :
+ entry = "full";
+ break;
+
+ default:
+ break;
+ }
+ configSettings->writeEntry("/listMode", entry);
+
+ configSettings->writeSizes("/split1", split1->sizes());
+ configSettings->writeSizes("/split2", split2->sizes());
+}
+
+void ConfigMainWindow::conf_changed(void)
+{
+ if (saveAction)
+ saveAction->setEnabled(conf_get_changed());
+}
+
+void fixup_rootmenu(struct menu *menu)
+{
+ struct menu *child;
+ static int menu_cnt = 0;
+
+ menu->flags |= MENU_ROOT;
+ for (child = menu->list; child; child = child->next) {
+ if (child->prompt && child->prompt->type == P_MENU) {
+ menu_cnt++;
+ fixup_rootmenu(child);
+ menu_cnt--;
+ } else if (!menu_cnt)
+ fixup_rootmenu(child);
+ }
+}
+
+static const char *progname;
+
+static void usage(void)
+{
+ printf(_("%s <config>\n"), progname);
+ exit(0);
+}
+
+int main(int ac, char** av)
+{
+ ConfigMainWindow* v;
+ const char *name;
+
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ progname = av[0];
+ configApp = new QApplication(ac, av);
+ if (ac > 1 && av[1][0] == '-') {
+ switch (av[1][1]) {
+ case 'h':
+ case '?':
+ usage();
+ }
+ name = av[2];
+ } else
+ name = av[1];
+ if (!name)
+ usage();
+
+ conf_parse(name);
+ fixup_rootmenu(&rootmenu);
+ conf_read(NULL);
+ //zconfdump(stdout);
+
+ configSettings = new ConfigSettings();
+ configSettings->beginGroup("/kconfig/qconf");
+ v = new ConfigMainWindow();
+
+ //zconfdump(stdout);
+ configApp->setMainWidget(v);
+ configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
+ configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
+ v->show();
+ configApp->exec();
+
+ configSettings->endGroup();
+ delete configSettings;
+
+ return 0;
+}
diff --git a/roms/seabios/scripts/kconfig/qconf.h b/roms/seabios/scripts/kconfig/qconf.h
new file mode 100644
index 00000000..bde0c6b6
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/qconf.h
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#if QT_VERSION < 0x040000
+#include <qlistview.h>
+#else
+#include <q3listview.h>
+#endif
+#include <qsettings.h>
+
+#if QT_VERSION < 0x040000
+#define Q3ValueList QValueList
+#define Q3PopupMenu QPopupMenu
+#define Q3ListView QListView
+#define Q3ListViewItem QListViewItem
+#define Q3VBox QVBox
+#define Q3TextBrowser QTextBrowser
+#define Q3MainWindow QMainWindow
+#define Q3Action QAction
+#define Q3ToolBar QToolBar
+#define Q3ListViewItemIterator QListViewItemIterator
+#define Q3FileDialog QFileDialog
+#endif
+
+class ConfigView;
+class ConfigList;
+class ConfigItem;
+class ConfigLineEdit;
+class ConfigMainWindow;
+
+class ConfigSettings : public QSettings {
+public:
+ ConfigSettings();
+ Q3ValueList<int> readSizes(const QString& key, bool *ok);
+ bool writeSizes(const QString& key, const Q3ValueList<int>& value);
+};
+
+enum colIdx {
+ promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr
+};
+enum listMode {
+ singleMode, menuMode, symbolMode, fullMode, listMode
+};
+enum optionMode {
+ normalOpt = 0, allOpt, promptOpt
+};
+
+class ConfigList : public Q3ListView {
+ Q_OBJECT
+ typedef class Q3ListView Parent;
+public:
+ ConfigList(ConfigView* p, const char *name = 0);
+ void reinit(void);
+ ConfigView* parent(void) const
+ {
+ return (ConfigView*)Parent::parent();
+ }
+ ConfigItem* findConfigItem(struct menu *);
+
+protected:
+ void keyPressEvent(QKeyEvent *e);
+ void contentsMousePressEvent(QMouseEvent *e);
+ void contentsMouseReleaseEvent(QMouseEvent *e);
+ void contentsMouseMoveEvent(QMouseEvent *e);
+ void contentsMouseDoubleClickEvent(QMouseEvent *e);
+ void focusInEvent(QFocusEvent *e);
+ void contextMenuEvent(QContextMenuEvent *e);
+
+public slots:
+ void setRootMenu(struct menu *menu);
+
+ void updateList(ConfigItem *item);
+ void setValue(ConfigItem* item, tristate val);
+ void changeValue(ConfigItem* item);
+ void updateSelection(void);
+ void saveSettings(void);
+signals:
+ void menuChanged(struct menu *menu);
+ void menuSelected(struct menu *menu);
+ void parentSelected(void);
+ void gotFocus(struct menu *);
+
+public:
+ void updateListAll(void)
+ {
+ updateAll = true;
+ updateList(NULL);
+ updateAll = false;
+ }
+ ConfigList* listView()
+ {
+ return this;
+ }
+ ConfigItem* firstChild() const
+ {
+ return (ConfigItem *)Parent::firstChild();
+ }
+ int mapIdx(colIdx idx)
+ {
+ return colMap[idx];
+ }
+ void addColumn(colIdx idx, const QString& label)
+ {
+ colMap[idx] = Parent::addColumn(label);
+ colRevMap[colMap[idx]] = idx;
+ }
+ void removeColumn(colIdx idx)
+ {
+ int col = colMap[idx];
+ if (col >= 0) {
+ Parent::removeColumn(col);
+ colRevMap[col] = colMap[idx] = -1;
+ }
+ }
+ void setAllOpen(bool open);
+ void setParentMenu(void);
+
+ bool menuSkip(struct menu *);
+
+ template <class P>
+ void updateMenuList(P*, struct menu*);
+
+ bool updateAll;
+
+ QPixmap symbolYesPix, symbolModPix, symbolNoPix;
+ QPixmap choiceYesPix, choiceNoPix;
+ QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
+
+ bool showName, showRange, showData;
+ enum listMode mode;
+ enum optionMode optMode;
+ struct menu *rootEntry;
+ QColorGroup disabledColorGroup;
+ QColorGroup inactivedColorGroup;
+ Q3PopupMenu* headerPopup;
+
+private:
+ int colMap[colNr];
+ int colRevMap[colNr];
+};
+
+class ConfigItem : public Q3ListViewItem {
+ typedef class Q3ListViewItem Parent;
+public:
+ ConfigItem(Q3ListView *parent, ConfigItem *after, struct menu *m, bool v)
+ : Parent(parent, after), menu(m), visible(v), goParent(false)
+ {
+ init();
+ }
+ ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v)
+ : Parent(parent, after), menu(m), visible(v), goParent(false)
+ {
+ init();
+ }
+ ConfigItem(Q3ListView *parent, ConfigItem *after, bool v)
+ : Parent(parent, after), menu(0), visible(v), goParent(true)
+ {
+ init();
+ }
+ ~ConfigItem(void);
+ void init(void);
+ void okRename(int col);
+ void updateMenu(void);
+ void testUpdateMenu(bool v);
+ ConfigList* listView() const
+ {
+ return (ConfigList*)Parent::listView();
+ }
+ ConfigItem* firstChild() const
+ {
+ return (ConfigItem *)Parent::firstChild();
+ }
+ ConfigItem* nextSibling() const
+ {
+ return (ConfigItem *)Parent::nextSibling();
+ }
+ void setText(colIdx idx, const QString& text)
+ {
+ Parent::setText(listView()->mapIdx(idx), text);
+ }
+ QString text(colIdx idx) const
+ {
+ return Parent::text(listView()->mapIdx(idx));
+ }
+ void setPixmap(colIdx idx, const QPixmap& pm)
+ {
+ Parent::setPixmap(listView()->mapIdx(idx), pm);
+ }
+ const QPixmap* pixmap(colIdx idx) const
+ {
+ return Parent::pixmap(listView()->mapIdx(idx));
+ }
+ void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align);
+
+ ConfigItem* nextItem;
+ struct menu *menu;
+ bool visible;
+ bool goParent;
+};
+
+class ConfigLineEdit : public QLineEdit {
+ Q_OBJECT
+ typedef class QLineEdit Parent;
+public:
+ ConfigLineEdit(ConfigView* parent);
+ ConfigView* parent(void) const
+ {
+ return (ConfigView*)Parent::parent();
+ }
+ void show(ConfigItem *i);
+ void keyPressEvent(QKeyEvent *e);
+
+public:
+ ConfigItem *item;
+};
+
+class ConfigView : public Q3VBox {
+ Q_OBJECT
+ typedef class Q3VBox Parent;
+public:
+ ConfigView(QWidget* parent, const char *name = 0);
+ ~ConfigView(void);
+ static void updateList(ConfigItem* item);
+ static void updateListAll(void);
+
+ bool showName(void) const { return list->showName; }
+ bool showRange(void) const { return list->showRange; }
+ bool showData(void) const { return list->showData; }
+public slots:
+ void setShowName(bool);
+ void setShowRange(bool);
+ void setShowData(bool);
+ void setOptionMode(QAction *);
+signals:
+ void showNameChanged(bool);
+ void showRangeChanged(bool);
+ void showDataChanged(bool);
+public:
+ ConfigList* list;
+ ConfigLineEdit* lineEdit;
+
+ static ConfigView* viewList;
+ ConfigView* nextView;
+
+ static QAction *showNormalAction;
+ static QAction *showAllAction;
+ static QAction *showPromptAction;
+};
+
+class ConfigInfoView : public Q3TextBrowser {
+ Q_OBJECT
+ typedef class Q3TextBrowser Parent;
+public:
+ ConfigInfoView(QWidget* parent, const char *name = 0);
+ bool showDebug(void) const { return _showDebug; }
+
+public slots:
+ void setInfo(struct menu *menu);
+ void saveSettings(void);
+ void setShowDebug(bool);
+
+signals:
+ void showDebugChanged(bool);
+ void menuSelected(struct menu *);
+
+protected:
+ void symbolInfo(void);
+ void menuInfo(void);
+ QString debug_info(struct symbol *sym);
+ static QString print_filter(const QString &str);
+ static void expr_print_help(void *data, struct symbol *sym, const char *str);
+ Q3PopupMenu* createPopupMenu(const QPoint& pos);
+ void contentsContextMenuEvent(QContextMenuEvent *e);
+
+ struct symbol *sym;
+ struct menu *_menu;
+ bool _showDebug;
+};
+
+class ConfigSearchWindow : public QDialog {
+ Q_OBJECT
+ typedef class QDialog Parent;
+public:
+ ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0);
+
+public slots:
+ void saveSettings(void);
+ void search(void);
+
+protected:
+ QLineEdit* editField;
+ QPushButton* searchButton;
+ QSplitter* split;
+ ConfigView* list;
+ ConfigInfoView* info;
+
+ struct symbol **result;
+};
+
+class ConfigMainWindow : public Q3MainWindow {
+ Q_OBJECT
+
+ static Q3Action *saveAction;
+ static void conf_changed(void);
+public:
+ ConfigMainWindow(void);
+public slots:
+ void changeMenu(struct menu *);
+ void setMenuLink(struct menu *);
+ void listFocusChanged(void);
+ void goBack(void);
+ void loadConfig(void);
+ bool saveConfig(void);
+ void saveConfigAs(void);
+ void searchConfig(void);
+ void showSingleView(void);
+ void showSplitView(void);
+ void showFullView(void);
+ void showIntro(void);
+ void showAbout(void);
+ void saveSettings(void);
+
+protected:
+ void closeEvent(QCloseEvent *e);
+
+ ConfigSearchWindow *searchWindow;
+ ConfigView *menuView;
+ ConfigList *menuList;
+ ConfigView *configView;
+ ConfigList *configList;
+ ConfigInfoView *helpText;
+ Q3ToolBar *toolBar;
+ Q3Action *backAction;
+ QSplitter* split1;
+ QSplitter* split2;
+};
diff --git a/roms/seabios/scripts/kconfig/streamline_config.pl b/roms/seabios/scripts/kconfig/streamline_config.pl
new file mode 100644
index 00000000..9cb8522d
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/streamline_config.pl
@@ -0,0 +1,647 @@
+#!/usr/bin/perl -w
+#
+# Copyright 2005-2009 - Steven Rostedt
+# Licensed under the terms of the GNU GPL License version 2
+#
+# It's simple enough to figure out how this works.
+# If not, then you can ask me at stripconfig@goodmis.org
+#
+# What it does?
+#
+# If you have installed a Linux kernel from a distribution
+# that turns on way too many modules than you need, and
+# you only want the modules you use, then this program
+# is perfect for you.
+#
+# It gives you the ability to turn off all the modules that are
+# not loaded on your system.
+#
+# Howto:
+#
+# 1. Boot up the kernel that you want to stream line the config on.
+# 2. Change directory to the directory holding the source of the
+# kernel that you just booted.
+# 3. Copy the configuraton file to this directory as .config
+# 4. Have all your devices that you need modules for connected and
+# operational (make sure that their corresponding modules are loaded)
+# 5. Run this script redirecting the output to some other file
+# like config_strip.
+# 6. Back up your old config (if you want too).
+# 7. copy the config_strip file to .config
+# 8. Run "make oldconfig"
+#
+# Now your kernel is ready to be built with only the modules that
+# are loaded.
+#
+# Here's what I did with my Debian distribution.
+#
+# cd /usr/src/linux-2.6.10
+# cp /boot/config-2.6.10-1-686-smp .config
+# ~/bin/streamline_config > config_strip
+# mv .config config_sav
+# mv config_strip .config
+# make oldconfig
+#
+use strict;
+use Getopt::Long;
+
+# set the environment variable LOCALMODCONFIG_DEBUG to get
+# debug output.
+my $debugprint = 0;
+$debugprint = 1 if (defined($ENV{LOCALMODCONFIG_DEBUG}));
+
+sub dprint {
+ return if (!$debugprint);
+ print STDERR @_;
+}
+
+my $config = ".config";
+
+my $uname = `uname -r`;
+chomp $uname;
+
+my @searchconfigs = (
+ {
+ "file" => ".config",
+ "exec" => "cat",
+ },
+ {
+ "file" => "/proc/config.gz",
+ "exec" => "zcat",
+ },
+ {
+ "file" => "/boot/config-$uname",
+ "exec" => "cat",
+ },
+ {
+ "file" => "/boot/vmlinuz-$uname",
+ "exec" => "scripts/extract-ikconfig",
+ "test" => "scripts/extract-ikconfig",
+ },
+ {
+ "file" => "vmlinux",
+ "exec" => "scripts/extract-ikconfig",
+ "test" => "scripts/extract-ikconfig",
+ },
+ {
+ "file" => "/lib/modules/$uname/kernel/kernel/configs.ko",
+ "exec" => "scripts/extract-ikconfig",
+ "test" => "scripts/extract-ikconfig",
+ },
+ {
+ "file" => "kernel/configs.ko",
+ "exec" => "scripts/extract-ikconfig",
+ "test" => "scripts/extract-ikconfig",
+ },
+ {
+ "file" => "kernel/configs.o",
+ "exec" => "scripts/extract-ikconfig",
+ "test" => "scripts/extract-ikconfig",
+ },
+);
+
+sub read_config {
+ foreach my $conf (@searchconfigs) {
+ my $file = $conf->{"file"};
+
+ next if ( ! -f "$file");
+
+ if (defined($conf->{"test"})) {
+ `$conf->{"test"} $conf->{"file"} 2>/dev/null`;
+ next if ($?);
+ }
+
+ my $exec = $conf->{"exec"};
+
+ print STDERR "using config: '$file'\n";
+
+ open(my $infile, '-|', "$exec $file") || die "Failed to run $exec $file";
+ my @x = <$infile>;
+ close $infile;
+ return @x;
+ }
+ die "No config file found";
+}
+
+my @config_file = read_config;
+
+# Parse options
+my $localmodconfig = 0;
+my $localyesconfig = 0;
+
+GetOptions("localmodconfig" => \$localmodconfig,
+ "localyesconfig" => \$localyesconfig);
+
+# Get the build source and top level Kconfig file (passed in)
+my $ksource = ($ARGV[0] ? $ARGV[0] : '.');
+my $kconfig = $ARGV[1];
+my $lsmod_file = $ENV{'LSMOD'};
+
+my @makefiles = `find $ksource -name Makefile 2>/dev/null`;
+chomp @makefiles;
+
+my %depends;
+my %selects;
+my %prompts;
+my %objects;
+my $var;
+my $iflevel = 0;
+my @ifdeps;
+
+# prevent recursion
+my %read_kconfigs;
+
+sub read_kconfig {
+ my ($kconfig) = @_;
+
+ my $state = "NONE";
+ my $config;
+
+ my $cont = 0;
+ my $line;
+
+ my $source = "$ksource/$kconfig";
+ my $last_source = "";
+
+ # Check for any environment variables used
+ while ($source =~ /\$(\w+)/ && $last_source ne $source) {
+ my $env = $1;
+ $last_source = $source;
+ $source =~ s/\$$env/$ENV{$env}/;
+ }
+
+ open(my $kinfile, '<', $source) || die "Can't open $kconfig";
+ while (<$kinfile>) {
+ chomp;
+
+ # Make sure that lines ending with \ continue
+ if ($cont) {
+ $_ = $line . " " . $_;
+ }
+
+ if (s/\\$//) {
+ $cont = 1;
+ $line = $_;
+ next;
+ }
+
+ $cont = 0;
+
+ # collect any Kconfig sources
+ if (/^source\s*"(.*)"/) {
+ my $kconfig = $1;
+ # prevent reading twice.
+ if (!defined($read_kconfigs{$kconfig})) {
+ $read_kconfigs{$kconfig} = 1;
+ read_kconfig($kconfig);
+ }
+ next;
+ }
+
+ # configs found
+ if (/^\s*(menu)?config\s+(\S+)\s*$/) {
+ $state = "NEW";
+ $config = $2;
+
+ # Add depends for 'if' nesting
+ for (my $i = 0; $i < $iflevel; $i++) {
+ if ($i) {
+ $depends{$config} .= " " . $ifdeps[$i];
+ } else {
+ $depends{$config} = $ifdeps[$i];
+ }
+ $state = "DEP";
+ }
+
+ # collect the depends for the config
+ } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) {
+ $state = "DEP";
+ $depends{$config} = $1;
+ } elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) {
+ $depends{$config} .= " " . $1;
+ } elsif ($state eq "DEP" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) {
+ my $dep = $3;
+ if ($dep !~ /^\s*(y|m|n)\s*$/) {
+ $dep =~ s/.*\sif\s+//;
+ $depends{$config} .= " " . $dep;
+ dprint "Added default depends $dep to $config\n";
+ }
+
+ # Get the configs that select this config
+ } elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) {
+ my $conf = $1;
+ if (defined($selects{$conf})) {
+ $selects{$conf} .= " " . $config;
+ } else {
+ $selects{$conf} = $config;
+ }
+
+ # configs without prompts must be selected
+ } elsif ($state ne "NONE" && /^\s*tristate\s\S/) {
+ # note if the config has a prompt
+ $prompts{$config} = 1;
+
+ # Check for if statements
+ } elsif (/^if\s+(.*\S)\s*$/) {
+ my $deps = $1;
+ # remove beginning and ending non text
+ $deps =~ s/^[^a-zA-Z0-9_]*//;
+ $deps =~ s/[^a-zA-Z0-9_]*$//;
+
+ my @deps = split /[^a-zA-Z0-9_]+/, $deps;
+
+ $ifdeps[$iflevel++] = join ':', @deps;
+
+ } elsif (/^endif/) {
+
+ $iflevel-- if ($iflevel);
+
+ # stop on "help"
+ } elsif (/^\s*help\s*$/) {
+ $state = "NONE";
+ }
+ }
+ close($kinfile);
+}
+
+if ($kconfig) {
+ read_kconfig($kconfig);
+}
+
+# Makefiles can use variables to define their dependencies
+sub convert_vars {
+ my ($line, %vars) = @_;
+
+ my $process = "";
+
+ while ($line =~ s/^(.*?)(\$\((.*?)\))//) {
+ my $start = $1;
+ my $variable = $2;
+ my $var = $3;
+
+ if (defined($vars{$var})) {
+ $process .= $start . $vars{$var};
+ } else {
+ $process .= $start . $variable;
+ }
+ }
+
+ $process .= $line;
+
+ return $process;
+}
+
+# Read all Makefiles to map the configs to the objects
+foreach my $makefile (@makefiles) {
+
+ my $line = "";
+ my %make_vars;
+
+ open(my $infile, '<', $makefile) || die "Can't open $makefile";
+ while (<$infile>) {
+ # if this line ends with a backslash, continue
+ chomp;
+ if (/^(.*)\\$/) {
+ $line .= $1;
+ next;
+ }
+
+ $line .= $_;
+ $_ = $line;
+ $line = "";
+
+ my $objs;
+
+ # Convert variables in a line (could define configs)
+ $_ = convert_vars($_, %make_vars);
+
+ # collect objects after obj-$(CONFIG_FOO_BAR)
+ if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) {
+ $var = $1;
+ $objs = $2;
+
+ # check if variables are set
+ } elsif (/^\s*(\S+)\s*[:]?=\s*(.*\S)/) {
+ $make_vars{$1} = $2;
+ }
+ if (defined($objs)) {
+ foreach my $obj (split /\s+/,$objs) {
+ $obj =~ s/-/_/g;
+ if ($obj =~ /(.*)\.o$/) {
+ # Objects may be enabled by more than one config.
+ # Store configs in an array.
+ my @arr;
+
+ if (defined($objects{$1})) {
+ @arr = @{$objects{$1}};
+ }
+
+ $arr[$#arr+1] = $var;
+
+ # The objects have a hash mapping to a reference
+ # of an array of configs.
+ $objects{$1} = \@arr;
+ }
+ }
+ }
+ }
+ close($infile);
+}
+
+my %modules;
+my $linfile;
+
+if (defined($lsmod_file)) {
+ if ( ! -f $lsmod_file) {
+ if ( -f $ENV{'objtree'}."/".$lsmod_file) {
+ $lsmod_file = $ENV{'objtree'}."/".$lsmod_file;
+ } else {
+ die "$lsmod_file not found";
+ }
+ }
+
+ my $otype = ( -x $lsmod_file) ? '-|' : '<';
+ open($linfile, $otype, $lsmod_file);
+
+} else {
+
+ # see what modules are loaded on this system
+ my $lsmod;
+
+ foreach my $dir ( ("/sbin", "/bin", "/usr/sbin", "/usr/bin") ) {
+ if ( -x "$dir/lsmod" ) {
+ $lsmod = "$dir/lsmod";
+ last;
+ }
+}
+ if (!defined($lsmod)) {
+ # try just the path
+ $lsmod = "lsmod";
+ }
+
+ open($linfile, '-|', $lsmod) || die "Can not call lsmod with $lsmod";
+}
+
+while (<$linfile>) {
+ next if (/^Module/); # Skip the first line.
+ if (/^(\S+)/) {
+ $modules{$1} = 1;
+ }
+}
+close ($linfile);
+
+# add to the configs hash all configs that are needed to enable
+# a loaded module. This is a direct obj-${CONFIG_FOO} += bar.o
+# where we know we need bar.o so we add FOO to the list.
+my %configs;
+foreach my $module (keys(%modules)) {
+ if (defined($objects{$module})) {
+ my @arr = @{$objects{$module}};
+ foreach my $conf (@arr) {
+ $configs{$conf} = $module;
+ dprint "$conf added by direct ($module)\n";
+ if ($debugprint) {
+ my $c=$conf;
+ $c =~ s/^CONFIG_//;
+ if (defined($depends{$c})) {
+ dprint " deps = $depends{$c}\n";
+ } else {
+ dprint " no deps\n";
+ }
+ }
+ }
+ } else {
+ # Most likely, someone has a custom (binary?) module loaded.
+ print STDERR "$module config not found!!\n";
+ }
+}
+
+# Read the current config, and see what is enabled. We want to
+# ignore configs that we would not enable anyway.
+
+my %orig_configs;
+my $valid = "A-Za-z_0-9";
+
+foreach my $line (@config_file) {
+ $_ = $line;
+
+ if (/(CONFIG_[$valid]*)=(m|y)/) {
+ $orig_configs{$1} = $2;
+ }
+}
+
+my $repeat = 1;
+
+my $depconfig;
+
+#
+# Note, we do not care about operands (like: &&, ||, !) we want to add any
+# config that is in the depend list of another config. This script does
+# not enable configs that are not already enabled. If we come across a
+# config A that depends on !B, we can still add B to the list of depends
+# to keep on. If A was on in the original config, B would not have been
+# and B would not be turned on by this script.
+#
+sub parse_config_depends
+{
+ my ($p) = @_;
+
+ while ($p =~ /[$valid]/) {
+
+ if ($p =~ /^[^$valid]*([$valid]+)/) {
+ my $conf = "CONFIG_" . $1;
+
+ $p =~ s/^[^$valid]*[$valid]+//;
+
+ # We only need to process if the depend config is a module
+ if (!defined($orig_configs{$conf}) || !$orig_configs{conf} eq "m") {
+ next;
+ }
+
+ if (!defined($configs{$conf})) {
+ # We must make sure that this config has its
+ # dependencies met.
+ $repeat = 1; # do again
+ dprint "$conf selected by depend $depconfig\n";
+ $configs{$conf} = 1;
+ }
+ } else {
+ die "this should never happen";
+ }
+ }
+}
+
+# Select is treated a bit differently than depends. We call this
+# when a config has no prompt and requires another config to be
+# selected. We use to just select all configs that selected this
+# config, but found that that can balloon into enabling hundreds
+# of configs that we do not care about.
+#
+# The idea is we look at all the configs that select it. If one
+# is already in our list of configs to enable, then there's nothing
+# else to do. If there isn't, we pick the first config that was
+# enabled in the orignal config and use that.
+sub parse_config_selects
+{
+ my ($config, $p) = @_;
+
+ my $next_config;
+
+ while ($p =~ /[$valid]/) {
+
+ if ($p =~ /^[^$valid]*([$valid]+)/) {
+ my $conf = "CONFIG_" . $1;
+
+ $p =~ s/^[^$valid]*[$valid]+//;
+
+ # Make sure that this config exists in the current .config file
+ if (!defined($orig_configs{$conf})) {
+ dprint "$conf not set for $config select\n";
+ next;
+ }
+
+ # Check if something other than a module selects this config
+ if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") {
+ dprint "$conf (non module) selects config, we are good\n";
+ # we are good with this
+ return;
+ }
+ if (defined($configs{$conf})) {
+ dprint "$conf selects $config so we are good\n";
+ # A set config selects this config, we are good
+ return;
+ }
+ # Set this config to be selected
+ if (!defined($next_config)) {
+ $next_config = $conf;
+ }
+ } else {
+ die "this should never happen";
+ }
+ }
+
+ # If no possible config selected this, then something happened.
+ if (!defined($next_config)) {
+ print STDERR "WARNING: $config is required, but nothing in the\n";
+ print STDERR " current config selects it.\n";
+ return;
+ }
+
+ # If we are here, then we found no config that is set and
+ # selects this config. Repeat.
+ $repeat = 1;
+ # Make this config need to be selected
+ $configs{$next_config} = 1;
+ dprint "$next_config selected by select $config\n";
+}
+
+my %process_selects;
+
+# loop through all configs, select their dependencies.
+sub loop_depend {
+ $repeat = 1;
+
+ while ($repeat) {
+ $repeat = 0;
+
+ forloop:
+ foreach my $config (keys %configs) {
+
+ # If this config is not a module, we do not need to process it
+ if (defined($orig_configs{$config}) && $orig_configs{$config} ne "m") {
+ next forloop;
+ }
+
+ $config =~ s/^CONFIG_//;
+ $depconfig = $config;
+
+ if (defined($depends{$config})) {
+ # This config has dependencies. Make sure they are also included
+ parse_config_depends $depends{$config};
+ }
+
+ # If the config has no prompt, then we need to check if a config
+ # that is enabled selected it. Or if we need to enable one.
+ if (!defined($prompts{$config}) && defined($selects{$config})) {
+ $process_selects{$config} = 1;
+ }
+ }
+ }
+}
+
+sub loop_select {
+
+ foreach my $config (keys %process_selects) {
+ $config =~ s/^CONFIG_//;
+
+ dprint "Process select $config\n";
+
+ # config has no prompt and must be selected.
+ parse_config_selects $config, $selects{$config};
+ }
+}
+
+while ($repeat) {
+ # Get the first set of configs and their dependencies.
+ loop_depend;
+
+ $repeat = 0;
+
+ # Now we need to see if we have to check selects;
+ loop_select;
+}
+
+my %setconfigs;
+
+# Finally, read the .config file and turn off any module enabled that
+# we could not find a reason to keep enabled.
+foreach my $line (@config_file) {
+ $_ = $line;
+
+ if (/CONFIG_IKCONFIG/) {
+ if (/# CONFIG_IKCONFIG is not set/) {
+ # enable IKCONFIG at least as a module
+ print "CONFIG_IKCONFIG=m\n";
+ # don't ask about PROC
+ print "# CONFIG_IKCONFIG_PROC is not set\n";
+ } else {
+ print;
+ }
+ next;
+ }
+
+ if (/^(CONFIG.*)=(m|y)/) {
+ if (defined($configs{$1})) {
+ if ($localyesconfig) {
+ $setconfigs{$1} = 'y';
+ print "$1=y\n";
+ next;
+ } else {
+ $setconfigs{$1} = $2;
+ }
+ } elsif ($2 eq "m") {
+ print "# $1 is not set\n";
+ next;
+ }
+ }
+ print;
+}
+
+# Integrity check, make sure all modules that we want enabled do
+# indeed have their configs set.
+loop:
+foreach my $module (keys(%modules)) {
+ if (defined($objects{$module})) {
+ my @arr = @{$objects{$module}};
+ foreach my $conf (@arr) {
+ if (defined($setconfigs{$conf})) {
+ next loop;
+ }
+ }
+ print STDERR "module $module did not have configs";
+ foreach my $conf (@arr) {
+ print STDERR " " , $conf;
+ }
+ print STDERR "\n";
+ }
+}
diff --git a/roms/seabios/scripts/kconfig/symbol.c b/roms/seabios/scripts/kconfig/symbol.c
new file mode 100644
index 00000000..7caabdb5
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/symbol.c
@@ -0,0 +1,1373 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include <sys/utsname.h>
+
+#include "lkc.h"
+
+struct symbol symbol_yes = {
+ .name = "y",
+ .curr = { "y", yes },
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_mod = {
+ .name = "m",
+ .curr = { "m", mod },
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_no = {
+ .name = "n",
+ .curr = { "n", no },
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_empty = {
+ .name = "",
+ .curr = { "", no },
+ .flags = SYMBOL_VALID,
+};
+
+struct symbol *sym_defconfig_list;
+struct symbol *modules_sym;
+tristate modules_val;
+
+struct expr *sym_env_list;
+
+static void sym_add_default(struct symbol *sym, const char *def)
+{
+ struct property *prop = prop_alloc(P_DEFAULT, sym);
+
+ prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
+}
+
+void sym_init(void)
+{
+ struct symbol *sym;
+ struct utsname uts;
+ static bool inited = false;
+
+ if (inited)
+ return;
+ inited = true;
+
+ uname(&uts);
+
+ sym = sym_lookup("UNAME_RELEASE", 0);
+ sym->type = S_STRING;
+ sym->flags |= SYMBOL_AUTO;
+ sym_add_default(sym, uts.release);
+}
+
+enum symbol_type sym_get_type(struct symbol *sym)
+{
+ enum symbol_type type = sym->type;
+
+ if (type == S_TRISTATE) {
+ if (sym_is_choice_value(sym) && sym->visible == yes)
+ type = S_BOOLEAN;
+ else if (modules_val == no)
+ type = S_BOOLEAN;
+ }
+ return type;
+}
+
+const char *sym_type_name(enum symbol_type type)
+{
+ switch (type) {
+ case S_BOOLEAN:
+ return "boolean";
+ case S_TRISTATE:
+ return "tristate";
+ case S_INT:
+ return "integer";
+ case S_HEX:
+ return "hex";
+ case S_STRING:
+ return "string";
+ case S_UNKNOWN:
+ return "unknown";
+ case S_OTHER:
+ break;
+ }
+ return "???";
+}
+
+struct property *sym_get_choice_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_choices(sym, prop)
+ return prop;
+ return NULL;
+}
+
+struct property *sym_get_env_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_properties(sym, prop, P_ENV)
+ return prop;
+ return NULL;
+}
+
+struct property *sym_get_default_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_defaults(sym, prop) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ if (prop->visible.tri != no)
+ return prop;
+ }
+ return NULL;
+}
+
+static struct property *sym_get_range_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_properties(sym, prop, P_RANGE) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ if (prop->visible.tri != no)
+ return prop;
+ }
+ return NULL;
+}
+
+static long long sym_get_range_val(struct symbol *sym, int base)
+{
+ sym_calc_value(sym);
+ switch (sym->type) {
+ case S_INT:
+ base = 10;
+ break;
+ case S_HEX:
+ base = 16;
+ break;
+ default:
+ break;
+ }
+ return strtoll(sym->curr.val, NULL, base);
+}
+
+static void sym_validate_range(struct symbol *sym)
+{
+ struct property *prop;
+ int base;
+ long long val, val2;
+ char str[64];
+
+ switch (sym->type) {
+ case S_INT:
+ base = 10;
+ break;
+ case S_HEX:
+ base = 16;
+ break;
+ default:
+ return;
+ }
+ prop = sym_get_range_prop(sym);
+ if (!prop)
+ return;
+ val = strtoll(sym->curr.val, NULL, base);
+ val2 = sym_get_range_val(prop->expr->left.sym, base);
+ if (val >= val2) {
+ val2 = sym_get_range_val(prop->expr->right.sym, base);
+ if (val <= val2)
+ return;
+ }
+ if (sym->type == S_INT)
+ sprintf(str, "%lld", val2);
+ else
+ sprintf(str, "0x%llx", val2);
+ sym->curr.val = strdup(str);
+}
+
+static void sym_calc_visibility(struct symbol *sym)
+{
+ struct property *prop;
+ tristate tri;
+
+ /* any prompt visible? */
+ tri = no;
+ for_all_prompts(sym, prop) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ tri = EXPR_OR(tri, prop->visible.tri);
+ }
+ if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
+ tri = yes;
+ if (sym->visible != tri) {
+ sym->visible = tri;
+ sym_set_changed(sym);
+ }
+ if (sym_is_choice_value(sym))
+ return;
+ /* defaulting to "yes" if no explicit "depends on" are given */
+ tri = yes;
+ if (sym->dir_dep.expr)
+ tri = expr_calc_value(sym->dir_dep.expr);
+ if (tri == mod)
+ tri = yes;
+ if (sym->dir_dep.tri != tri) {
+ sym->dir_dep.tri = tri;
+ sym_set_changed(sym);
+ }
+ tri = no;
+ if (sym->rev_dep.expr)
+ tri = expr_calc_value(sym->rev_dep.expr);
+ if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+ tri = yes;
+ if (sym->rev_dep.tri != tri) {
+ sym->rev_dep.tri = tri;
+ sym_set_changed(sym);
+ }
+}
+
+/*
+ * Find the default symbol for a choice.
+ * First try the default values for the choice symbol
+ * Next locate the first visible choice value
+ * Return NULL if none was found
+ */
+struct symbol *sym_choice_default(struct symbol *sym)
+{
+ struct symbol *def_sym;
+ struct property *prop;
+ struct expr *e;
+
+ /* any of the defaults visible? */
+ for_all_defaults(sym, prop) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ if (prop->visible.tri == no)
+ continue;
+ def_sym = prop_get_symbol(prop);
+ if (def_sym->visible != no)
+ return def_sym;
+ }
+
+ /* just get the first visible value */
+ prop = sym_get_choice_prop(sym);
+ expr_list_for_each_sym(prop->expr, e, def_sym)
+ if (def_sym->visible != no)
+ return def_sym;
+
+ /* failed to locate any defaults */
+ return NULL;
+}
+
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+ struct symbol *def_sym;
+ struct property *prop;
+ struct expr *e;
+ int flags;
+
+ /* first calculate all choice values' visibilities */
+ flags = sym->flags;
+ prop = sym_get_choice_prop(sym);
+ expr_list_for_each_sym(prop->expr, e, def_sym) {
+ sym_calc_visibility(def_sym);
+ if (def_sym->visible != no)
+ flags &= def_sym->flags;
+ }
+
+ sym->flags &= flags | ~SYMBOL_DEF_USER;
+
+ /* is the user choice visible? */
+ def_sym = sym->def[S_DEF_USER].val;
+ if (def_sym && def_sym->visible != no)
+ return def_sym;
+
+ def_sym = sym_choice_default(sym);
+
+ if (def_sym == NULL)
+ /* no choice? reset tristate value */
+ sym->curr.tri = no;
+
+ return def_sym;
+}
+
+void sym_calc_value(struct symbol *sym)
+{
+ struct symbol_value newval, oldval;
+ struct property *prop;
+ struct expr *e;
+
+ if (!sym)
+ return;
+
+ if (sym->flags & SYMBOL_VALID)
+ return;
+
+ if (sym_is_choice_value(sym) &&
+ sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) {
+ sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES;
+ prop = sym_get_choice_prop(sym);
+ sym_calc_value(prop_get_symbol(prop));
+ }
+
+ sym->flags |= SYMBOL_VALID;
+
+ oldval = sym->curr;
+
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ newval = symbol_empty.curr;
+ break;
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ newval = symbol_no.curr;
+ break;
+ default:
+ sym->curr.val = sym->name;
+ sym->curr.tri = no;
+ return;
+ }
+ if (!sym_is_choice_value(sym))
+ sym->flags &= ~SYMBOL_WRITE;
+
+ sym_calc_visibility(sym);
+
+ /* set default if recursively called */
+ sym->curr = newval;
+
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_is_choice_value(sym) && sym->visible == yes) {
+ prop = sym_get_choice_prop(sym);
+ newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
+ } else {
+ if (sym->visible != no) {
+ /* if the symbol is visible use the user value
+ * if available, otherwise try the default value
+ */
+ sym->flags |= SYMBOL_WRITE;
+ if (sym_has_value(sym)) {
+ newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
+ sym->visible);
+ goto calc_newval;
+ }
+ }
+ if (sym->rev_dep.tri != no)
+ sym->flags |= SYMBOL_WRITE;
+ if (!sym_is_choice(sym)) {
+ prop = sym_get_default_prop(sym);
+ if (prop) {
+ sym->flags |= SYMBOL_WRITE;
+ newval.tri = EXPR_AND(expr_calc_value(prop->expr),
+ prop->visible.tri);
+ }
+ }
+ calc_newval:
+ if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
+ struct expr *e;
+ e = expr_simplify_unmet_dep(sym->rev_dep.expr,
+ sym->dir_dep.expr);
+ fprintf(stderr, "warning: (");
+ expr_fprint(e, stderr);
+ fprintf(stderr, ") selects %s which has unmet direct dependencies (",
+ sym->name);
+ expr_fprint(sym->dir_dep.expr, stderr);
+ fprintf(stderr, ")\n");
+ expr_free(e);
+ }
+ newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
+ }
+ if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
+ newval.tri = yes;
+ break;
+ case S_STRING:
+ case S_HEX:
+ case S_INT:
+ if (sym->visible != no) {
+ sym->flags |= SYMBOL_WRITE;
+ if (sym_has_value(sym)) {
+ newval.val = sym->def[S_DEF_USER].val;
+ break;
+ }
+ }
+ prop = sym_get_default_prop(sym);
+ if (prop) {
+ struct symbol *ds = prop_get_symbol(prop);
+ if (ds) {
+ sym->flags |= SYMBOL_WRITE;
+ sym_calc_value(ds);
+ newval.val = ds->curr.val;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+
+ sym->curr = newval;
+ if (sym_is_choice(sym) && newval.tri == yes)
+ sym->curr.val = sym_calc_choice(sym);
+ sym_validate_range(sym);
+
+ if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
+ sym_set_changed(sym);
+ if (modules_sym == sym) {
+ sym_set_all_changed();
+ modules_val = modules_sym->curr.tri;
+ }
+ }
+
+ if (sym_is_choice(sym)) {
+ struct symbol *choice_sym;
+
+ prop = sym_get_choice_prop(sym);
+ expr_list_for_each_sym(prop->expr, e, choice_sym) {
+ if ((sym->flags & SYMBOL_WRITE) &&
+ choice_sym->visible != no)
+ choice_sym->flags |= SYMBOL_WRITE;
+ if (sym->flags & SYMBOL_CHANGED)
+ sym_set_changed(choice_sym);
+ }
+ }
+
+ if (sym->flags & SYMBOL_AUTO)
+ sym->flags &= ~SYMBOL_WRITE;
+
+ if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES)
+ set_all_choice_values(sym);
+}
+
+void sym_clear_all_valid(void)
+{
+ struct symbol *sym;
+ int i;
+
+ for_all_symbols(i, sym)
+ sym->flags &= ~SYMBOL_VALID;
+ sym_add_change_count(1);
+ if (modules_sym)
+ sym_calc_value(modules_sym);
+}
+
+void sym_set_changed(struct symbol *sym)
+{
+ struct property *prop;
+
+ sym->flags |= SYMBOL_CHANGED;
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu)
+ prop->menu->flags |= MENU_CHANGED;
+ }
+}
+
+void sym_set_all_changed(void)
+{
+ struct symbol *sym;
+ int i;
+
+ for_all_symbols(i, sym)
+ sym_set_changed(sym);
+}
+
+bool sym_tristate_within_range(struct symbol *sym, tristate val)
+{
+ int type = sym_get_type(sym);
+
+ if (sym->visible == no)
+ return false;
+
+ if (type != S_BOOLEAN && type != S_TRISTATE)
+ return false;
+
+ if (type == S_BOOLEAN && val == mod)
+ return false;
+ if (sym->visible <= sym->rev_dep.tri)
+ return false;
+ if (sym_is_choice_value(sym) && sym->visible == yes)
+ return val == yes;
+ return val >= sym->rev_dep.tri && val <= sym->visible;
+}
+
+bool sym_set_tristate_value(struct symbol *sym, tristate val)
+{
+ tristate oldval = sym_get_tristate_value(sym);
+
+ if (oldval != val && !sym_tristate_within_range(sym, val))
+ return false;
+
+ if (!(sym->flags & SYMBOL_DEF_USER)) {
+ sym->flags |= SYMBOL_DEF_USER;
+ sym_set_changed(sym);
+ }
+ /*
+ * setting a choice value also resets the new flag of the choice
+ * symbol and all other choice values.
+ */
+ if (sym_is_choice_value(sym) && val == yes) {
+ struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+ struct property *prop;
+ struct expr *e;
+
+ cs->def[S_DEF_USER].val = sym;
+ cs->flags |= SYMBOL_DEF_USER;
+ prop = sym_get_choice_prop(cs);
+ for (e = prop->expr; e; e = e->left.expr) {
+ if (e->right.sym->visible != no)
+ e->right.sym->flags |= SYMBOL_DEF_USER;
+ }
+ }
+
+ sym->def[S_DEF_USER].tri = val;
+ if (oldval != val)
+ sym_clear_all_valid();
+
+ return true;
+}
+
+tristate sym_toggle_tristate_value(struct symbol *sym)
+{
+ tristate oldval, newval;
+
+ oldval = newval = sym_get_tristate_value(sym);
+ do {
+ switch (newval) {
+ case no:
+ newval = mod;
+ break;
+ case mod:
+ newval = yes;
+ break;
+ case yes:
+ newval = no;
+ break;
+ }
+ if (sym_set_tristate_value(sym, newval))
+ break;
+ } while (oldval != newval);
+ return newval;
+}
+
+bool sym_string_valid(struct symbol *sym, const char *str)
+{
+ signed char ch;
+
+ switch (sym->type) {
+ case S_STRING:
+ return true;
+ case S_INT:
+ ch = *str++;
+ if (ch == '-')
+ ch = *str++;
+ if (!isdigit(ch))
+ return false;
+ if (ch == '0' && *str != 0)
+ return false;
+ while ((ch = *str++)) {
+ if (!isdigit(ch))
+ return false;
+ }
+ return true;
+ case S_HEX:
+ if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+ str += 2;
+ ch = *str++;
+ do {
+ if (!isxdigit(ch))
+ return false;
+ } while ((ch = *str++));
+ return true;
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (str[0]) {
+ case 'y': case 'Y':
+ case 'm': case 'M':
+ case 'n': case 'N':
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+bool sym_string_within_range(struct symbol *sym, const char *str)
+{
+ struct property *prop;
+ long long val;
+
+ switch (sym->type) {
+ case S_STRING:
+ return sym_string_valid(sym, str);
+ case S_INT:
+ if (!sym_string_valid(sym, str))
+ return false;
+ prop = sym_get_range_prop(sym);
+ if (!prop)
+ return true;
+ val = strtoll(str, NULL, 10);
+ return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
+ val <= sym_get_range_val(prop->expr->right.sym, 10);
+ case S_HEX:
+ if (!sym_string_valid(sym, str))
+ return false;
+ prop = sym_get_range_prop(sym);
+ if (!prop)
+ return true;
+ val = strtoll(str, NULL, 16);
+ return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
+ val <= sym_get_range_val(prop->expr->right.sym, 16);
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (str[0]) {
+ case 'y': case 'Y':
+ return sym_tristate_within_range(sym, yes);
+ case 'm': case 'M':
+ return sym_tristate_within_range(sym, mod);
+ case 'n': case 'N':
+ return sym_tristate_within_range(sym, no);
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+bool sym_set_string_value(struct symbol *sym, const char *newval)
+{
+ const char *oldval;
+ char *val;
+ int size;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (newval[0]) {
+ case 'y': case 'Y':
+ return sym_set_tristate_value(sym, yes);
+ case 'm': case 'M':
+ return sym_set_tristate_value(sym, mod);
+ case 'n': case 'N':
+ return sym_set_tristate_value(sym, no);
+ }
+ return false;
+ default:
+ ;
+ }
+
+ if (!sym_string_within_range(sym, newval))
+ return false;
+
+ if (!(sym->flags & SYMBOL_DEF_USER)) {
+ sym->flags |= SYMBOL_DEF_USER;
+ sym_set_changed(sym);
+ }
+
+ oldval = sym->def[S_DEF_USER].val;
+ size = strlen(newval) + 1;
+ if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
+ size += 2;
+ sym->def[S_DEF_USER].val = val = xmalloc(size);
+ *val++ = '0';
+ *val++ = 'x';
+ } else if (!oldval || strcmp(oldval, newval))
+ sym->def[S_DEF_USER].val = val = xmalloc(size);
+ else
+ return true;
+
+ strcpy(val, newval);
+ free((void *)oldval);
+ sym_clear_all_valid();
+
+ return true;
+}
+
+/*
+ * Find the default value associated to a symbol.
+ * For tristate symbol handle the modules=n case
+ * in which case "m" becomes "y".
+ * If the symbol does not have any default then fallback
+ * to the fixed default values.
+ */
+const char *sym_get_string_default(struct symbol *sym)
+{
+ struct property *prop;
+ struct symbol *ds;
+ const char *str;
+ tristate val;
+
+ sym_calc_visibility(sym);
+ sym_calc_value(modules_sym);
+ val = symbol_no.curr.tri;
+ str = symbol_empty.curr.val;
+
+ /* If symbol has a default value look it up */
+ prop = sym_get_default_prop(sym);
+ if (prop != NULL) {
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ /* The visibility may limit the value from yes => mod */
+ val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
+ break;
+ default:
+ /*
+ * The following fails to handle the situation
+ * where a default value is further limited by
+ * the valid range.
+ */
+ ds = prop_get_symbol(prop);
+ if (ds != NULL) {
+ sym_calc_value(ds);
+ str = (const char *)ds->curr.val;
+ }
+ }
+ }
+
+ /* Handle select statements */
+ val = EXPR_OR(val, sym->rev_dep.tri);
+
+ /* transpose mod to yes if modules are not enabled */
+ if (val == mod)
+ if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
+ val = yes;
+
+ /* transpose mod to yes if type is bool */
+ if (sym->type == S_BOOLEAN && val == mod)
+ val = yes;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (val) {
+ case no: return "n";
+ case mod: return "m";
+ case yes: return "y";
+ }
+ case S_INT:
+ case S_HEX:
+ return str;
+ case S_STRING:
+ return str;
+ case S_OTHER:
+ case S_UNKNOWN:
+ break;
+ }
+ return "";
+}
+
+const char *sym_get_string_value(struct symbol *sym)
+{
+ tristate val;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ val = sym_get_tristate_value(sym);
+ switch (val) {
+ case no:
+ return "n";
+ case mod:
+ sym_calc_value(modules_sym);
+ return (modules_sym->curr.tri == no) ? "n" : "m";
+ case yes:
+ return "y";
+ }
+ break;
+ default:
+ ;
+ }
+ return (const char *)sym->curr.val;
+}
+
+bool sym_is_changable(struct symbol *sym)
+{
+ return sym->visible > sym->rev_dep.tri;
+}
+
+static unsigned strhash(const char *s)
+{
+ /* fnv32 hash */
+ unsigned hash = 2166136261U;
+ for (; *s; s++)
+ hash = (hash ^ *s) * 0x01000193;
+ return hash;
+}
+
+struct symbol *sym_lookup(const char *name, int flags)
+{
+ struct symbol *symbol;
+ char *new_name;
+ int hash;
+
+ if (name) {
+ if (name[0] && !name[1]) {
+ switch (name[0]) {
+ case 'y': return &symbol_yes;
+ case 'm': return &symbol_mod;
+ case 'n': return &symbol_no;
+ }
+ }
+ hash = strhash(name) % SYMBOL_HASHSIZE;
+
+ for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+ if (symbol->name &&
+ !strcmp(symbol->name, name) &&
+ (flags ? symbol->flags & flags
+ : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
+ return symbol;
+ }
+ new_name = strdup(name);
+ } else {
+ new_name = NULL;
+ hash = 0;
+ }
+
+ symbol = xmalloc(sizeof(*symbol));
+ memset(symbol, 0, sizeof(*symbol));
+ symbol->name = new_name;
+ symbol->type = S_UNKNOWN;
+ symbol->flags |= flags;
+
+ symbol->next = symbol_hash[hash];
+ symbol_hash[hash] = symbol;
+
+ return symbol;
+}
+
+struct symbol *sym_find(const char *name)
+{
+ struct symbol *symbol = NULL;
+ int hash = 0;
+
+ if (!name)
+ return NULL;
+
+ if (name[0] && !name[1]) {
+ switch (name[0]) {
+ case 'y': return &symbol_yes;
+ case 'm': return &symbol_mod;
+ case 'n': return &symbol_no;
+ }
+ }
+ hash = strhash(name) % SYMBOL_HASHSIZE;
+
+ for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+ if (symbol->name &&
+ !strcmp(symbol->name, name) &&
+ !(symbol->flags & SYMBOL_CONST))
+ break;
+ }
+
+ return symbol;
+}
+
+/*
+ * Expand symbol's names embedded in the string given in argument. Symbols'
+ * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to
+ * the empty string.
+ */
+const char *sym_expand_string_value(const char *in)
+{
+ const char *src;
+ char *res;
+ size_t reslen;
+
+ reslen = strlen(in) + 1;
+ res = xmalloc(reslen);
+ res[0] = '\0';
+
+ while ((src = strchr(in, '$'))) {
+ char *p, name[SYMBOL_MAXLENGTH];
+ const char *symval = "";
+ struct symbol *sym;
+ size_t newlen;
+
+ strncat(res, in, src - in);
+ src++;
+
+ p = name;
+ while (isalnum(*src) || *src == '_')
+ *p++ = *src++;
+ *p = '\0';
+
+ sym = sym_find(name);
+ if (sym != NULL) {
+ sym_calc_value(sym);
+ symval = sym_get_string_value(sym);
+ }
+
+ newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
+ if (newlen > reslen) {
+ reslen = newlen;
+ res = realloc(res, reslen);
+ }
+
+ strcat(res, symval);
+ in = src;
+ }
+ strcat(res, in);
+
+ return res;
+}
+
+const char *sym_escape_string_value(const char *in)
+{
+ const char *p;
+ size_t reslen;
+ char *res;
+ size_t l;
+
+ reslen = strlen(in) + strlen("\"\"") + 1;
+
+ p = in;
+ for (;;) {
+ l = strcspn(p, "\"\\");
+ p += l;
+
+ if (p[0] == '\0')
+ break;
+
+ reslen++;
+ p++;
+ }
+
+ res = xmalloc(reslen);
+ res[0] = '\0';
+
+ strcat(res, "\"");
+
+ p = in;
+ for (;;) {
+ l = strcspn(p, "\"\\");
+ strncat(res, p, l);
+ p += l;
+
+ if (p[0] == '\0')
+ break;
+
+ strcat(res, "\\");
+ strncat(res, p++, 1);
+ }
+
+ strcat(res, "\"");
+ return res;
+}
+
+struct sym_match {
+ struct symbol *sym;
+ off_t so, eo;
+};
+
+/* Compare matched symbols as thus:
+ * - first, symbols that match exactly
+ * - then, alphabetical sort
+ */
+static int sym_rel_comp(const void *sym1, const void *sym2)
+{
+ const struct sym_match *s1 = sym1;
+ const struct sym_match *s2 = sym2;
+ int exact1, exact2;
+
+ /* Exact match:
+ * - if matched length on symbol s1 is the length of that symbol,
+ * then this symbol should come first;
+ * - if matched length on symbol s2 is the length of that symbol,
+ * then this symbol should come first.
+ * Note: since the search can be a regexp, both symbols may match
+ * exactly; if this is the case, we can't decide which comes first,
+ * and we fallback to sorting alphabetically.
+ */
+ exact1 = (s1->eo - s1->so) == strlen(s1->sym->name);
+ exact2 = (s2->eo - s2->so) == strlen(s2->sym->name);
+ if (exact1 && !exact2)
+ return -1;
+ if (!exact1 && exact2)
+ return 1;
+
+ /* As a fallback, sort symbols alphabetically */
+ return strcmp(s1->sym->name, s2->sym->name);
+}
+
+struct symbol **sym_re_search(const char *pattern)
+{
+ struct symbol *sym, **sym_arr = NULL;
+ struct sym_match *sym_match_arr = NULL;
+ int i, cnt, size;
+ regex_t re;
+ regmatch_t match[1];
+
+ cnt = size = 0;
+ /* Skip if empty */
+ if (strlen(pattern) == 0)
+ return NULL;
+ if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE))
+ return NULL;
+
+ for_all_symbols(i, sym) {
+ if (sym->flags & SYMBOL_CONST || !sym->name)
+ continue;
+ if (regexec(&re, sym->name, 1, match, 0))
+ continue;
+ if (cnt >= size) {
+ void *tmp;
+ size += 16;
+ tmp = realloc(sym_match_arr, size * sizeof(struct sym_match));
+ if (!tmp)
+ goto sym_re_search_free;
+ sym_match_arr = tmp;
+ }
+ sym_calc_value(sym);
+ /* As regexec returned 0, we know we have a match, so
+ * we can use match[0].rm_[se]o without further checks
+ */
+ sym_match_arr[cnt].so = match[0].rm_so;
+ sym_match_arr[cnt].eo = match[0].rm_eo;
+ sym_match_arr[cnt++].sym = sym;
+ }
+ if (sym_match_arr) {
+ qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp);
+ sym_arr = malloc((cnt+1) * sizeof(struct symbol));
+ if (!sym_arr)
+ goto sym_re_search_free;
+ for (i = 0; i < cnt; i++)
+ sym_arr[i] = sym_match_arr[i].sym;
+ sym_arr[cnt] = NULL;
+ }
+sym_re_search_free:
+ /* sym_match_arr can be NULL if no match, but free(NULL) is OK */
+ free(sym_match_arr);
+ regfree(&re);
+
+ return sym_arr;
+}
+
+/*
+ * When we check for recursive dependencies we use a stack to save
+ * current state so we can print out relevant info to user.
+ * The entries are located on the call stack so no need to free memory.
+ * Note insert() remove() must always match to properly clear the stack.
+ */
+static struct dep_stack {
+ struct dep_stack *prev, *next;
+ struct symbol *sym;
+ struct property *prop;
+ struct expr *expr;
+} *check_top;
+
+static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
+{
+ memset(stack, 0, sizeof(*stack));
+ if (check_top)
+ check_top->next = stack;
+ stack->prev = check_top;
+ stack->sym = sym;
+ check_top = stack;
+}
+
+static void dep_stack_remove(void)
+{
+ check_top = check_top->prev;
+ if (check_top)
+ check_top->next = NULL;
+}
+
+/*
+ * Called when we have detected a recursive dependency.
+ * check_top point to the top of the stact so we use
+ * the ->prev pointer to locate the bottom of the stack.
+ */
+static void sym_check_print_recursive(struct symbol *last_sym)
+{
+ struct dep_stack *stack;
+ struct symbol *sym, *next_sym;
+ struct menu *menu = NULL;
+ struct property *prop;
+ struct dep_stack cv_stack;
+
+ if (sym_is_choice_value(last_sym)) {
+ dep_stack_insert(&cv_stack, last_sym);
+ last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
+ }
+
+ for (stack = check_top; stack != NULL; stack = stack->prev)
+ if (stack->sym == last_sym)
+ break;
+ if (!stack) {
+ fprintf(stderr, "unexpected recursive dependency error\n");
+ return;
+ }
+
+ for (; stack; stack = stack->next) {
+ sym = stack->sym;
+ next_sym = stack->next ? stack->next->sym : last_sym;
+ prop = stack->prop;
+ if (prop == NULL)
+ prop = stack->sym->prop;
+
+ /* for choice values find the menu entry (used below) */
+ if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
+ for (prop = sym->prop; prop; prop = prop->next) {
+ menu = prop->menu;
+ if (prop->menu)
+ break;
+ }
+ }
+ if (stack->sym == last_sym)
+ fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
+ prop->file->name, prop->lineno);
+ if (stack->expr) {
+ fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ prop_get_type_name(prop->type),
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (stack->prop) {
+ fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (sym_is_choice(sym)) {
+ fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
+ menu->file->name, menu->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (sym_is_choice_value(sym)) {
+ fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
+ menu->file->name, menu->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else {
+ fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ }
+ }
+
+ if (check_top == &cv_stack)
+ dep_stack_remove();
+}
+
+static struct symbol *sym_check_expr_deps(struct expr *e)
+{
+ struct symbol *sym;
+
+ if (!e)
+ return NULL;
+ switch (e->type) {
+ case E_OR:
+ case E_AND:
+ sym = sym_check_expr_deps(e->left.expr);
+ if (sym)
+ return sym;
+ return sym_check_expr_deps(e->right.expr);
+ case E_NOT:
+ return sym_check_expr_deps(e->left.expr);
+ case E_EQUAL:
+ case E_UNEQUAL:
+ sym = sym_check_deps(e->left.sym);
+ if (sym)
+ return sym;
+ return sym_check_deps(e->right.sym);
+ case E_SYMBOL:
+ return sym_check_deps(e->left.sym);
+ default:
+ break;
+ }
+ printf("Oops! How to check %d?\n", e->type);
+ return NULL;
+}
+
+/* return NULL when dependencies are OK */
+static struct symbol *sym_check_sym_deps(struct symbol *sym)
+{
+ struct symbol *sym2;
+ struct property *prop;
+ struct dep_stack stack;
+
+ dep_stack_insert(&stack, sym);
+
+ sym2 = sym_check_expr_deps(sym->rev_dep.expr);
+ if (sym2)
+ goto out;
+
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->type == P_CHOICE || prop->type == P_SELECT)
+ continue;
+ stack.prop = prop;
+ sym2 = sym_check_expr_deps(prop->visible.expr);
+ if (sym2)
+ break;
+ if (prop->type != P_DEFAULT || sym_is_choice(sym))
+ continue;
+ stack.expr = prop->expr;
+ sym2 = sym_check_expr_deps(prop->expr);
+ if (sym2)
+ break;
+ stack.expr = NULL;
+ }
+
+out:
+ dep_stack_remove();
+
+ return sym2;
+}
+
+static struct symbol *sym_check_choice_deps(struct symbol *choice)
+{
+ struct symbol *sym, *sym2;
+ struct property *prop;
+ struct expr *e;
+ struct dep_stack stack;
+
+ dep_stack_insert(&stack, choice);
+
+ prop = sym_get_choice_prop(choice);
+ expr_list_for_each_sym(prop->expr, e, sym)
+ sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+
+ choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+ sym2 = sym_check_sym_deps(choice);
+ choice->flags &= ~SYMBOL_CHECK;
+ if (sym2)
+ goto out;
+
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ sym2 = sym_check_sym_deps(sym);
+ if (sym2)
+ break;
+ }
+out:
+ expr_list_for_each_sym(prop->expr, e, sym)
+ sym->flags &= ~SYMBOL_CHECK;
+
+ if (sym2 && sym_is_choice_value(sym2) &&
+ prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
+ sym2 = choice;
+
+ dep_stack_remove();
+
+ return sym2;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+ struct symbol *sym2;
+ struct property *prop;
+
+ if (sym->flags & SYMBOL_CHECK) {
+ sym_check_print_recursive(sym);
+ return sym;
+ }
+ if (sym->flags & SYMBOL_CHECKED)
+ return NULL;
+
+ if (sym_is_choice_value(sym)) {
+ struct dep_stack stack;
+
+ /* for choice groups start the check with main choice symbol */
+ dep_stack_insert(&stack, sym);
+ prop = sym_get_choice_prop(sym);
+ sym2 = sym_check_deps(prop_get_symbol(prop));
+ dep_stack_remove();
+ } else if (sym_is_choice(sym)) {
+ sym2 = sym_check_choice_deps(sym);
+ } else {
+ sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+ sym2 = sym_check_sym_deps(sym);
+ sym->flags &= ~SYMBOL_CHECK;
+ }
+
+ if (sym2 && sym2 == sym)
+ sym2 = NULL;
+
+ return sym2;
+}
+
+struct property *prop_alloc(enum prop_type type, struct symbol *sym)
+{
+ struct property *prop;
+ struct property **propp;
+
+ prop = xmalloc(sizeof(*prop));
+ memset(prop, 0, sizeof(*prop));
+ prop->type = type;
+ prop->sym = sym;
+ prop->file = current_file;
+ prop->lineno = zconf_lineno();
+
+ /* append property to the prop list of symbol */
+ if (sym) {
+ for (propp = &sym->prop; *propp; propp = &(*propp)->next)
+ ;
+ *propp = prop;
+ }
+
+ return prop;
+}
+
+struct symbol *prop_get_symbol(struct property *prop)
+{
+ if (prop->expr && (prop->expr->type == E_SYMBOL ||
+ prop->expr->type == E_LIST))
+ return prop->expr->left.sym;
+ return NULL;
+}
+
+const char *prop_get_type_name(enum prop_type type)
+{
+ switch (type) {
+ case P_PROMPT:
+ return "prompt";
+ case P_ENV:
+ return "env";
+ case P_COMMENT:
+ return "comment";
+ case P_MENU:
+ return "menu";
+ case P_DEFAULT:
+ return "default";
+ case P_CHOICE:
+ return "choice";
+ case P_SELECT:
+ return "select";
+ case P_RANGE:
+ return "range";
+ case P_SYMBOL:
+ return "symbol";
+ case P_UNKNOWN:
+ break;
+ }
+ return "unknown";
+}
+
+static void prop_add_env(const char *env)
+{
+ struct symbol *sym, *sym2;
+ struct property *prop;
+ char *p;
+
+ sym = current_entry->sym;
+ sym->flags |= SYMBOL_AUTO;
+ for_all_properties(sym, prop, P_ENV) {
+ sym2 = prop_get_symbol(prop);
+ if (strcmp(sym2->name, env))
+ menu_warn(current_entry, "redefining environment symbol from %s",
+ sym2->name);
+ return;
+ }
+
+ prop = prop_alloc(P_ENV, sym);
+ prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
+
+ sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
+ sym_env_list->right.sym = sym;
+
+ p = getenv(env);
+ if (p)
+ sym_add_default(sym, p);
+ else
+ menu_warn(current_entry, "environment variable %s undefined", env);
+}
diff --git a/roms/seabios/scripts/kconfig/util.c b/roms/seabios/scripts/kconfig/util.c
new file mode 100644
index 00000000..94f9c83e
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/util.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org>
+ * Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include "lkc.h"
+
+/* file already present in list? If not add it */
+struct file *file_lookup(const char *name)
+{
+ struct file *file;
+ const char *file_name = sym_expand_string_value(name);
+
+ for (file = file_list; file; file = file->next) {
+ if (!strcmp(name, file->name)) {
+ free((void *)file_name);
+ return file;
+ }
+ }
+
+ file = xmalloc(sizeof(*file));
+ memset(file, 0, sizeof(*file));
+ file->name = file_name;
+ file->next = file_list;
+ file_list = file;
+ return file;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+int file_write_dep(const char *name)
+{
+ struct symbol *sym, *env_sym;
+ struct expr *e;
+ struct file *file;
+ FILE *out;
+
+ if (!name)
+ name = ".kconfig.d";
+ out = fopen("..config.tmp", "w");
+ if (!out)
+ return 1;
+ fprintf(out, "deps_config := \\\n");
+ for (file = file_list; file; file = file->next) {
+ if (file->next)
+ fprintf(out, "\t%s \\\n", file->name);
+ else
+ fprintf(out, "\t%s\n", file->name);
+ }
+ fprintf(out, "\n%s: \\\n"
+ "\t$(deps_config)\n\n", conf_get_autoconfig_name());
+
+ expr_list_for_each_sym(sym_env_list, e, sym) {
+ struct property *prop;
+ const char *value;
+
+ prop = sym_get_env_prop(sym);
+ env_sym = prop_get_symbol(prop);
+ if (!env_sym)
+ continue;
+ value = getenv(env_sym->name);
+ if (!value)
+ value = "";
+ fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
+ fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name());
+ fprintf(out, "endif\n");
+ }
+
+ fprintf(out, "\n$(deps_config): ;\n");
+ fclose(out);
+ rename("..config.tmp", name);
+ return 0;
+}
+
+
+/* Allocate initial growable string */
+struct gstr str_new(void)
+{
+ struct gstr gs;
+ gs.s = xmalloc(sizeof(char) * 64);
+ gs.len = 64;
+ gs.max_width = 0;
+ strcpy(gs.s, "\0");
+ return gs;
+}
+
+/* Allocate and assign growable string */
+struct gstr str_assign(const char *s)
+{
+ struct gstr gs;
+ gs.s = strdup(s);
+ gs.len = strlen(s) + 1;
+ gs.max_width = 0;
+ return gs;
+}
+
+/* Free storage for growable string */
+void str_free(struct gstr *gs)
+{
+ if (gs->s)
+ free(gs->s);
+ gs->s = NULL;
+ gs->len = 0;
+}
+
+/* Append to growable string */
+void str_append(struct gstr *gs, const char *s)
+{
+ size_t l;
+ if (s) {
+ l = strlen(gs->s) + strlen(s) + 1;
+ if (l > gs->len) {
+ gs->s = realloc(gs->s, l);
+ gs->len = l;
+ }
+ strcat(gs->s, s);
+ }
+}
+
+/* Append printf formatted string to growable string */
+void str_printf(struct gstr *gs, const char *fmt, ...)
+{
+ va_list ap;
+ char s[10000]; /* big enough... */
+ va_start(ap, fmt);
+ vsnprintf(s, sizeof(s), fmt, ap);
+ str_append(gs, s);
+ va_end(ap);
+}
+
+/* Retrieve value of growable string */
+const char *str_get(struct gstr *gs)
+{
+ return gs->s;
+}
+
+void *xmalloc(size_t size)
+{
+ void *p = malloc(size);
+ if (p)
+ return p;
+ fprintf(stderr, "Out of memory.\n");
+ exit(1);
+}
+
+void *xcalloc(size_t nmemb, size_t size)
+{
+ void *p = calloc(nmemb, size);
+ if (p)
+ return p;
+ fprintf(stderr, "Out of memory.\n");
+ exit(1);
+}
diff --git a/roms/seabios/scripts/kconfig/zconf.gperf b/roms/seabios/scripts/kconfig/zconf.gperf
new file mode 100644
index 00000000..b6ac02d6
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/zconf.gperf
@@ -0,0 +1,48 @@
+%language=ANSI-C
+%define hash-function-name kconf_id_hash
+%define lookup-function-name kconf_id_lookup
+%define string-pool-name kconf_id_strings
+%compare-strncmp
+%enum
+%pic
+%struct-type
+
+struct kconf_id;
+
+static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
+
+%%
+mainmenu, T_MAINMENU, TF_COMMAND
+menu, T_MENU, TF_COMMAND
+endmenu, T_ENDMENU, TF_COMMAND
+source, T_SOURCE, TF_COMMAND
+choice, T_CHOICE, TF_COMMAND
+endchoice, T_ENDCHOICE, TF_COMMAND
+comment, T_COMMENT, TF_COMMAND
+config, T_CONFIG, TF_COMMAND
+menuconfig, T_MENUCONFIG, TF_COMMAND
+help, T_HELP, TF_COMMAND
+if, T_IF, TF_COMMAND|TF_PARAM
+endif, T_ENDIF, TF_COMMAND
+depends, T_DEPENDS, TF_COMMAND
+optional, T_OPTIONAL, TF_COMMAND
+default, T_DEFAULT, TF_COMMAND, S_UNKNOWN
+prompt, T_PROMPT, TF_COMMAND
+tristate, T_TYPE, TF_COMMAND, S_TRISTATE
+def_tristate, T_DEFAULT, TF_COMMAND, S_TRISTATE
+bool, T_TYPE, TF_COMMAND, S_BOOLEAN
+boolean, T_TYPE, TF_COMMAND, S_BOOLEAN
+def_bool, T_DEFAULT, TF_COMMAND, S_BOOLEAN
+int, T_TYPE, TF_COMMAND, S_INT
+hex, T_TYPE, TF_COMMAND, S_HEX
+string, T_TYPE, TF_COMMAND, S_STRING
+select, T_SELECT, TF_COMMAND
+range, T_RANGE, TF_COMMAND
+visible, T_VISIBLE, TF_COMMAND
+option, T_OPTION, TF_COMMAND
+on, T_ON, TF_PARAM
+modules, T_OPT_MODULES, TF_OPTION
+defconfig_list, T_OPT_DEFCONFIG_LIST,TF_OPTION
+env, T_OPT_ENV, TF_OPTION
+allnoconfig_y, T_OPT_ALLNOCONFIG_Y,TF_OPTION
+%%
diff --git a/roms/seabios/scripts/kconfig/zconf.hash.c_shipped b/roms/seabios/scripts/kconfig/zconf.hash.c_shipped
new file mode 100644
index 00000000..c77a8eff
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/zconf.hash.c_shipped
@@ -0,0 +1,289 @@
+/* ANSI-C code produced by gperf version 3.0.4 */
+/* Command-line: gperf -t --output-file scripts/kconfig/zconf.hash.c_shipped -a -C -E -g -k '1,3,$' -p -t scripts/kconfig/zconf.gperf */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 10 "scripts/kconfig/zconf.gperf"
+struct kconf_id;
+
+static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
+/* maximum key range = 71, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+kconf_id_hash (register const char *str, register unsigned int len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 5, 25, 25,
+ 0, 0, 0, 5, 0, 0, 73, 73, 5, 0,
+ 10, 5, 45, 73, 20, 20, 0, 15, 15, 73,
+ 20, 5, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73
+ };
+ register int hval = len;
+
+ switch (hval)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[2]];
+ /*FALLTHROUGH*/
+ case 2:
+ case 1:
+ hval += asso_values[(unsigned char)str[0]];
+ break;
+ }
+ return hval + asso_values[(unsigned char)str[len - 1]];
+}
+
+struct kconf_id_strings_t
+ {
+ char kconf_id_strings_str2[sizeof("if")];
+ char kconf_id_strings_str3[sizeof("int")];
+ char kconf_id_strings_str5[sizeof("endif")];
+ char kconf_id_strings_str7[sizeof("default")];
+ char kconf_id_strings_str8[sizeof("tristate")];
+ char kconf_id_strings_str9[sizeof("endchoice")];
+ char kconf_id_strings_str12[sizeof("def_tristate")];
+ char kconf_id_strings_str13[sizeof("def_bool")];
+ char kconf_id_strings_str14[sizeof("defconfig_list")];
+ char kconf_id_strings_str17[sizeof("on")];
+ char kconf_id_strings_str18[sizeof("optional")];
+ char kconf_id_strings_str21[sizeof("option")];
+ char kconf_id_strings_str22[sizeof("endmenu")];
+ char kconf_id_strings_str23[sizeof("mainmenu")];
+ char kconf_id_strings_str25[sizeof("menuconfig")];
+ char kconf_id_strings_str27[sizeof("modules")];
+ char kconf_id_strings_str28[sizeof("allnoconfig_y")];
+ char kconf_id_strings_str29[sizeof("menu")];
+ char kconf_id_strings_str31[sizeof("select")];
+ char kconf_id_strings_str32[sizeof("comment")];
+ char kconf_id_strings_str33[sizeof("env")];
+ char kconf_id_strings_str35[sizeof("range")];
+ char kconf_id_strings_str36[sizeof("choice")];
+ char kconf_id_strings_str39[sizeof("bool")];
+ char kconf_id_strings_str41[sizeof("source")];
+ char kconf_id_strings_str42[sizeof("visible")];
+ char kconf_id_strings_str43[sizeof("hex")];
+ char kconf_id_strings_str46[sizeof("config")];
+ char kconf_id_strings_str47[sizeof("boolean")];
+ char kconf_id_strings_str51[sizeof("string")];
+ char kconf_id_strings_str54[sizeof("help")];
+ char kconf_id_strings_str56[sizeof("prompt")];
+ char kconf_id_strings_str72[sizeof("depends")];
+ };
+static const struct kconf_id_strings_t kconf_id_strings_contents =
+ {
+ "if",
+ "int",
+ "endif",
+ "default",
+ "tristate",
+ "endchoice",
+ "def_tristate",
+ "def_bool",
+ "defconfig_list",
+ "on",
+ "optional",
+ "option",
+ "endmenu",
+ "mainmenu",
+ "menuconfig",
+ "modules",
+ "allnoconfig_y",
+ "menu",
+ "select",
+ "comment",
+ "env",
+ "range",
+ "choice",
+ "bool",
+ "source",
+ "visible",
+ "hex",
+ "config",
+ "boolean",
+ "string",
+ "help",
+ "prompt",
+ "depends"
+ };
+#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
+#ifdef __GNUC__
+__inline
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+const struct kconf_id *
+kconf_id_lookup (register const char *str, register unsigned int len)
+{
+ enum
+ {
+ TOTAL_KEYWORDS = 33,
+ MIN_WORD_LENGTH = 2,
+ MAX_WORD_LENGTH = 14,
+ MIN_HASH_VALUE = 2,
+ MAX_HASH_VALUE = 72
+ };
+
+ static const struct kconf_id wordlist[] =
+ {
+ {-1}, {-1},
+#line 25 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_IF, TF_COMMAND|TF_PARAM},
+#line 36 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_TYPE, TF_COMMAND, S_INT},
+ {-1},
+#line 26 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND},
+ {-1},
+#line 29 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_DEFAULT, TF_COMMAND, S_UNKNOWN},
+#line 31 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_TYPE, TF_COMMAND, S_TRISTATE},
+#line 20 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND},
+ {-1}, {-1},
+#line 32 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_TRISTATE},
+#line 35 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN},
+#line 45 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_OPT_DEFCONFIG_LIST,TF_OPTION},
+ {-1}, {-1},
+#line 43 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_ON, TF_PARAM},
+#line 28 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_OPTIONAL, TF_COMMAND},
+ {-1}, {-1},
+#line 42 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_OPTION, TF_COMMAND},
+#line 17 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ENDMENU, TF_COMMAND},
+#line 15 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_MAINMENU, TF_COMMAND},
+ {-1},
+#line 23 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str25, T_MENUCONFIG, TF_COMMAND},
+ {-1},
+#line 44 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION},
+#line 47 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_OPT_ALLNOCONFIG_Y,TF_OPTION},
+#line 16 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND},
+ {-1},
+#line 39 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND},
+#line 21 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND},
+#line 46 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_OPT_ENV, TF_OPTION},
+ {-1},
+#line 40 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_RANGE, TF_COMMAND},
+#line 19 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_CHOICE, TF_COMMAND},
+ {-1}, {-1},
+#line 33 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str39, T_TYPE, TF_COMMAND, S_BOOLEAN},
+ {-1},
+#line 18 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_SOURCE, TF_COMMAND},
+#line 41 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_VISIBLE, TF_COMMAND},
+#line 37 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str43, T_TYPE, TF_COMMAND, S_HEX},
+ {-1}, {-1},
+#line 22 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_CONFIG, TF_COMMAND},
+#line 34 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_TYPE, TF_COMMAND, S_BOOLEAN},
+ {-1}, {-1}, {-1},
+#line 38 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51, T_TYPE, TF_COMMAND, S_STRING},
+ {-1}, {-1},
+#line 24 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str54, T_HELP, TF_COMMAND},
+ {-1},
+#line 30 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str56, T_PROMPT, TF_COMMAND},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+ {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+#line 27 "scripts/kconfig/zconf.gperf"
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str72, T_DEPENDS, TF_COMMAND}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = kconf_id_hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register int o = wordlist[key].name;
+ if (o >= 0)
+ {
+ register const char *s = o + kconf_id_strings;
+
+ if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+ return &wordlist[key];
+ }
+ }
+ }
+ return 0;
+}
+#line 48 "scripts/kconfig/zconf.gperf"
+
diff --git a/roms/seabios/scripts/kconfig/zconf.l b/roms/seabios/scripts/kconfig/zconf.l
new file mode 100644
index 00000000..6c62d93b
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/zconf.l
@@ -0,0 +1,363 @@
+%option nostdinit noyywrap never-interactive full ecs
+%option 8bit nodefault perf-report perf-report
+%option noinput
+%x COMMAND HELP STRING PARAM
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "lkc.h"
+
+#define START_STRSIZE 16
+
+static struct {
+ struct file *file;
+ int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+ text = xmalloc(START_STRSIZE);
+ text_asize = START_STRSIZE;
+ text_size = 0;
+ *text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+ int new_size = text_size + size + 1;
+ if (new_size > text_asize) {
+ new_size += START_STRSIZE - 1;
+ new_size &= -START_STRSIZE;
+ text = realloc(text, new_size);
+ text_asize = new_size;
+ }
+ memcpy(text + text_size, str, size);
+ text_size += size;
+ text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+ text = xmalloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+%}
+
+n [A-Za-z0-9_]
+
+%%
+ int str = 0;
+ int ts, i;
+
+[ \t]*#.*\n |
+[ \t]*\n {
+ current_file->lineno++;
+ return T_EOL;
+}
+[ \t]*#.*
+
+
+[ \t]+ {
+ BEGIN(COMMAND);
+}
+
+. {
+ unput(yytext[0]);
+ BEGIN(COMMAND);
+}
+
+
+<COMMAND>{
+ {n}+ {
+ const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+ BEGIN(PARAM);
+ current_pos.file = current_file;
+ current_pos.lineno = current_file->lineno;
+ if (id && id->flags & TF_COMMAND) {
+ zconflval.id = id;
+ return id->token;
+ }
+ alloc_string(yytext, yyleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ .
+ \n {
+ BEGIN(INITIAL);
+ current_file->lineno++;
+ return T_EOL;
+ }
+}
+
+<PARAM>{
+ "&&" return T_AND;
+ "||" return T_OR;
+ "(" return T_OPEN_PAREN;
+ ")" return T_CLOSE_PAREN;
+ "!" return T_NOT;
+ "=" return T_EQUAL;
+ "!=" return T_UNEQUAL;
+ \"|\' {
+ str = yytext[0];
+ new_string();
+ BEGIN(STRING);
+ }
+ \n BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+ --- /* ignore */
+ ({n}|[-/.])+ {
+ const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+ if (id && id->flags & TF_PARAM) {
+ zconflval.id = id;
+ return id->token;
+ }
+ alloc_string(yytext, yyleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ #.* /* comment */
+ \\\n current_file->lineno++;
+ .
+ <<EOF>> {
+ BEGIN(INITIAL);
+ }
+}
+
+<STRING>{
+ [^'"\\\n]+/\n {
+ append_string(yytext, yyleng);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ [^'"\\\n]+ {
+ append_string(yytext, yyleng);
+ }
+ \\.?/\n {
+ append_string(yytext + 1, yyleng - 1);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ \\.? {
+ append_string(yytext + 1, yyleng - 1);
+ }
+ \'|\" {
+ if (str == yytext[0]) {
+ BEGIN(PARAM);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(yytext, 1);
+ }
+ \n {
+ printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+ current_file->lineno++;
+ BEGIN(INITIAL);
+ return T_EOL;
+ }
+ <<EOF>> {
+ BEGIN(INITIAL);
+ }
+}
+
+<HELP>{
+ [ \t]+ {
+ ts = 0;
+ for (i = 0; i < yyleng; i++) {
+ if (yytext[i] == '\t')
+ ts = (ts & ~7) + 8;
+ else
+ ts++;
+ }
+ last_ts = ts;
+ if (first_ts) {
+ if (ts < first_ts) {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ ts -= first_ts;
+ while (ts > 8) {
+ append_string(" ", 8);
+ ts -= 8;
+ }
+ append_string(" ", ts);
+ }
+ }
+ [ \t]*\n/[^ \t\n] {
+ current_file->lineno++;
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ [ \t]*\n {
+ current_file->lineno++;
+ append_string("\n", 1);
+ }
+ [^ \t\n].* {
+ while (yyleng) {
+ if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+ break;
+ yyleng--;
+ }
+ append_string(yytext, yyleng);
+ if (!first_ts)
+ first_ts = last_ts;
+ }
+ <<EOF>> {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+}
+
+<<EOF>> {
+ if (current_file) {
+ zconf_endfile();
+ return T_EOL;
+ }
+ fclose(yyin);
+ yyterminate();
+}
+
+%%
+void zconf_starthelp(void)
+{
+ new_string();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ zconflval.string = text;
+ BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+ char *env, fullname[PATH_MAX+1];
+ FILE *f;
+
+ f = fopen(name, "r");
+ if (!f && name != NULL && name[0] != '/') {
+ env = getenv(SRCTREE);
+ if (env) {
+ sprintf(fullname, "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ yyin = zconf_fopen(name);
+ if (!yyin) {
+ printf("can't find file %s\n", name);
+ exit(1);
+ }
+
+ current_buf = xmalloc(sizeof(*current_buf));
+ memset(current_buf, 0, sizeof(*current_buf));
+
+ current_file = file_lookup(name);
+ current_file->lineno = 1;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct file *iter;
+ struct file *file = file_lookup(name);
+ struct buffer *buf = xmalloc(sizeof(*buf));
+ memset(buf, 0, sizeof(*buf));
+
+ current_buf->state = YY_CURRENT_BUFFER;
+ yyin = zconf_fopen(file->name);
+ if (!yyin) {
+ printf("%s:%d: can't open file \"%s\"\n",
+ zconf_curname(), zconf_lineno(), file->name);
+ exit(1);
+ }
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+ buf->parent = current_buf;
+ current_buf = buf;
+
+ for (iter = current_file->parent; iter; iter = iter->parent ) {
+ if (!strcmp(current_file->name,iter->name) ) {
+ printf("%s:%d: recursive inclusion detected. "
+ "Inclusion path:\n current file : '%s'\n",
+ zconf_curname(), zconf_lineno(),
+ zconf_curname());
+ iter = current_file->parent;
+ while (iter && \
+ strcmp(iter->name,current_file->name)) {
+ printf(" included from: '%s:%d'\n",
+ iter->name, iter->lineno-1);
+ iter = iter->parent;
+ }
+ if (iter)
+ printf(" included from: '%s:%d'\n",
+ iter->name, iter->lineno+1);
+ exit(1);
+ }
+ }
+ file->lineno = 1;
+ file->parent = current_file;
+ current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+ struct buffer *parent;
+
+ current_file = current_file->parent;
+
+ parent = current_buf->parent;
+ if (parent) {
+ fclose(yyin);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(parent->state);
+ }
+ free(current_buf);
+ current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+ return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+ return current_pos.file ? current_pos.file->name : "<none>";
+}
diff --git a/roms/seabios/scripts/kconfig/zconf.lex.c_shipped b/roms/seabios/scripts/kconfig/zconf.lex.c_shipped
new file mode 100644
index 00000000..349a7f24
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/zconf.lex.c_shipped
@@ -0,0 +1,2420 @@
+
+#line 3 "scripts/kconfig/zconf.lex.c_shipped"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer zconf_create_buffer
+#define yy_delete_buffer zconf_delete_buffer
+#define yy_flex_debug zconf_flex_debug
+#define yy_init_buffer zconf_init_buffer
+#define yy_flush_buffer zconf_flush_buffer
+#define yy_load_buffer_state zconf_load_buffer_state
+#define yy_switch_to_buffer zconf_switch_to_buffer
+#define yyin zconfin
+#define yyleng zconfleng
+#define yylex zconflex
+#define yylineno zconflineno
+#define yyout zconfout
+#define yyrestart zconfrestart
+#define yytext zconftext
+#define yywrap zconfwrap
+#define yyalloc zconfalloc
+#define yyrealloc zconfrealloc
+#define yyfree zconffree
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE zconfrestart(zconfin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int zconfleng;
+
+extern FILE *zconfin, *zconfout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up zconftext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up zconftext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via zconfrestart()), so that the user can continue scanning by
+ * just pointing zconfin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when zconftext is formed. */
+static char yy_hold_char;
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+int zconfleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow zconfwrap()'s to do buffer switches
+ * instead of setting up a fresh zconfin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void zconfrestart (FILE *input_file );
+void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size );
+void zconf_delete_buffer (YY_BUFFER_STATE b );
+void zconf_flush_buffer (YY_BUFFER_STATE b );
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer );
+void zconfpop_buffer_state (void );
+
+static void zconfensure_buffer_stack (void );
+static void zconf_load_buffer_state (void );
+static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len );
+
+void *zconfalloc (yy_size_t );
+void *zconfrealloc (void *,yy_size_t );
+void zconffree (void * );
+
+#define yy_new_buffer zconf_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ zconfensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ zconfensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define zconfwrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int zconflineno;
+
+int zconflineno = 1;
+
+extern char *zconftext;
+#define yytext_ptr zconftext
+static yyconst flex_int16_t yy_nxt[][17] =
+ {
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0
+ },
+
+ {
+ 11, 12, 13, 14, 12, 12, 15, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12
+ },
+
+ {
+ 11, 12, 13, 14, 12, 12, 15, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12
+ },
+
+ {
+ 11, 16, 16, 17, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 18, 16, 16, 16
+ },
+
+ {
+ 11, 16, 16, 17, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 18, 16, 16, 16
+
+ },
+
+ {
+ 11, 19, 20, 21, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19
+ },
+
+ {
+ 11, 19, 20, 21, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19
+ },
+
+ {
+ 11, 22, 22, 23, 22, 24, 22, 22, 24, 22,
+ 22, 22, 22, 22, 22, 25, 22
+ },
+
+ {
+ 11, 22, 22, 23, 22, 24, 22, 22, 24, 22,
+ 22, 22, 22, 22, 22, 25, 22
+ },
+
+ {
+ 11, 26, 26, 27, 28, 29, 30, 31, 29, 32,
+ 33, 34, 35, 35, 36, 37, 38
+
+ },
+
+ {
+ 11, 26, 26, 27, 28, 29, 30, 31, 29, 32,
+ 33, 34, 35, 35, 36, 37, 38
+ },
+
+ {
+ -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+ -11, -11, -11, -11, -11, -11, -11
+ },
+
+ {
+ 11, -12, -12, -12, -12, -12, -12, -12, -12, -12,
+ -12, -12, -12, -12, -12, -12, -12
+ },
+
+ {
+ 11, -13, 39, 40, -13, -13, 41, -13, -13, -13,
+ -13, -13, -13, -13, -13, -13, -13
+ },
+
+ {
+ 11, -14, -14, -14, -14, -14, -14, -14, -14, -14,
+ -14, -14, -14, -14, -14, -14, -14
+
+ },
+
+ {
+ 11, 42, 42, 43, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42
+ },
+
+ {
+ 11, -16, -16, -16, -16, -16, -16, -16, -16, -16,
+ -16, -16, -16, -16, -16, -16, -16
+ },
+
+ {
+ 11, -17, -17, -17, -17, -17, -17, -17, -17, -17,
+ -17, -17, -17, -17, -17, -17, -17
+ },
+
+ {
+ 11, -18, -18, -18, -18, -18, -18, -18, -18, -18,
+ -18, -18, -18, 44, -18, -18, -18
+ },
+
+ {
+ 11, 45, 45, -19, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45
+
+ },
+
+ {
+ 11, -20, 46, 47, -20, -20, -20, -20, -20, -20,
+ -20, -20, -20, -20, -20, -20, -20
+ },
+
+ {
+ 11, 48, -21, -21, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48
+ },
+
+ {
+ 11, 49, 49, 50, 49, -22, 49, 49, -22, 49,
+ 49, 49, 49, 49, 49, -22, 49
+ },
+
+ {
+ 11, -23, -23, -23, -23, -23, -23, -23, -23, -23,
+ -23, -23, -23, -23, -23, -23, -23
+ },
+
+ {
+ 11, -24, -24, -24, -24, -24, -24, -24, -24, -24,
+ -24, -24, -24, -24, -24, -24, -24
+
+ },
+
+ {
+ 11, 51, 51, 52, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51
+ },
+
+ {
+ 11, -26, -26, -26, -26, -26, -26, -26, -26, -26,
+ -26, -26, -26, -26, -26, -26, -26
+ },
+
+ {
+ 11, -27, -27, -27, -27, -27, -27, -27, -27, -27,
+ -27, -27, -27, -27, -27, -27, -27
+ },
+
+ {
+ 11, -28, -28, -28, -28, -28, -28, -28, -28, -28,
+ -28, -28, -28, -28, 53, -28, -28
+ },
+
+ {
+ 11, -29, -29, -29, -29, -29, -29, -29, -29, -29,
+ -29, -29, -29, -29, -29, -29, -29
+
+ },
+
+ {
+ 11, 54, 54, -30, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54
+ },
+
+ {
+ 11, -31, -31, -31, -31, -31, -31, 55, -31, -31,
+ -31, -31, -31, -31, -31, -31, -31
+ },
+
+ {
+ 11, -32, -32, -32, -32, -32, -32, -32, -32, -32,
+ -32, -32, -32, -32, -32, -32, -32
+ },
+
+ {
+ 11, -33, -33, -33, -33, -33, -33, -33, -33, -33,
+ -33, -33, -33, -33, -33, -33, -33
+ },
+
+ {
+ 11, -34, -34, -34, -34, -34, -34, -34, -34, -34,
+ -34, 56, 57, 57, -34, -34, -34
+
+ },
+
+ {
+ 11, -35, -35, -35, -35, -35, -35, -35, -35, -35,
+ -35, 57, 57, 57, -35, -35, -35
+ },
+
+ {
+ 11, -36, -36, -36, -36, -36, -36, -36, -36, -36,
+ -36, -36, -36, -36, -36, -36, -36
+ },
+
+ {
+ 11, -37, -37, 58, -37, -37, -37, -37, -37, -37,
+ -37, -37, -37, -37, -37, -37, -37
+ },
+
+ {
+ 11, -38, -38, -38, -38, -38, -38, -38, -38, -38,
+ -38, -38, -38, -38, -38, -38, 59
+ },
+
+ {
+ 11, -39, 39, 40, -39, -39, 41, -39, -39, -39,
+ -39, -39, -39, -39, -39, -39, -39
+
+ },
+
+ {
+ 11, -40, -40, -40, -40, -40, -40, -40, -40, -40,
+ -40, -40, -40, -40, -40, -40, -40
+ },
+
+ {
+ 11, 42, 42, 43, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42
+ },
+
+ {
+ 11, 42, 42, 43, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42
+ },
+
+ {
+ 11, -43, -43, -43, -43, -43, -43, -43, -43, -43,
+ -43, -43, -43, -43, -43, -43, -43
+ },
+
+ {
+ 11, -44, -44, -44, -44, -44, -44, -44, -44, -44,
+ -44, -44, -44, 44, -44, -44, -44
+
+ },
+
+ {
+ 11, 45, 45, -45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45
+ },
+
+ {
+ 11, -46, 46, 47, -46, -46, -46, -46, -46, -46,
+ -46, -46, -46, -46, -46, -46, -46
+ },
+
+ {
+ 11, 48, -47, -47, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48
+ },
+
+ {
+ 11, -48, -48, -48, -48, -48, -48, -48, -48, -48,
+ -48, -48, -48, -48, -48, -48, -48
+ },
+
+ {
+ 11, 49, 49, 50, 49, -49, 49, 49, -49, 49,
+ 49, 49, 49, 49, 49, -49, 49
+
+ },
+
+ {
+ 11, -50, -50, -50, -50, -50, -50, -50, -50, -50,
+ -50, -50, -50, -50, -50, -50, -50
+ },
+
+ {
+ 11, -51, -51, 52, -51, -51, -51, -51, -51, -51,
+ -51, -51, -51, -51, -51, -51, -51
+ },
+
+ {
+ 11, -52, -52, -52, -52, -52, -52, -52, -52, -52,
+ -52, -52, -52, -52, -52, -52, -52
+ },
+
+ {
+ 11, -53, -53, -53, -53, -53, -53, -53, -53, -53,
+ -53, -53, -53, -53, -53, -53, -53
+ },
+
+ {
+ 11, 54, 54, -54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54
+
+ },
+
+ {
+ 11, -55, -55, -55, -55, -55, -55, -55, -55, -55,
+ -55, -55, -55, -55, -55, -55, -55
+ },
+
+ {
+ 11, -56, -56, -56, -56, -56, -56, -56, -56, -56,
+ -56, 60, 57, 57, -56, -56, -56
+ },
+
+ {
+ 11, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, 57, 57, 57, -57, -57, -57
+ },
+
+ {
+ 11, -58, -58, -58, -58, -58, -58, -58, -58, -58,
+ -58, -58, -58, -58, -58, -58, -58
+ },
+
+ {
+ 11, -59, -59, -59, -59, -59, -59, -59, -59, -59,
+ -59, -59, -59, -59, -59, -59, -59
+
+ },
+
+ {
+ 11, -60, -60, -60, -60, -60, -60, -60, -60, -60,
+ -60, 57, 57, 57, -60, -60, -60
+ },
+
+ } ;
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up zconftext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ zconfleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 33
+#define YY_END_OF_BUFFER 34
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[61] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 34, 5, 4, 2, 3, 7, 8, 6, 32, 29,
+ 31, 24, 28, 27, 26, 22, 17, 13, 16, 20,
+ 22, 11, 12, 19, 19, 14, 22, 22, 4, 2,
+ 3, 3, 1, 6, 32, 29, 31, 30, 24, 23,
+ 26, 25, 15, 20, 9, 19, 19, 21, 10, 18
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 5, 6, 1, 1, 7, 8, 9,
+ 10, 1, 1, 1, 11, 12, 12, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 1, 1, 1,
+ 14, 1, 1, 1, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 1, 15, 1, 1, 13, 1, 13, 13, 13, 13,
+
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 1, 16, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+extern int zconf_flex_debug;
+int zconf_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *zconftext;
+#define YY_NO_INPUT 1
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "lkc.h"
+
+#define START_STRSIZE 16
+
+static struct {
+ struct file *file;
+ int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+ text = xmalloc(START_STRSIZE);
+ text_asize = START_STRSIZE;
+ text_size = 0;
+ *text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+ int new_size = text_size + size + 1;
+ if (new_size > text_asize) {
+ new_size += START_STRSIZE - 1;
+ new_size &= -START_STRSIZE;
+ text = realloc(text, new_size);
+ text_asize = new_size;
+ }
+ memcpy(text + text_size, str, size);
+ text_size += size;
+ text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+ text = xmalloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+
+#define INITIAL 0
+#define COMMAND 1
+#define HELP 2
+#define STRING 3
+#define PARAM 4
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int zconflex_destroy (void );
+
+int zconfget_debug (void );
+
+void zconfset_debug (int debug_flag );
+
+YY_EXTRA_TYPE zconfget_extra (void );
+
+void zconfset_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *zconfget_in (void );
+
+void zconfset_in (FILE * in_str );
+
+FILE *zconfget_out (void );
+
+void zconfset_out (FILE * out_str );
+
+int zconfget_leng (void );
+
+char *zconfget_text (void );
+
+int zconfget_lineno (void );
+
+void zconfset_lineno (int line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int zconfwrap (void );
+#else
+extern int zconfwrap (void );
+#endif
+#endif
+
+ static void yyunput (int c,char *buf_ptr );
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( zconftext, zconfleng, 1, zconfout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ errno=0; \
+ while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(zconfin); \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int zconflex (void);
+
+#define YY_DECL int zconflex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after zconftext and zconfleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+ int str = 0;
+ int ts, i;
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! zconfin )
+ zconfin = stdin;
+
+ if ( ! zconfout )
+ zconfout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ zconfensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ zconf_create_buffer(zconfin,YY_BUF_SIZE );
+ }
+
+ zconf_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of zconftext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 )
+ ++yy_cp;
+
+ yy_current_state = -yy_current_state;
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+case 1:
+/* rule 1 can match eol */
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+{
+ current_file->lineno++;
+ return T_EOL;
+}
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+ BEGIN(COMMAND);
+}
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{
+ unput(zconftext[0]);
+ BEGIN(COMMAND);
+}
+ YY_BREAK
+
+case 6:
+YY_RULE_SETUP
+{
+ const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+ BEGIN(PARAM);
+ current_pos.file = current_file;
+ current_pos.lineno = current_file->lineno;
+ if (id && id->flags & TF_COMMAND) {
+ zconflval.id = id;
+ return id->token;
+ }
+ alloc_string(zconftext, zconfleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+
+ YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+{
+ BEGIN(INITIAL);
+ current_file->lineno++;
+ return T_EOL;
+ }
+ YY_BREAK
+
+case 9:
+YY_RULE_SETUP
+return T_AND;
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+return T_OR;
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+return T_OPEN_PAREN;
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+return T_CLOSE_PAREN;
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+return T_NOT;
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+return T_EQUAL;
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+return T_UNEQUAL;
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{
+ str = zconftext[0];
+ new_string();
+ BEGIN(STRING);
+ }
+ YY_BREAK
+case 17:
+/* rule 17 can match eol */
+YY_RULE_SETUP
+BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+/* ignore */
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+{
+ const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+ if (id && id->flags & TF_PARAM) {
+ zconflval.id = id;
+ return id->token;
+ }
+ alloc_string(zconftext, zconfleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+/* comment */
+ YY_BREAK
+case 21:
+/* rule 21 can match eol */
+YY_RULE_SETUP
+current_file->lineno++;
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+
+ YY_BREAK
+case YY_STATE_EOF(PARAM):
+{
+ BEGIN(INITIAL);
+ }
+ YY_BREAK
+
+case 23:
+/* rule 23 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+ append_string(zconftext, zconfleng);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+{
+ append_string(zconftext, zconfleng);
+ }
+ YY_BREAK
+case 25:
+/* rule 25 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+ append_string(zconftext + 1, zconfleng - 1);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+{
+ append_string(zconftext + 1, zconfleng - 1);
+ }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+{
+ if (str == zconftext[0]) {
+ BEGIN(PARAM);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(zconftext, 1);
+ }
+ YY_BREAK
+case 28:
+/* rule 28 can match eol */
+YY_RULE_SETUP
+{
+ printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+ current_file->lineno++;
+ BEGIN(INITIAL);
+ return T_EOL;
+ }
+ YY_BREAK
+case YY_STATE_EOF(STRING):
+{
+ BEGIN(INITIAL);
+ }
+ YY_BREAK
+
+case 29:
+YY_RULE_SETUP
+{
+ ts = 0;
+ for (i = 0; i < zconfleng; i++) {
+ if (zconftext[i] == '\t')
+ ts = (ts & ~7) + 8;
+ else
+ ts++;
+ }
+ last_ts = ts;
+ if (first_ts) {
+ if (ts < first_ts) {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ ts -= first_ts;
+ while (ts > 8) {
+ append_string(" ", 8);
+ ts -= 8;
+ }
+ append_string(" ", ts);
+ }
+ }
+ YY_BREAK
+case 30:
+/* rule 30 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+ current_file->lineno++;
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ YY_BREAK
+case 31:
+/* rule 31 can match eol */
+YY_RULE_SETUP
+{
+ current_file->lineno++;
+ append_string("\n", 1);
+ }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+{
+ while (zconfleng) {
+ if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t'))
+ break;
+ zconfleng--;
+ }
+ append_string(zconftext, zconfleng);
+ if (!first_ts)
+ first_ts = last_ts;
+ }
+ YY_BREAK
+case YY_STATE_EOF(HELP):
+{
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ YY_BREAK
+
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMAND):
+{
+ if (current_file) {
+ zconf_endfile();
+ return T_EOL;
+ }
+ fclose(zconfin);
+ yyterminate();
+}
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed zconfin at a new source and called
+ * zconflex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( zconfwrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * zconftext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of zconflex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), (size_t) num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ zconfrestart(zconfin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) zconfrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+
+ yy_current_state = yy_nxt[yy_current_state][1];
+ yy_is_jam = (yy_current_state <= 0);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ static void yyunput (int c, register char * yy_bp )
+{
+ register char *yy_cp;
+
+ yy_cp = (yy_c_buf_p);
+
+ /* undo effects of setting up zconftext */
+ *yy_cp = (yy_hold_char);
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = (yy_n_chars) + 2;
+ register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ (yytext_ptr) = yy_bp;
+ (yy_hold_char) = *yy_cp;
+ (yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ int offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ zconfrestart(zconfin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( zconfwrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve zconftext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void zconfrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ zconfensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ zconf_create_buffer(zconfin,YY_BUF_SIZE );
+ }
+
+ zconf_init_buffer(YY_CURRENT_BUFFER,input_file );
+ zconf_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * zconfpop_buffer_state();
+ * zconfpush_buffer_state(new_buffer);
+ */
+ zconfensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ zconf_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (zconfwrap()) processing, but the only time this flag
+ * is looked at is after zconfwrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void zconf_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE zconf_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ zconf_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with zconf_create_buffer()
+ *
+ */
+ void zconf_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ zconffree((void *) b->yy_ch_buf );
+
+ zconffree((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a zconfrestart() or at EOF.
+ */
+ static void zconf_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ zconf_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then zconf_init_buffer was _probably_
+ * called from zconfrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void zconf_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ zconf_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ zconfensure_buffer_stack();
+
+ /* This block is copied from zconf_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from zconf_switch_to_buffer. */
+ zconf_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void zconfpop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ zconf_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ zconf_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void zconfensure_buffer_stack (void)
+{
+ int num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ zconf_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to zconflex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * zconf_scan_bytes() instead.
+ */
+YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr )
+{
+
+ return zconf_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char * yybytes, int _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) zconfalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = zconf_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up zconftext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ zconftext[zconfleng] = (yy_hold_char); \
+ (yy_c_buf_p) = zconftext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ zconfleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int zconfget_lineno (void)
+{
+
+ return zconflineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *zconfget_in (void)
+{
+ return zconfin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *zconfget_out (void)
+{
+ return zconfout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int zconfget_leng (void)
+{
+ return zconfleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *zconfget_text (void)
+{
+ return zconftext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void zconfset_lineno (int line_number )
+{
+
+ zconflineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see zconf_switch_to_buffer
+ */
+void zconfset_in (FILE * in_str )
+{
+ zconfin = in_str ;
+}
+
+void zconfset_out (FILE * out_str )
+{
+ zconfout = out_str ;
+}
+
+int zconfget_debug (void)
+{
+ return zconf_flex_debug;
+}
+
+void zconfset_debug (int bdebug )
+{
+ zconf_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from zconflex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ zconfin = stdin;
+ zconfout = stdout;
+#else
+ zconfin = (FILE *) 0;
+ zconfout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * zconflex_init()
+ */
+ return 0;
+}
+
+/* zconflex_destroy is for both reentrant and non-reentrant scanners. */
+int zconflex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ zconf_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ zconfpop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ zconffree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * zconflex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *zconfalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *zconfrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void zconffree (void * ptr )
+{
+ free( (char *) ptr ); /* see zconfrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+void zconf_starthelp(void)
+{
+ new_string();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ zconflval.string = text;
+ BEGIN(INITIAL);
+}
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+ char *env, fullname[PATH_MAX+1];
+ FILE *f;
+
+ f = fopen(name, "r");
+ if (!f && name != NULL && name[0] != '/') {
+ env = getenv(SRCTREE);
+ if (env) {
+ sprintf(fullname, "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ zconfin = zconf_fopen(name);
+ if (!zconfin) {
+ printf("can't find file %s\n", name);
+ exit(1);
+ }
+
+ current_buf = xmalloc(sizeof(*current_buf));
+ memset(current_buf, 0, sizeof(*current_buf));
+
+ current_file = file_lookup(name);
+ current_file->lineno = 1;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct file *iter;
+ struct file *file = file_lookup(name);
+ struct buffer *buf = xmalloc(sizeof(*buf));
+ memset(buf, 0, sizeof(*buf));
+
+ current_buf->state = YY_CURRENT_BUFFER;
+ zconfin = zconf_fopen(file->name);
+ if (!zconfin) {
+ printf("%s:%d: can't open file \"%s\"\n",
+ zconf_curname(), zconf_lineno(), file->name);
+ exit(1);
+ }
+ zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
+ buf->parent = current_buf;
+ current_buf = buf;
+
+ for (iter = current_file->parent; iter; iter = iter->parent ) {
+ if (!strcmp(current_file->name,iter->name) ) {
+ printf("%s:%d: recursive inclusion detected. "
+ "Inclusion path:\n current file : '%s'\n",
+ zconf_curname(), zconf_lineno(),
+ zconf_curname());
+ iter = current_file->parent;
+ while (iter && \
+ strcmp(iter->name,current_file->name)) {
+ printf(" included from: '%s:%d'\n",
+ iter->name, iter->lineno-1);
+ iter = iter->parent;
+ }
+ if (iter)
+ printf(" included from: '%s:%d'\n",
+ iter->name, iter->lineno+1);
+ exit(1);
+ }
+ }
+ file->lineno = 1;
+ file->parent = current_file;
+ current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+ struct buffer *parent;
+
+ current_file = current_file->parent;
+
+ parent = current_buf->parent;
+ if (parent) {
+ fclose(zconfin);
+ zconf_delete_buffer(YY_CURRENT_BUFFER);
+ zconf_switch_to_buffer(parent->state);
+ }
+ free(current_buf);
+ current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+ return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+ return current_pos.file ? current_pos.file->name : "<none>";
+}
+
diff --git a/roms/seabios/scripts/kconfig/zconf.tab.c_shipped b/roms/seabios/scripts/kconfig/zconf.tab.c_shipped
new file mode 100644
index 00000000..de5e84ed
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/zconf.tab.c_shipped
@@ -0,0 +1,2538 @@
+/* A Bison parser, made by GNU Bison 2.5. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.5"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names. */
+#define yyparse zconfparse
+#define yylex zconflex
+#define yyerror zconferror
+#define yylval zconflval
+#define yychar zconfchar
+#define yydebug zconfdebug
+#define yynerrs zconfnerrs
+
+
+/* Copy the first part of user declarations. */
+
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "lkc.h"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD 0x0001
+#define DEBUG_PARSE 0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
+
+static struct menu *current_menu, *current_entry;
+
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ T_MAINMENU = 258,
+ T_MENU = 259,
+ T_ENDMENU = 260,
+ T_SOURCE = 261,
+ T_CHOICE = 262,
+ T_ENDCHOICE = 263,
+ T_COMMENT = 264,
+ T_CONFIG = 265,
+ T_MENUCONFIG = 266,
+ T_HELP = 267,
+ T_HELPTEXT = 268,
+ T_IF = 269,
+ T_ENDIF = 270,
+ T_DEPENDS = 271,
+ T_OPTIONAL = 272,
+ T_PROMPT = 273,
+ T_TYPE = 274,
+ T_DEFAULT = 275,
+ T_SELECT = 276,
+ T_RANGE = 277,
+ T_VISIBLE = 278,
+ T_OPTION = 279,
+ T_ON = 280,
+ T_WORD = 281,
+ T_WORD_QUOTE = 282,
+ T_UNEQUAL = 283,
+ T_CLOSE_PAREN = 284,
+ T_OPEN_PAREN = 285,
+ T_EOL = 286,
+ T_OR = 287,
+ T_AND = 288,
+ T_EQUAL = 289,
+ T_NOT = 290
+ };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+
+ char *string;
+ struct file *file;
+ struct symbol *symbol;
+ struct expr *expr;
+ struct menu *menu;
+ const struct kconf_id *id;
+
+
+
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Include zconf.hash.c here so it can see the token constants. */
+#include "zconf.hash.c"
+
+
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 11
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 290
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 36
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 50
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 118
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 191
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 290
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 6, 8, 11, 13, 14, 17, 20,
+ 23, 26, 31, 36, 40, 42, 44, 46, 48, 50,
+ 52, 54, 56, 58, 60, 62, 64, 66, 68, 72,
+ 75, 79, 82, 86, 89, 90, 93, 96, 99, 102,
+ 105, 108, 112, 117, 122, 127, 133, 137, 138, 142,
+ 143, 146, 150, 153, 155, 159, 160, 163, 166, 169,
+ 172, 175, 180, 184, 187, 192, 193, 196, 200, 202,
+ 206, 207, 210, 213, 216, 220, 224, 228, 230, 234,
+ 235, 238, 241, 244, 248, 252, 255, 258, 261, 262,
+ 265, 268, 271, 276, 277, 280, 283, 286, 287, 290,
+ 292, 294, 297, 300, 303, 305, 308, 309, 312, 314,
+ 318, 322, 326, 329, 333, 337, 339, 341, 342
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 37, 0, -1, 81, 38, -1, 38, -1, 63, 39,
+ -1, 39, -1, -1, 39, 41, -1, 39, 55, -1,
+ 39, 67, -1, 39, 80, -1, 39, 26, 1, 31,
+ -1, 39, 40, 1, 31, -1, 39, 1, 31, -1,
+ 16, -1, 18, -1, 19, -1, 21, -1, 17, -1,
+ 22, -1, 20, -1, 23, -1, 31, -1, 61, -1,
+ 71, -1, 44, -1, 46, -1, 69, -1, 26, 1,
+ 31, -1, 1, 31, -1, 10, 26, 31, -1, 43,
+ 47, -1, 11, 26, 31, -1, 45, 47, -1, -1,
+ 47, 48, -1, 47, 49, -1, 47, 75, -1, 47,
+ 73, -1, 47, 42, -1, 47, 31, -1, 19, 78,
+ 31, -1, 18, 79, 82, 31, -1, 20, 83, 82,
+ 31, -1, 21, 26, 82, 31, -1, 22, 84, 84,
+ 82, 31, -1, 24, 50, 31, -1, -1, 50, 26,
+ 51, -1, -1, 34, 79, -1, 7, 85, 31, -1,
+ 52, 56, -1, 80, -1, 53, 58, 54, -1, -1,
+ 56, 57, -1, 56, 75, -1, 56, 73, -1, 56,
+ 31, -1, 56, 42, -1, 18, 79, 82, 31, -1,
+ 19, 78, 31, -1, 17, 31, -1, 20, 26, 82,
+ 31, -1, -1, 58, 41, -1, 14, 83, 81, -1,
+ 80, -1, 59, 62, 60, -1, -1, 62, 41, -1,
+ 62, 67, -1, 62, 55, -1, 3, 79, 81, -1,
+ 4, 79, 31, -1, 64, 76, 74, -1, 80, -1,
+ 65, 68, 66, -1, -1, 68, 41, -1, 68, 67,
+ -1, 68, 55, -1, 6, 79, 31, -1, 9, 79,
+ 31, -1, 70, 74, -1, 12, 31, -1, 72, 13,
+ -1, -1, 74, 75, -1, 74, 31, -1, 74, 42,
+ -1, 16, 25, 83, 31, -1, -1, 76, 77, -1,
+ 76, 31, -1, 23, 82, -1, -1, 79, 82, -1,
+ 26, -1, 27, -1, 5, 31, -1, 8, 31, -1,
+ 15, 31, -1, 31, -1, 81, 31, -1, -1, 14,
+ 83, -1, 84, -1, 84, 34, 84, -1, 84, 28,
+ 84, -1, 30, 83, 29, -1, 35, 83, -1, 83,
+ 32, 83, -1, 83, 33, 83, -1, 26, -1, 27,
+ -1, -1, 26, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 103, 103, 103, 105, 105, 107, 109, 110, 111,
+ 112, 113, 114, 118, 122, 122, 122, 122, 122, 122,
+ 122, 122, 126, 127, 128, 129, 130, 131, 135, 136,
+ 142, 150, 156, 164, 174, 176, 177, 178, 179, 180,
+ 181, 184, 192, 198, 208, 214, 220, 223, 225, 236,
+ 237, 242, 251, 256, 264, 267, 269, 270, 271, 272,
+ 273, 276, 282, 293, 299, 309, 311, 316, 324, 332,
+ 335, 337, 338, 339, 344, 351, 358, 363, 371, 374,
+ 376, 377, 378, 381, 389, 396, 403, 409, 416, 418,
+ 419, 420, 423, 431, 433, 434, 437, 444, 446, 451,
+ 452, 455, 456, 457, 461, 462, 465, 466, 469, 470,
+ 471, 472, 473, 474, 475, 478, 479, 482, 483
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU",
+ "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
+ "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
+ "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE",
+ "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL",
+ "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL",
+ "T_NOT", "$accept", "input", "start", "stmt_list", "option_name",
+ "common_stmt", "option_error", "config_entry_start", "config_stmt",
+ "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
+ "config_option", "symbol_option", "symbol_option_list",
+ "symbol_option_arg", "choice", "choice_entry", "choice_end",
+ "choice_stmt", "choice_option_list", "choice_option", "choice_block",
+ "if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu",
+ "menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt",
+ "comment", "comment_stmt", "help_start", "help", "depends_list",
+ "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt",
+ "end", "nl", "if_expr", "expr", "symbol", "word_opt", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 36, 37, 37, 38, 38, 39, 39, 39, 39,
+ 39, 39, 39, 39, 40, 40, 40, 40, 40, 40,
+ 40, 40, 41, 41, 41, 41, 41, 41, 42, 42,
+ 43, 44, 45, 46, 47, 47, 47, 47, 47, 47,
+ 47, 48, 48, 48, 48, 48, 49, 50, 50, 51,
+ 51, 52, 53, 54, 55, 56, 56, 56, 56, 56,
+ 56, 57, 57, 57, 57, 58, 58, 59, 60, 61,
+ 62, 62, 62, 62, 63, 64, 65, 66, 67, 68,
+ 68, 68, 68, 69, 70, 71, 72, 73, 74, 74,
+ 74, 74, 75, 76, 76, 76, 77, 78, 78, 79,
+ 79, 80, 80, 80, 81, 81, 82, 82, 83, 83,
+ 83, 83, 83, 83, 83, 84, 84, 85, 85
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 2, 1, 2, 1, 0, 2, 2, 2,
+ 2, 4, 4, 3, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 3, 2,
+ 3, 2, 3, 2, 0, 2, 2, 2, 2, 2,
+ 2, 3, 4, 4, 4, 5, 3, 0, 3, 0,
+ 2, 3, 2, 1, 3, 0, 2, 2, 2, 2,
+ 2, 4, 3, 2, 4, 0, 2, 3, 1, 3,
+ 0, 2, 2, 2, 3, 3, 3, 1, 3, 0,
+ 2, 2, 2, 3, 3, 2, 2, 2, 0, 2,
+ 2, 2, 4, 0, 2, 2, 2, 0, 2, 1,
+ 1, 2, 2, 2, 1, 2, 0, 2, 1, 3,
+ 3, 3, 2, 3, 3, 1, 1, 0, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 6, 0, 104, 0, 3, 0, 6, 6, 99, 100,
+ 0, 1, 0, 0, 0, 0, 117, 0, 0, 0,
+ 0, 0, 0, 14, 18, 15, 16, 20, 17, 19,
+ 21, 0, 22, 0, 7, 34, 25, 34, 26, 55,
+ 65, 8, 70, 23, 93, 79, 9, 27, 88, 24,
+ 10, 0, 105, 2, 74, 13, 0, 101, 0, 118,
+ 0, 102, 0, 0, 0, 115, 116, 0, 0, 0,
+ 108, 103, 0, 0, 0, 0, 0, 0, 0, 88,
+ 0, 0, 75, 83, 51, 84, 30, 32, 0, 112,
+ 0, 0, 67, 0, 0, 11, 12, 0, 0, 0,
+ 0, 97, 0, 0, 0, 47, 0, 40, 39, 35,
+ 36, 0, 38, 37, 0, 0, 97, 0, 59, 60,
+ 56, 58, 57, 66, 54, 53, 71, 73, 69, 72,
+ 68, 106, 95, 0, 94, 80, 82, 78, 81, 77,
+ 90, 91, 89, 111, 113, 114, 110, 109, 29, 86,
+ 0, 106, 0, 106, 106, 106, 0, 0, 0, 87,
+ 63, 106, 0, 106, 0, 96, 0, 0, 41, 98,
+ 0, 0, 106, 49, 46, 28, 0, 62, 0, 107,
+ 92, 42, 43, 44, 0, 0, 48, 61, 64, 45,
+ 50
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 3, 4, 5, 33, 34, 108, 35, 36, 37,
+ 38, 74, 109, 110, 157, 186, 39, 40, 124, 41,
+ 76, 120, 77, 42, 128, 43, 78, 6, 44, 45,
+ 137, 46, 80, 47, 48, 49, 111, 112, 81, 113,
+ 79, 134, 152, 153, 50, 7, 165, 69, 70, 60
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -90
+static const yytype_int16 yypact[] =
+{
+ 4, 42, -90, 96, -90, 111, -90, 15, -90, -90,
+ 75, -90, 82, 42, 104, 42, 110, 107, 42, 115,
+ 125, -4, 121, -90, -90, -90, -90, -90, -90, -90,
+ -90, 162, -90, 163, -90, -90, -90, -90, -90, -90,
+ -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,
+ -90, 139, -90, -90, 138, -90, 142, -90, 143, -90,
+ 152, -90, 164, 167, 168, -90, -90, -4, -4, 77,
+ -18, -90, 177, 185, 33, 71, 195, 247, 236, -2,
+ 236, 171, -90, -90, -90, -90, -90, -90, 41, -90,
+ -4, -4, 138, 97, 97, -90, -90, 186, 187, 194,
+ 42, 42, -4, 196, 97, -90, 219, -90, -90, -90,
+ -90, 210, -90, -90, 204, 42, 42, 199, -90, -90,
+ -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,
+ -90, 222, -90, 223, -90, -90, -90, -90, -90, -90,
+ -90, -90, -90, -90, 215, -90, -90, -90, -90, -90,
+ -4, 222, 228, 222, -5, 222, 97, 35, 229, -90,
+ -90, 222, 232, 222, -4, -90, 135, 233, -90, -90,
+ 234, 235, 222, 240, -90, -90, 237, -90, 239, -13,
+ -90, -90, -90, -90, 244, 42, -90, -90, -90, -90,
+ -90
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -90, -90, 269, 271, -90, 23, -70, -90, -90, -90,
+ -90, 243, -90, -90, -90, -90, -90, -90, -90, -48,
+ -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,
+ -90, -20, -90, -90, -90, -90, -90, 206, 205, -68,
+ -90, -90, 169, -1, 27, -7, 118, -66, -89, -90
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -86
+static const yytype_int16 yytable[] =
+{
+ 10, 88, 89, 54, 146, 147, 119, 1, 122, 164,
+ 93, 141, 56, 142, 58, 156, 94, 62, 1, 90,
+ 91, 131, 65, 66, 144, 145, 67, 90, 91, 132,
+ 127, 68, 136, -31, 97, 2, 154, -31, -31, -31,
+ -31, -31, -31, -31, -31, 98, 52, -31, -31, 99,
+ -31, 100, 101, 102, 103, 104, -31, 105, 129, 106,
+ 138, 173, 92, 141, 107, 142, 174, 172, 8, 9,
+ 143, -33, 97, 90, 91, -33, -33, -33, -33, -33,
+ -33, -33, -33, 98, 166, -33, -33, 99, -33, 100,
+ 101, 102, 103, 104, -33, 105, 11, 106, 179, 151,
+ 123, 126, 107, 135, 125, 130, 2, 139, 2, 90,
+ 91, -5, 12, 55, 161, 13, 14, 15, 16, 17,
+ 18, 19, 20, 65, 66, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 57, 59, 31, 61, -4,
+ 12, 63, 32, 13, 14, 15, 16, 17, 18, 19,
+ 20, 64, 71, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 72, 73, 31, 180, 90, 91, 52,
+ 32, -85, 97, 82, 83, -85, -85, -85, -85, -85,
+ -85, -85, -85, 84, 190, -85, -85, 99, -85, -85,
+ -85, -85, -85, -85, -85, 85, 97, 106, 86, 87,
+ -52, -52, 140, -52, -52, -52, -52, 98, 95, -52,
+ -52, 99, 114, 115, 116, 117, 96, 148, 149, 150,
+ 158, 106, 155, 159, 97, 163, 118, -76, -76, -76,
+ -76, -76, -76, -76, -76, 160, 164, -76, -76, 99,
+ 13, 14, 15, 16, 17, 18, 19, 20, 91, 106,
+ 21, 22, 14, 15, 140, 17, 18, 19, 20, 168,
+ 175, 21, 22, 177, 181, 182, 183, 32, 187, 167,
+ 188, 169, 170, 171, 185, 189, 53, 51, 32, 176,
+ 75, 178, 121, 0, 133, 162, 0, 0, 0, 0,
+ 184
+};
+
+#define yypact_value_is_default(yystate) \
+ ((yystate) == (-90))
+
+#define yytable_value_is_error(yytable_value) \
+ YYID (0)
+
+static const yytype_int16 yycheck[] =
+{
+ 1, 67, 68, 10, 93, 94, 76, 3, 76, 14,
+ 28, 81, 13, 81, 15, 104, 34, 18, 3, 32,
+ 33, 23, 26, 27, 90, 91, 30, 32, 33, 31,
+ 78, 35, 80, 0, 1, 31, 102, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 31, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 78, 26,
+ 80, 26, 69, 133, 31, 133, 31, 156, 26, 27,
+ 29, 0, 1, 32, 33, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 150, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 0, 26, 164, 100,
+ 77, 78, 31, 80, 77, 78, 31, 80, 31, 32,
+ 33, 0, 1, 31, 115, 4, 5, 6, 7, 8,
+ 9, 10, 11, 26, 27, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 31, 26, 26, 31, 0,
+ 1, 26, 31, 4, 5, 6, 7, 8, 9, 10,
+ 11, 26, 31, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 1, 1, 26, 31, 32, 33, 31,
+ 31, 0, 1, 31, 31, 4, 5, 6, 7, 8,
+ 9, 10, 11, 31, 185, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 31, 1, 26, 31, 31,
+ 5, 6, 31, 8, 9, 10, 11, 12, 31, 14,
+ 15, 16, 17, 18, 19, 20, 31, 31, 31, 25,
+ 1, 26, 26, 13, 1, 26, 31, 4, 5, 6,
+ 7, 8, 9, 10, 11, 31, 14, 14, 15, 16,
+ 4, 5, 6, 7, 8, 9, 10, 11, 33, 26,
+ 14, 15, 5, 6, 31, 8, 9, 10, 11, 31,
+ 31, 14, 15, 31, 31, 31, 31, 31, 31, 151,
+ 31, 153, 154, 155, 34, 31, 7, 6, 31, 161,
+ 37, 163, 76, -1, 79, 116, -1, -1, -1, -1,
+ 172
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 3, 31, 37, 38, 39, 63, 81, 26, 27,
+ 79, 0, 1, 4, 5, 6, 7, 8, 9, 10,
+ 11, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 26, 31, 40, 41, 43, 44, 45, 46, 52,
+ 53, 55, 59, 61, 64, 65, 67, 69, 70, 71,
+ 80, 39, 31, 38, 81, 31, 79, 31, 79, 26,
+ 85, 31, 79, 26, 26, 26, 27, 30, 35, 83,
+ 84, 31, 1, 1, 47, 47, 56, 58, 62, 76,
+ 68, 74, 31, 31, 31, 31, 31, 31, 83, 83,
+ 32, 33, 81, 28, 34, 31, 31, 1, 12, 16,
+ 18, 19, 20, 21, 22, 24, 26, 31, 42, 48,
+ 49, 72, 73, 75, 17, 18, 19, 20, 31, 42,
+ 57, 73, 75, 41, 54, 80, 41, 55, 60, 67,
+ 80, 23, 31, 74, 77, 41, 55, 66, 67, 80,
+ 31, 42, 75, 29, 83, 83, 84, 84, 31, 31,
+ 25, 79, 78, 79, 83, 26, 84, 50, 1, 13,
+ 31, 79, 78, 26, 14, 82, 83, 82, 31, 82,
+ 82, 82, 84, 26, 31, 31, 82, 31, 82, 83,
+ 31, 31, 31, 31, 82, 34, 51, 31, 31, 31,
+ 79
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* This macro is provided for backward compatibility. */
+
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = 0;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+ case 53: /* "choice_entry" */
+
+ {
+ fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+ (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+ if (current_menu == (yyvaluep->menu))
+ menu_end_menu();
+};
+
+ break;
+ case 59: /* "if_entry" */
+
+ {
+ fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+ (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+ if (current_menu == (yyvaluep->menu))
+ menu_end_menu();
+};
+
+ break;
+ case 65: /* "menu_entry" */
+
+ {
+ fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+ (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+ if (current_menu == (yyvaluep->menu))
+ menu_end_menu();
+};
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 10:
+
+ { zconf_error("unexpected end statement"); }
+ break;
+
+ case 11:
+
+ { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); }
+ break;
+
+ case 12:
+
+ {
+ zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name);
+}
+ break;
+
+ case 13:
+
+ { zconf_error("invalid statement"); }
+ break;
+
+ case 28:
+
+ { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); }
+ break;
+
+ case 29:
+
+ { zconf_error("invalid option"); }
+ break;
+
+ case 30:
+
+ {
+ struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+}
+ break;
+
+ case 31:
+
+ {
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+}
+ break;
+
+ case 32:
+
+ {
+ struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+}
+ break;
+
+ case 33:
+
+ {
+ if (current_entry->prompt)
+ current_entry->prompt->type = P_MENU;
+ else
+ zconfprint("warning: menuconfig statement without prompt");
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+}
+ break;
+
+ case 41:
+
+ {
+ menu_set_type((yyvsp[(1) - (3)].id)->stype);
+ printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ (yyvsp[(1) - (3)].id)->stype);
+}
+ break;
+
+ case 42:
+
+ {
+ menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+}
+ break;
+
+ case 43:
+
+ {
+ menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr));
+ if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN)
+ menu_set_type((yyvsp[(1) - (4)].id)->stype);
+ printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ (yyvsp[(1) - (4)].id)->stype);
+}
+ break;
+
+ case 44:
+
+ {
+ menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+}
+ break;
+
+ case 45:
+
+ {
+ menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr));
+ printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+}
+ break;
+
+ case 48:
+
+ {
+ const struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string)));
+ if (id && id->flags & TF_OPTION)
+ menu_add_option(id->token, (yyvsp[(3) - (3)].string));
+ else
+ zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string));
+ free((yyvsp[(2) - (3)].string));
+}
+ break;
+
+ case 49:
+
+ { (yyval.string) = NULL; }
+ break;
+
+ case 50:
+
+ { (yyval.string) = (yyvsp[(2) - (2)].string); }
+ break;
+
+ case 51:
+
+ {
+ struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE);
+ sym->flags |= SYMBOL_AUTO;
+ menu_add_entry(sym);
+ menu_add_expr(P_CHOICE, NULL, NULL);
+ printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+}
+ break;
+
+ case 52:
+
+ {
+ (yyval.menu) = menu_add_menu();
+}
+ break;
+
+ case 53:
+
+ {
+ if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+ }
+}
+ break;
+
+ case 61:
+
+ {
+ menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+}
+ break;
+
+ case 62:
+
+ {
+ if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) {
+ menu_set_type((yyvsp[(1) - (3)].id)->stype);
+ printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ (yyvsp[(1) - (3)].id)->stype);
+ } else
+ YYERROR;
+}
+ break;
+
+ case 63:
+
+ {
+ current_entry->sym->flags |= SYMBOL_OPTIONAL;
+ printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+}
+ break;
+
+ case 64:
+
+ {
+ if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) {
+ menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:default\n",
+ zconf_curname(), zconf_lineno());
+ } else
+ YYERROR;
+}
+ break;
+
+ case 67:
+
+ {
+ printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+ menu_add_entry(NULL);
+ menu_add_dep((yyvsp[(2) - (3)].expr));
+ (yyval.menu) = menu_add_menu();
+}
+ break;
+
+ case 68:
+
+ {
+ if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+ }
+}
+ break;
+
+ case 74:
+
+ {
+ menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
+}
+ break;
+
+ case 75:
+
+ {
+ menu_add_entry(NULL);
+ menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
+ printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+}
+ break;
+
+ case 76:
+
+ {
+ (yyval.menu) = menu_add_menu();
+}
+ break;
+
+ case 77:
+
+ {
+ if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+ }
+}
+ break;
+
+ case 83:
+
+ {
+ printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+ zconf_nextfile((yyvsp[(2) - (3)].string));
+}
+ break;
+
+ case 84:
+
+ {
+ menu_add_entry(NULL);
+ menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL);
+ printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+}
+ break;
+
+ case 85:
+
+ {
+ menu_end_entry();
+}
+ break;
+
+ case 86:
+
+ {
+ printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+ zconf_starthelp();
+}
+ break;
+
+ case 87:
+
+ {
+ current_entry->help = (yyvsp[(2) - (2)].string);
+}
+ break;
+
+ case 92:
+
+ {
+ menu_add_dep((yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+}
+ break;
+
+ case 96:
+
+ {
+ menu_add_visibility((yyvsp[(2) - (2)].expr));
+}
+ break;
+
+ case 98:
+
+ {
+ menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr));
+}
+ break;
+
+ case 101:
+
+ { (yyval.id) = (yyvsp[(1) - (2)].id); }
+ break;
+
+ case 102:
+
+ { (yyval.id) = (yyvsp[(1) - (2)].id); }
+ break;
+
+ case 103:
+
+ { (yyval.id) = (yyvsp[(1) - (2)].id); }
+ break;
+
+ case 106:
+
+ { (yyval.expr) = NULL; }
+ break;
+
+ case 107:
+
+ { (yyval.expr) = (yyvsp[(2) - (2)].expr); }
+ break;
+
+ case 108:
+
+ { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); }
+ break;
+
+ case 109:
+
+ { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); }
+ break;
+
+ case 110:
+
+ { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); }
+ break;
+
+ case 111:
+
+ { (yyval.expr) = (yyvsp[(2) - (3)].expr); }
+ break;
+
+ case 112:
+
+ { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); }
+ break;
+
+ case 113:
+
+ { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); }
+ break;
+
+ case 114:
+
+ { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); }
+ break;
+
+ case 115:
+
+ { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); }
+ break;
+
+ case 116:
+
+ { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); }
+ break;
+
+ case 117:
+
+ { (yyval.string) = NULL; }
+ break;
+
+
+
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
+
+
+void conf_parse(const char *name)
+{
+ struct symbol *sym;
+ int i;
+
+ zconf_initscan(name);
+
+ sym_init();
+ _menu_init();
+ rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
+
+ if (getenv("ZCONF_DEBUG"))
+ zconfdebug = 1;
+ zconfparse();
+ if (zconfnerrs)
+ exit(1);
+ if (!modules_sym)
+ modules_sym = sym_find( "n" );
+
+ rootmenu.prompt->text = _(rootmenu.prompt->text);
+ rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
+
+ menu_finalize(&rootmenu);
+ for_all_symbols(i, sym) {
+ if (sym_check_deps(sym))
+ zconfnerrs++;
+ }
+ if (zconfnerrs)
+ exit(1);
+ sym_set_change_count(1);
+}
+
+static const char *zconf_tokenname(int token)
+{
+ switch (token) {
+ case T_MENU: return "menu";
+ case T_ENDMENU: return "endmenu";
+ case T_CHOICE: return "choice";
+ case T_ENDCHOICE: return "endchoice";
+ case T_IF: return "if";
+ case T_ENDIF: return "endif";
+ case T_DEPENDS: return "depends";
+ case T_VISIBLE: return "visible";
+ }
+ return "<token>";
+}
+
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken)
+{
+ if (id->token != endtoken) {
+ zconf_error("unexpected '%s' within %s block",
+ kconf_id_strings + id->name, zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ if (current_menu->file != current_file) {
+ zconf_error("'%s' in different file than '%s'",
+ kconf_id_strings + id->name, zconf_tokenname(starttoken));
+ fprintf(stderr, "%s:%d: location of the '%s'\n",
+ current_menu->file->name, current_menu->lineno,
+ zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+ va_list ap;
+
+ zconfnerrs++;
+ fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+ fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+}
+
+static void print_quoted_string(FILE *out, const char *str)
+{
+ const char *p;
+ int len;
+
+ putc('"', out);
+ while ((p = strchr(str, '"'))) {
+ len = p - str;
+ if (len)
+ fprintf(out, "%.*s", len, str);
+ fputs("\\\"", out);
+ str = p + 1;
+ }
+ fputs(str, out);
+ putc('"', out);
+}
+
+static void print_symbol(FILE *out, struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ struct property *prop;
+
+ if (sym_is_choice(sym))
+ fprintf(out, "\nchoice\n");
+ else
+ fprintf(out, "\nconfig %s\n", sym->name);
+ switch (sym->type) {
+ case S_BOOLEAN:
+ fputs(" boolean\n", out);
+ break;
+ case S_TRISTATE:
+ fputs(" tristate\n", out);
+ break;
+ case S_STRING:
+ fputs(" string\n", out);
+ break;
+ case S_INT:
+ fputs(" integer\n", out);
+ break;
+ case S_HEX:
+ fputs(" hex\n", out);
+ break;
+ default:
+ fputs(" ???\n", out);
+ break;
+ }
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ switch (prop->type) {
+ case P_PROMPT:
+ fputs(" prompt ", out);
+ print_quoted_string(out, prop->text);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_DEFAULT:
+ fputs( " default ", out);
+ expr_fprint(prop->expr, out);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_CHOICE:
+ fputs(" #choice value\n", out);
+ break;
+ case P_SELECT:
+ fputs( " select ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_RANGE:
+ fputs( " range ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_MENU:
+ fputs( " menu ", out);
+ print_quoted_string(out, prop->text);
+ fputc('\n', out);
+ break;
+ default:
+ fprintf(out, " unknown prop %d!\n", prop->type);
+ break;
+ }
+ }
+ if (menu->help) {
+ int len = strlen(menu->help);
+ while (menu->help[--len] == '\n')
+ menu->help[len] = 0;
+ fprintf(out, " help\n%s\n", menu->help);
+ }
+}
+
+void zconfdump(FILE *out)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct menu *menu;
+
+ menu = rootmenu.list;
+ while (menu) {
+ if ((sym = menu->sym))
+ print_symbol(out, menu);
+ else if ((prop = menu->prompt)) {
+ switch (prop->type) {
+ case P_COMMENT:
+ fputs("\ncomment ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ case P_MENU:
+ fputs("\nmenu ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ default:
+ ;
+ }
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" depends ", out);
+ expr_fprint(prop->visible.expr, out);
+ fputc('\n', out);
+ }
+ }
+
+ if (menu->list)
+ menu = menu->list;
+ else if (menu->next)
+ menu = menu->next;
+ else while ((menu = menu->parent)) {
+ if (menu->prompt && menu->prompt->type == P_MENU)
+ fputs("\nendmenu\n", out);
+ if (menu->next) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+}
+
+#include "zconf.lex.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
+
diff --git a/roms/seabios/scripts/kconfig/zconf.y b/roms/seabios/scripts/kconfig/zconf.y
new file mode 100644
index 00000000..0f683cfa
--- /dev/null
+++ b/roms/seabios/scripts/kconfig/zconf.y
@@ -0,0 +1,733 @@
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "lkc.h"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD 0x0001
+#define DEBUG_PARSE 0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
+
+static struct menu *current_menu, *current_entry;
+
+%}
+%expect 30
+
+%union
+{
+ char *string;
+ struct file *file;
+ struct symbol *symbol;
+ struct expr *expr;
+ struct menu *menu;
+ const struct kconf_id *id;
+}
+
+%token <id>T_MAINMENU
+%token <id>T_MENU
+%token <id>T_ENDMENU
+%token <id>T_SOURCE
+%token <id>T_CHOICE
+%token <id>T_ENDCHOICE
+%token <id>T_COMMENT
+%token <id>T_CONFIG
+%token <id>T_MENUCONFIG
+%token <id>T_HELP
+%token <string> T_HELPTEXT
+%token <id>T_IF
+%token <id>T_ENDIF
+%token <id>T_DEPENDS
+%token <id>T_OPTIONAL
+%token <id>T_PROMPT
+%token <id>T_TYPE
+%token <id>T_DEFAULT
+%token <id>T_SELECT
+%token <id>T_RANGE
+%token <id>T_VISIBLE
+%token <id>T_OPTION
+%token <id>T_ON
+%token <string> T_WORD
+%token <string> T_WORD_QUOTE
+%token T_UNEQUAL
+%token T_CLOSE_PAREN
+%token T_OPEN_PAREN
+%token T_EOL
+
+%left T_OR
+%left T_AND
+%left T_EQUAL T_UNEQUAL
+%nonassoc T_NOT
+
+%type <string> prompt
+%type <symbol> symbol
+%type <expr> expr
+%type <expr> if_expr
+%type <id> end
+%type <id> option_name
+%type <menu> if_entry menu_entry choice_entry
+%type <string> symbol_option_arg word_opt
+
+%destructor {
+ fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+ $$->file->name, $$->lineno);
+ if (current_menu == $$)
+ menu_end_menu();
+} if_entry menu_entry choice_entry
+
+%{
+/* Include zconf.hash.c here so it can see the token constants. */
+#include "zconf.hash.c"
+%}
+
+%%
+input: nl start | start;
+
+start: mainmenu_stmt stmt_list | stmt_list;
+
+stmt_list:
+ /* empty */
+ | stmt_list common_stmt
+ | stmt_list choice_stmt
+ | stmt_list menu_stmt
+ | stmt_list end { zconf_error("unexpected end statement"); }
+ | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); }
+ | stmt_list option_name error T_EOL
+{
+ zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
+}
+ | stmt_list error T_EOL { zconf_error("invalid statement"); }
+;
+
+option_name:
+ T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE
+;
+
+common_stmt:
+ T_EOL
+ | if_stmt
+ | comment_stmt
+ | config_stmt
+ | menuconfig_stmt
+ | source_stmt
+;
+
+option_error:
+ T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); }
+ | error T_EOL { zconf_error("invalid option"); }
+;
+
+
+/* config/menuconfig entry */
+
+config_entry_start: T_CONFIG T_WORD T_EOL
+{
+ struct symbol *sym = sym_lookup($2, 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+config_stmt: config_entry_start config_option_list
+{
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
+{
+ struct symbol *sym = sym_lookup($2, 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+menuconfig_stmt: menuconfig_entry_start config_option_list
+{
+ if (current_entry->prompt)
+ current_entry->prompt->type = P_MENU;
+ else
+ zconfprint("warning: menuconfig statement without prompt");
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+config_option_list:
+ /* empty */
+ | config_option_list config_option
+ | config_option_list symbol_option
+ | config_option_list depends
+ | config_option_list help
+ | config_option_list option_error
+ | config_option_list T_EOL
+;
+
+config_option: T_TYPE prompt_stmt_opt T_EOL
+{
+ menu_set_type($1->stype);
+ printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ $1->stype);
+};
+
+config_option: T_PROMPT prompt if_expr T_EOL
+{
+ menu_add_prompt(P_PROMPT, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_DEFAULT expr if_expr T_EOL
+{
+ menu_add_expr(P_DEFAULT, $2, $3);
+ if ($1->stype != S_UNKNOWN)
+ menu_set_type($1->stype);
+ printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ $1->stype);
+};
+
+config_option: T_SELECT T_WORD if_expr T_EOL
+{
+ menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
+ printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_RANGE symbol symbol if_expr T_EOL
+{
+ menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
+ printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+};
+
+symbol_option: T_OPTION symbol_option_list T_EOL
+;
+
+symbol_option_list:
+ /* empty */
+ | symbol_option_list T_WORD symbol_option_arg
+{
+ const struct kconf_id *id = kconf_id_lookup($2, strlen($2));
+ if (id && id->flags & TF_OPTION)
+ menu_add_option(id->token, $3);
+ else
+ zconfprint("warning: ignoring unknown option %s", $2);
+ free($2);
+};
+
+symbol_option_arg:
+ /* empty */ { $$ = NULL; }
+ | T_EQUAL prompt { $$ = $2; }
+;
+
+/* choice entry */
+
+choice: T_CHOICE word_opt T_EOL
+{
+ struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
+ sym->flags |= SYMBOL_AUTO;
+ menu_add_entry(sym);
+ menu_add_expr(P_CHOICE, NULL, NULL);
+ printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+};
+
+choice_entry: choice choice_option_list
+{
+ $$ = menu_add_menu();
+};
+
+choice_end: end
+{
+ if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+ }
+};
+
+choice_stmt: choice_entry choice_block choice_end
+;
+
+choice_option_list:
+ /* empty */
+ | choice_option_list choice_option
+ | choice_option_list depends
+ | choice_option_list help
+ | choice_option_list T_EOL
+ | choice_option_list option_error
+;
+
+choice_option: T_PROMPT prompt if_expr T_EOL
+{
+ menu_add_prompt(P_PROMPT, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_TYPE prompt_stmt_opt T_EOL
+{
+ if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
+ menu_set_type($1->stype);
+ printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ $1->stype);
+ } else
+ YYERROR;
+};
+
+choice_option: T_OPTIONAL T_EOL
+{
+ current_entry->sym->flags |= SYMBOL_OPTIONAL;
+ printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_DEFAULT T_WORD if_expr T_EOL
+{
+ if ($1->stype == S_UNKNOWN) {
+ menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
+ printd(DEBUG_PARSE, "%s:%d:default\n",
+ zconf_curname(), zconf_lineno());
+ } else
+ YYERROR;
+};
+
+choice_block:
+ /* empty */
+ | choice_block common_stmt
+;
+
+/* if entry */
+
+if_entry: T_IF expr nl
+{
+ printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+ menu_add_entry(NULL);
+ menu_add_dep($2);
+ $$ = menu_add_menu();
+};
+
+if_end: end
+{
+ if (zconf_endtoken($1, T_IF, T_ENDIF)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+ }
+};
+
+if_stmt: if_entry if_block if_end
+;
+
+if_block:
+ /* empty */
+ | if_block common_stmt
+ | if_block menu_stmt
+ | if_block choice_stmt
+;
+
+/* mainmenu entry */
+
+mainmenu_stmt: T_MAINMENU prompt nl
+{
+ menu_add_prompt(P_MENU, $2, NULL);
+};
+
+/* menu entry */
+
+menu: T_MENU prompt T_EOL
+{
+ menu_add_entry(NULL);
+ menu_add_prompt(P_MENU, $2, NULL);
+ printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+};
+
+menu_entry: menu visibility_list depends_list
+{
+ $$ = menu_add_menu();
+};
+
+menu_end: end
+{
+ if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+ }
+};
+
+menu_stmt: menu_entry menu_block menu_end
+;
+
+menu_block:
+ /* empty */
+ | menu_block common_stmt
+ | menu_block menu_stmt
+ | menu_block choice_stmt
+;
+
+source_stmt: T_SOURCE prompt T_EOL
+{
+ printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
+ zconf_nextfile($2);
+};
+
+/* comment entry */
+
+comment: T_COMMENT prompt T_EOL
+{
+ menu_add_entry(NULL);
+ menu_add_prompt(P_COMMENT, $2, NULL);
+ printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+};
+
+comment_stmt: comment depends_list
+{
+ menu_end_entry();
+};
+
+/* help option */
+
+help_start: T_HELP T_EOL
+{
+ printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+ zconf_starthelp();
+};
+
+help: help_start T_HELPTEXT
+{
+ current_entry->help = $2;
+};
+
+/* depends option */
+
+depends_list:
+ /* empty */
+ | depends_list depends
+ | depends_list T_EOL
+ | depends_list option_error
+;
+
+depends: T_DEPENDS T_ON expr T_EOL
+{
+ menu_add_dep($3);
+ printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+};
+
+/* visibility option */
+
+visibility_list:
+ /* empty */
+ | visibility_list visible
+ | visibility_list T_EOL
+;
+
+visible: T_VISIBLE if_expr
+{
+ menu_add_visibility($2);
+};
+
+/* prompt statement */
+
+prompt_stmt_opt:
+ /* empty */
+ | prompt if_expr
+{
+ menu_add_prompt(P_PROMPT, $1, $2);
+};
+
+prompt: T_WORD
+ | T_WORD_QUOTE
+;
+
+end: T_ENDMENU T_EOL { $$ = $1; }
+ | T_ENDCHOICE T_EOL { $$ = $1; }
+ | T_ENDIF T_EOL { $$ = $1; }
+;
+
+nl:
+ T_EOL
+ | nl T_EOL
+;
+
+if_expr: /* empty */ { $$ = NULL; }
+ | T_IF expr { $$ = $2; }
+;
+
+expr: symbol { $$ = expr_alloc_symbol($1); }
+ | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
+ | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
+ | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; }
+ | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); }
+ | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); }
+ | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); }
+;
+
+symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); }
+ | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
+;
+
+word_opt: /* empty */ { $$ = NULL; }
+ | T_WORD
+
+%%
+
+void conf_parse(const char *name)
+{
+ struct symbol *sym;
+ int i;
+
+ zconf_initscan(name);
+
+ sym_init();
+ _menu_init();
+ rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
+
+ if (getenv("ZCONF_DEBUG"))
+ zconfdebug = 1;
+ zconfparse();
+ if (zconfnerrs)
+ exit(1);
+ if (!modules_sym)
+ modules_sym = sym_find( "n" );
+
+ rootmenu.prompt->text = _(rootmenu.prompt->text);
+ rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
+
+ menu_finalize(&rootmenu);
+ for_all_symbols(i, sym) {
+ if (sym_check_deps(sym))
+ zconfnerrs++;
+ }
+ if (zconfnerrs)
+ exit(1);
+ sym_set_change_count(1);
+}
+
+static const char *zconf_tokenname(int token)
+{
+ switch (token) {
+ case T_MENU: return "menu";
+ case T_ENDMENU: return "endmenu";
+ case T_CHOICE: return "choice";
+ case T_ENDCHOICE: return "endchoice";
+ case T_IF: return "if";
+ case T_ENDIF: return "endif";
+ case T_DEPENDS: return "depends";
+ case T_VISIBLE: return "visible";
+ }
+ return "<token>";
+}
+
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken)
+{
+ if (id->token != endtoken) {
+ zconf_error("unexpected '%s' within %s block",
+ kconf_id_strings + id->name, zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ if (current_menu->file != current_file) {
+ zconf_error("'%s' in different file than '%s'",
+ kconf_id_strings + id->name, zconf_tokenname(starttoken));
+ fprintf(stderr, "%s:%d: location of the '%s'\n",
+ current_menu->file->name, current_menu->lineno,
+ zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+ va_list ap;
+
+ zconfnerrs++;
+ fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+ fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+}
+
+static void print_quoted_string(FILE *out, const char *str)
+{
+ const char *p;
+ int len;
+
+ putc('"', out);
+ while ((p = strchr(str, '"'))) {
+ len = p - str;
+ if (len)
+ fprintf(out, "%.*s", len, str);
+ fputs("\\\"", out);
+ str = p + 1;
+ }
+ fputs(str, out);
+ putc('"', out);
+}
+
+static void print_symbol(FILE *out, struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ struct property *prop;
+
+ if (sym_is_choice(sym))
+ fprintf(out, "\nchoice\n");
+ else
+ fprintf(out, "\nconfig %s\n", sym->name);
+ switch (sym->type) {
+ case S_BOOLEAN:
+ fputs(" boolean\n", out);
+ break;
+ case S_TRISTATE:
+ fputs(" tristate\n", out);
+ break;
+ case S_STRING:
+ fputs(" string\n", out);
+ break;
+ case S_INT:
+ fputs(" integer\n", out);
+ break;
+ case S_HEX:
+ fputs(" hex\n", out);
+ break;
+ default:
+ fputs(" ???\n", out);
+ break;
+ }
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ switch (prop->type) {
+ case P_PROMPT:
+ fputs(" prompt ", out);
+ print_quoted_string(out, prop->text);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_DEFAULT:
+ fputs( " default ", out);
+ expr_fprint(prop->expr, out);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_CHOICE:
+ fputs(" #choice value\n", out);
+ break;
+ case P_SELECT:
+ fputs( " select ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_RANGE:
+ fputs( " range ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_MENU:
+ fputs( " menu ", out);
+ print_quoted_string(out, prop->text);
+ fputc('\n', out);
+ break;
+ default:
+ fprintf(out, " unknown prop %d!\n", prop->type);
+ break;
+ }
+ }
+ if (menu->help) {
+ int len = strlen(menu->help);
+ while (menu->help[--len] == '\n')
+ menu->help[len] = 0;
+ fprintf(out, " help\n%s\n", menu->help);
+ }
+}
+
+void zconfdump(FILE *out)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct menu *menu;
+
+ menu = rootmenu.list;
+ while (menu) {
+ if ((sym = menu->sym))
+ print_symbol(out, menu);
+ else if ((prop = menu->prompt)) {
+ switch (prop->type) {
+ case P_COMMENT:
+ fputs("\ncomment ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ case P_MENU:
+ fputs("\nmenu ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ default:
+ ;
+ }
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" depends ", out);
+ expr_fprint(prop->visible.expr, out);
+ fputc('\n', out);
+ }
+ }
+
+ if (menu->list)
+ menu = menu->list;
+ else if (menu->next)
+ menu = menu->next;
+ else while ((menu = menu->parent)) {
+ if (menu->prompt && menu->prompt->type == P_MENU)
+ fputs("\nendmenu\n", out);
+ if (menu->next) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+}
+
+#include "zconf.lex.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
diff --git a/roms/seabios/scripts/layoutrom.py b/roms/seabios/scripts/layoutrom.py
new file mode 100755
index 00000000..dd770fe4
--- /dev/null
+++ b/roms/seabios/scripts/layoutrom.py
@@ -0,0 +1,691 @@
+#!/usr/bin/env python
+# Script to analyze code and arrange ld sections.
+#
+# Copyright (C) 2008-2014 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import operator
+import sys
+
+# LD script headers/trailers
+COMMONHEADER = """
+/* DO NOT EDIT! This is an autogenerated file. See scripts/layoutrom.py. */
+OUTPUT_FORMAT("elf32-i386")
+OUTPUT_ARCH("i386")
+SECTIONS
+{
+"""
+COMMONTRAILER = """
+
+ /* Discard regular data sections to force a link error if
+ * code attempts to access data not marked with VAR16 (or other
+ * appropriate macro)
+ */
+ /DISCARD/ : {
+ *(.text*) *(.data*) *(.bss*) *(.rodata*)
+ *(COMMON) *(.discard*) *(.eh_frame) *(.note*)
+ }
+}
+"""
+
+
+######################################################################
+# Determine section locations
+######################################################################
+
+# Align 'pos' to 'alignbytes' offset
+def alignpos(pos, alignbytes):
+ mask = alignbytes - 1
+ return (pos + mask) & ~mask
+
+# Determine the final addresses for a list of sections that end at an
+# address.
+def setSectionsStart(sections, endaddr, minalign=1, segoffset=0):
+ totspace = 0
+ for section in sections:
+ if section.align > minalign:
+ minalign = section.align
+ totspace = alignpos(totspace, section.align) + section.size
+ startaddr = int((endaddr - totspace) / minalign) * minalign
+ curaddr = startaddr
+ for section in sections:
+ curaddr = alignpos(curaddr, section.align)
+ section.finalloc = curaddr
+ section.finalsegloc = curaddr - segoffset
+ curaddr += section.size
+ return startaddr, minalign
+
+# The 16bit code can't exceed 64K of space.
+BUILD_BIOS_ADDR = 0xf0000
+BUILD_BIOS_SIZE = 0x10000
+BUILD_ROM_START = 0xc0000
+BUILD_LOWRAM_END = 0xa0000
+# Space to reserve in f-segment for dynamic allocations
+BUILD_MIN_BIOSTABLE = 2048
+
+# Layout the 16bit code. This ensures sections with fixed offset
+# requirements are placed in the correct location. It also places the
+# 16bit code as high as possible in the f-segment.
+def fitSections(sections, fillsections):
+ # fixedsections = [(addr, section), ...]
+ fixedsections = []
+ for section in sections:
+ if section.name.startswith('.fixedaddr.'):
+ addr = int(section.name[11:], 16)
+ section.finalloc = addr + BUILD_BIOS_ADDR
+ section.finalsegloc = addr
+ fixedsections.append((addr, section))
+ if section.align != 1:
+ print("Error: Fixed section %s has non-zero alignment (%d)" % (
+ section.name, section.align))
+ sys.exit(1)
+ fixedsections.sort(key=operator.itemgetter(0))
+ firstfixed = fixedsections[0][0]
+
+ # Find freespace in fixed address area
+ # fixedAddr = [(freespace, section), ...]
+ fixedAddr = []
+ for i in range(len(fixedsections)):
+ fixedsectioninfo = fixedsections[i]
+ addr, section = fixedsectioninfo
+ if i == len(fixedsections) - 1:
+ nextaddr = BUILD_BIOS_SIZE
+ else:
+ nextaddr = fixedsections[i+1][0]
+ avail = nextaddr - addr - section.size
+ fixedAddr.append((avail, section))
+ fixedAddr.sort(key=operator.itemgetter(0))
+
+ # Attempt to fit other sections into fixed area
+ canrelocate = [(section.size, section.align, section.name, section)
+ for section in fillsections]
+ canrelocate.sort()
+ canrelocate = [section for size, align, name, section in canrelocate]
+ totalused = 0
+ for freespace, fixedsection in fixedAddr:
+ addpos = fixedsection.finalsegloc + fixedsection.size
+ totalused += fixedsection.size
+ nextfixedaddr = addpos + freespace
+# print("Filling section %x uses %d, next=%x, available=%d" % (
+# fixedsection.finalloc, fixedsection.size, nextfixedaddr, freespace))
+ while 1:
+ canfit = None
+ for fitsection in canrelocate:
+ if addpos + fitsection.size > nextfixedaddr:
+ # Can't fit and nothing else will fit.
+ break
+ fitnextaddr = alignpos(addpos, fitsection.align) + fitsection.size
+# print("Test %s - %x vs %x" % (
+# fitsection.name, fitnextaddr, nextfixedaddr))
+ if fitnextaddr > nextfixedaddr:
+ # This item can't fit.
+ continue
+ canfit = (fitnextaddr, fitsection)
+ if canfit is None:
+ break
+ # Found a section that can fit.
+ fitnextaddr, fitsection = canfit
+ canrelocate.remove(fitsection)
+ fitsection.finalloc = addpos + BUILD_BIOS_ADDR
+ fitsection.finalsegloc = addpos
+ addpos = fitnextaddr
+ totalused += fitsection.size
+# print(" Adding %s (size %d align %d) pos=%x avail=%d" % (
+# fitsection[2], fitsection[0], fitsection[1]
+# , fitnextaddr, nextfixedaddr - fitnextaddr))
+
+ # Report stats
+ total = BUILD_BIOS_SIZE-firstfixed
+ slack = total - totalused
+ print ("Fixed space: 0x%x-0x%x total: %d slack: %d"
+ " Percent slack: %.1f%%" % (
+ firstfixed, BUILD_BIOS_SIZE, total, slack,
+ (float(slack) / total) * 100.0))
+
+ return firstfixed + BUILD_BIOS_ADDR
+
+# Return the subset of sections with a given category
+def getSectionsCategory(sections, category):
+ return [section for section in sections if section.category == category]
+
+# Return the subset of sections with a given fileid
+def getSectionsFileid(sections, fileid):
+ return [section for section in sections if section.fileid == fileid]
+
+# Return the subset of sections with a given name prefix
+def getSectionsPrefix(sections, prefix):
+ return [section for section in sections
+ if section.name.startswith(prefix)]
+
+# The sections (and associated information) to be placed in output rom
+class LayoutInfo:
+ sections = None
+ genreloc = None
+ sec32init_start = sec32init_end = sec32init_align = None
+ sec32low_start = sec32low_end = None
+ zonelow_base = final_sec32low_start = None
+ zonefseg_start = zonefseg_end = None
+ final_readonly_start = None
+ varlowsyms = entrysym = None
+
+# Determine final memory addresses for sections
+def doLayout(sections, config, genreloc):
+ li = LayoutInfo()
+ li.sections = sections
+ li.genreloc = genreloc
+ # Determine 16bit positions
+ sections16 = getSectionsCategory(sections, '16')
+ textsections = getSectionsPrefix(sections16, '.text.')
+ rodatasections = getSectionsPrefix(sections16, '.rodata')
+ datasections = getSectionsPrefix(sections16, '.data16.')
+ fixedsections = getSectionsCategory(sections, 'fixed')
+
+ firstfixed = fitSections(fixedsections, textsections)
+ remsections = [s for s in textsections+rodatasections+datasections
+ if s.finalloc is None]
+ sec16_start, sec16_align = setSectionsStart(
+ remsections, firstfixed, segoffset=BUILD_BIOS_ADDR)
+
+ # Determine 32seg positions
+ sections32seg = getSectionsCategory(sections, '32seg')
+ textsections = getSectionsPrefix(sections32seg, '.text.')
+ rodatasections = getSectionsPrefix(sections32seg, '.rodata')
+ datasections = getSectionsPrefix(sections32seg, '.data32seg.')
+
+ sec32seg_start, sec32seg_align = setSectionsStart(
+ textsections + rodatasections + datasections, sec16_start
+ , segoffset=BUILD_BIOS_ADDR)
+
+ # Determine 32bit "fseg memory" data positions
+ sections32textfseg = getSectionsCategory(sections, '32textfseg')
+ sec32textfseg_start, sec32textfseg_align = setSectionsStart(
+ sections32textfseg, sec32seg_start, 16)
+
+ sections32fseg = getSectionsCategory(sections, '32fseg')
+ sec32fseg_start, sec32fseg_align = setSectionsStart(
+ sections32fseg, sec32textfseg_start, 16
+ , segoffset=BUILD_BIOS_ADDR)
+
+ # Determine 32flat runtime positions
+ sections32flat = getSectionsCategory(sections, '32flat')
+ textsections = getSectionsPrefix(sections32flat, '.text.')
+ rodatasections = getSectionsPrefix(sections32flat, '.rodata')
+ datasections = getSectionsPrefix(sections32flat, '.data.')
+ bsssections = getSectionsPrefix(sections32flat, '.bss.')
+
+ sec32flat_start, sec32flat_align = setSectionsStart(
+ textsections + rodatasections + datasections + bsssections
+ , sec32fseg_start, 16)
+
+ # Determine 32flat init positions
+ sections32init = getSectionsCategory(sections, '32init')
+ init32_textsections = getSectionsPrefix(sections32init, '.text.')
+ init32_rodatasections = getSectionsPrefix(sections32init, '.rodata')
+ init32_datasections = getSectionsPrefix(sections32init, '.data.')
+ init32_bsssections = getSectionsPrefix(sections32init, '.bss.')
+
+ sec32init_start, sec32init_align = setSectionsStart(
+ init32_textsections + init32_rodatasections
+ + init32_datasections + init32_bsssections
+ , sec32flat_start, 16)
+
+ # Determine location of ZoneFSeg memory.
+ zonefseg_end = sec32flat_start
+ if not genreloc:
+ zonefseg_end = sec32init_start
+ zonefseg_start = BUILD_BIOS_ADDR
+ if zonefseg_start + BUILD_MIN_BIOSTABLE > zonefseg_end:
+ # Not enough ZoneFSeg space - force a minimum space.
+ zonefseg_end = sec32fseg_start
+ zonefseg_start = zonefseg_end - BUILD_MIN_BIOSTABLE
+ sec32flat_start, sec32flat_align = setSectionsStart(
+ textsections + rodatasections + datasections + bsssections
+ , zonefseg_start, 16)
+ sec32init_start, sec32init_align = setSectionsStart(
+ init32_textsections + init32_rodatasections
+ + init32_datasections + init32_bsssections
+ , sec32flat_start, 16)
+ li.sec32init_start = sec32init_start
+ li.sec32init_end = sec32flat_start
+ li.sec32init_align = sec32init_align
+ final_readonly_start = min(BUILD_BIOS_ADDR, sec32flat_start)
+ if not genreloc:
+ final_readonly_start = min(BUILD_BIOS_ADDR, sec32init_start)
+ li.zonefseg_start = zonefseg_start
+ li.zonefseg_end = zonefseg_end
+ li.final_readonly_start = final_readonly_start
+
+ # Determine "low memory" data positions
+ sections32low = getSectionsCategory(sections, '32low')
+ sec32low_end = sec32init_start
+ if config.get('CONFIG_MALLOC_UPPERMEMORY'):
+ final_sec32low_end = final_readonly_start
+ zonelow_base = final_sec32low_end - 64*1024
+ zonelow_base = max(BUILD_ROM_START, alignpos(zonelow_base, 2*1024))
+ else:
+ final_sec32low_end = BUILD_LOWRAM_END
+ zonelow_base = final_sec32low_end - 64*1024
+ relocdelta = final_sec32low_end - sec32low_end
+ li.sec32low_start, li.sec32low_align = setSectionsStart(
+ sections32low, sec32low_end, 16
+ , segoffset=zonelow_base - relocdelta)
+ li.sec32low_end = sec32low_end
+ li.zonelow_base = zonelow_base
+ li.final_sec32low_start = li.sec32low_start + relocdelta
+
+ # Print statistics
+ size16 = BUILD_BIOS_ADDR + BUILD_BIOS_SIZE - sec16_start
+ size32seg = sec16_start - sec32seg_start
+ size32textfseg = sec32seg_start - sec32textfseg_start
+ size32fseg = sec32textfseg_start - sec32fseg_start
+ size32flat = sec32fseg_start - sec32flat_start
+ size32init = sec32flat_start - sec32init_start
+ sizelow = li.sec32low_end - li.sec32low_start
+ print("16bit size: %d" % size16)
+ print("32bit segmented size: %d" % size32seg)
+ print("32bit flat size: %d" % (size32flat + size32textfseg))
+ print("32bit flat init size: %d" % size32init)
+ print("Lowmem size: %d" % sizelow)
+ print("f-segment var size: %d" % size32fseg)
+ return li
+
+
+######################################################################
+# Linker script output
+######################################################################
+
+# Write LD script includes for the given cross references
+def outXRefs(sections, useseg=0, exportsyms=[], forcedelta=0):
+ xrefs = dict([(symbol.name, symbol) for symbol in exportsyms])
+ out = ""
+ for section in sections:
+ for reloc in section.relocs:
+ symbol = reloc.symbol
+ if (symbol.section is not None
+ and (symbol.section.fileid != section.fileid
+ or symbol.name != reloc.symbolname)):
+ xrefs[reloc.symbolname] = symbol
+ for symbolname, symbol in xrefs.items():
+ loc = symbol.section.finalloc
+ if useseg:
+ loc = symbol.section.finalsegloc
+ out += "%s = 0x%x ;\n" % (symbolname, loc + forcedelta + symbol.offset)
+ return out
+
+# Write LD script includes for the given sections
+def outSections(sections, useseg=0):
+ out = ""
+ for section in sections:
+ loc = section.finalloc
+ if useseg:
+ loc = section.finalsegloc
+ out += "%s 0x%x : { *(%s) }\n" % (section.name, loc, section.name)
+ return out
+
+# Write LD script includes for the given sections using relative offsets
+def outRelSections(sections, startsym, useseg=0):
+ sections = [(section.finalloc, section) for section in sections
+ if section.finalloc is not None]
+ sections.sort(key=operator.itemgetter(0))
+ out = ""
+ for addr, section in sections:
+ loc = section.finalloc
+ if useseg:
+ loc = section.finalsegloc
+ out += ". = ( 0x%x - %s ) ;\n" % (loc, startsym)
+ if section.name in ('.rodata.str1.1', '.rodata'):
+ out += "_rodata%s = . ;\n" % (section.fileid,)
+ out += "*%s.*(%s)\n" % (section.fileid, section.name)
+ return out
+
+# Build linker script output for a list of relocations.
+def strRelocs(outname, outrel, relocs):
+ relocs.sort()
+ return (" %s_start = ABSOLUTE(.) ;\n" % (outname,)
+ + "".join(["LONG(0x%x - %s)\n" % (pos, outrel)
+ for pos in relocs])
+ + " %s_end = ABSOLUTE(.) ;\n" % (outname,))
+
+# Find relocations to the given sections
+def getRelocs(sections, tosection, type=None):
+ return [section.finalloc + reloc.offset
+ for section in sections
+ for reloc in section.relocs
+ if (reloc.symbol.section in tosection
+ and (type is None or reloc.type == type))]
+
+# Output the linker scripts for all required sections.
+def writeLinkerScripts(li, out16, out32seg, out32flat):
+ # Write 16bit linker script
+ filesections16 = getSectionsFileid(li.sections, '16')
+ out = outXRefs(filesections16, useseg=1) + """
+ zonelow_base = 0x%x ;
+ _zonelow_seg = 0x%x ;
+
+%s
+""" % (li.zonelow_base,
+ int(li.zonelow_base / 16),
+ outSections(filesections16, useseg=1))
+ outfile = open(out16, 'w')
+ outfile.write(COMMONHEADER + out + COMMONTRAILER)
+ outfile.close()
+
+ # Write 32seg linker script
+ filesections32seg = getSectionsFileid(li.sections, '32seg')
+ out = (outXRefs(filesections32seg, useseg=1)
+ + outSections(filesections32seg, useseg=1))
+ outfile = open(out32seg, 'w')
+ outfile.write(COMMONHEADER + out + COMMONTRAILER)
+ outfile.close()
+
+ # Write 32flat linker script
+ sec32all_start = li.sec32low_start
+ relocstr = ""
+ if li.genreloc:
+ # Generate relocations
+ initsections = dict([
+ (s, 1) for s in getSectionsCategory(li.sections, '32init')])
+ noninitsections = dict([(s, 1) for s in li.sections
+ if s not in initsections])
+ absrelocs = getRelocs(initsections, initsections, type='R_386_32')
+ relrelocs = getRelocs(initsections, noninitsections, type='R_386_PC32')
+ initrelocs = getRelocs(noninitsections, initsections)
+ relocstr = (strRelocs("_reloc_abs", "code32init_start", absrelocs)
+ + strRelocs("_reloc_rel", "code32init_start", relrelocs)
+ + strRelocs("_reloc_init", "code32flat_start", initrelocs))
+ numrelocs = len(absrelocs + relrelocs + initrelocs)
+ sec32all_start -= numrelocs * 4
+ filesections32flat = getSectionsFileid(li.sections, '32flat')
+ out = outXRefs([], exportsyms=li.varlowsyms
+ , forcedelta=li.final_sec32low_start-li.sec32low_start)
+ out += outXRefs(filesections32flat, exportsyms=[li.entrysym]) + """
+ _reloc_min_align = 0x%x ;
+ zonefseg_start = 0x%x ;
+ zonefseg_end = 0x%x ;
+ zonelow_base = 0x%x ;
+ final_varlow_start = 0x%x ;
+ final_readonly_start = 0x%x ;
+ varlow_start = 0x%x ;
+ varlow_end = 0x%x ;
+ code32init_start = 0x%x ;
+ code32init_end = 0x%x ;
+
+ code32flat_start = 0x%x ;
+ .text code32flat_start : {
+%s
+%s
+ code32flat_end = ABSOLUTE(.) ;
+ } :text
+""" % (li.sec32init_align,
+ li.zonefseg_start,
+ li.zonefseg_end,
+ li.zonelow_base,
+ li.final_sec32low_start,
+ li.final_readonly_start,
+ li.sec32low_start,
+ li.sec32low_end,
+ li.sec32init_start,
+ li.sec32init_end,
+ sec32all_start,
+ relocstr,
+ outRelSections(li.sections, 'code32flat_start'))
+ out = COMMONHEADER + out + COMMONTRAILER + """
+ENTRY(%s)
+PHDRS
+{
+ text PT_LOAD AT ( code32flat_start ) ;
+}
+""" % (li.entrysym.name,)
+ outfile = open(out32flat, 'w')
+ outfile.write(out)
+ outfile.close()
+
+
+######################################################################
+# Detection of unused sections and init sections
+######################################################################
+
+# Visit all sections reachable from a given set of start sections
+def findReachable(anchorsections, checkreloc, data):
+ anchorsections = dict([(section, []) for section in anchorsections])
+ pending = list(anchorsections)
+ while pending:
+ section = pending.pop()
+ for reloc in section.relocs:
+ chain = anchorsections[section] + [section.name]
+ if not checkreloc(reloc, section, data, chain):
+ continue
+ nextsection = reloc.symbol.section
+ if nextsection not in anchorsections:
+ anchorsections[nextsection] = chain
+ pending.append(nextsection)
+ return anchorsections
+
+# Find "runtime" sections (ie, not init only sections).
+def checkRuntime(reloc, rsection, data, chain):
+ section = reloc.symbol.section
+ if section is None or '.init.' in section.name:
+ return 0
+ if '.data.varinit.' in section.name:
+ print("ERROR: %s is VARVERIFY32INIT but used from %s" % (
+ section.name, chain))
+ sys.exit(1)
+ return 1
+
+# Find and keep the section associated with a symbol (if available).
+def checkKeepSym(reloc, syms, fileid, isxref):
+ symbolname = reloc.symbolname
+ mustbecfunc = symbolname.startswith('_cfunc')
+ if mustbecfunc:
+ symprefix = '_cfunc' + fileid + '_'
+ if not symbolname.startswith(symprefix):
+ return 0
+ symbolname = symbolname[len(symprefix):]
+ symbol = syms.get(symbolname)
+ if (symbol is None or symbol.section is None
+ or symbol.section.name.startswith('.discard.')):
+ return 0
+ isdestcfunc = (symbol.section.name.startswith('.text.')
+ and not symbol.section.name.startswith('.text.asm.'))
+ if ((mustbecfunc and not isdestcfunc)
+ or (not mustbecfunc and isdestcfunc and isxref)):
+ return 0
+
+ reloc.symbol = symbol
+ return 1
+
+# Resolve a relocation and check if it should be kept in the final binary.
+def checkKeep(reloc, section, symbols, chain):
+ ret = checkKeepSym(reloc, symbols[section.fileid], section.fileid, 0)
+ if ret:
+ return ret
+ # Not in primary sections - it may be a cross 16/32 reference
+ for fileid in ('16', '32seg', '32flat'):
+ if fileid != section.fileid:
+ ret = checkKeepSym(reloc, symbols[fileid], fileid, 1)
+ if ret:
+ return ret
+ return 0
+
+
+######################################################################
+# Startup and input parsing
+######################################################################
+
+class Section:
+ name = size = alignment = fileid = relocs = None
+ finalloc = finalsegloc = category = None
+class Reloc:
+ offset = type = symbolname = symbol = None
+class Symbol:
+ name = offset = section = None
+
+# Read in output from objdump
+def parseObjDump(file, fileid):
+ # sections = [section, ...]
+ sections = []
+ sectionmap = {}
+ # symbols[symbolname] = symbol
+ symbols = {}
+
+ state = None
+ for line in file.readlines():
+ line = line.rstrip()
+ if line == 'Sections:':
+ state = 'section'
+ continue
+ if line == 'SYMBOL TABLE:':
+ state = 'symbol'
+ continue
+ if line.startswith('RELOCATION RECORDS FOR ['):
+ sectionname = line[24:-2]
+ if sectionname.startswith('.debug_'):
+ # Skip debugging sections (to reduce parsing time)
+ state = None
+ continue
+ state = 'reloc'
+ relocsection = sectionmap[sectionname]
+ continue
+
+ if state == 'section':
+ try:
+ idx, name, size, vma, lma, fileoff, align = line.split()
+ if align[:3] != '2**':
+ continue
+ section = Section()
+ section.name = name
+ section.size = int(size, 16)
+ section.align = 2**int(align[3:])
+ section.fileid = fileid
+ section.relocs = []
+ sections.append(section)
+ sectionmap[name] = section
+ except ValueError:
+ pass
+ continue
+ if state == 'symbol':
+ try:
+ parts = line[17:].split()
+ if len(parts) == 3:
+ sectionname, size, name = parts
+ elif len(parts) == 4 and parts[2] == '.hidden':
+ sectionname, size, hidden, name = parts
+ else:
+ continue
+ symbol = Symbol()
+ symbol.size = int(size, 16)
+ symbol.offset = int(line[:8], 16)
+ symbol.name = name
+ symbol.section = sectionmap.get(sectionname)
+ symbols[name] = symbol
+ except ValueError:
+ pass
+ continue
+ if state == 'reloc':
+ try:
+ off, type, symbolname = line.split()
+ reloc = Reloc()
+ reloc.offset = int(off, 16)
+ reloc.type = type
+ reloc.symbolname = symbolname
+ reloc.symbol = symbols.get(symbolname)
+ if reloc.symbol is None:
+ # Some binutils (2.20.1) give section name instead
+ # of a symbol - create a dummy symbol.
+ reloc.symbol = symbol = Symbol()
+ symbol.size = 0
+ symbol.offset = 0
+ symbol.name = symbolname
+ symbol.section = sectionmap.get(symbolname)
+ symbols[symbolname] = symbol
+ relocsection.relocs.append(reloc)
+ except ValueError:
+ pass
+ return sections, symbols
+
+# Parser for constants in simple C header files.
+def scanconfig(file):
+ f = open(file, 'r')
+ opts = {}
+ for l in f.readlines():
+ parts = l.split()
+ if len(parts) != 3:
+ continue
+ if parts[0] != '#define':
+ continue
+ value = parts[2]
+ if value.isdigit() or (value.startswith('0x') and value[2:].isdigit()):
+ value = int(value, 0)
+ opts[parts[1]] = value
+ return opts
+
+def main():
+ # Get output name
+ in16, in32seg, in32flat, cfgfile, out16, out32seg, out32flat = sys.argv[1:]
+
+ # Read in the objdump information
+ infile16 = open(in16, 'r')
+ infile32seg = open(in32seg, 'r')
+ infile32flat = open(in32flat, 'r')
+
+ # infoX = (sections, symbols)
+ info16 = parseObjDump(infile16, '16')
+ info32seg = parseObjDump(infile32seg, '32seg')
+ info32flat = parseObjDump(infile32flat, '32flat')
+
+ # Read kconfig config file
+ config = scanconfig(cfgfile)
+
+ # Figure out which sections to keep.
+ allsections = info16[0] + info32seg[0] + info32flat[0]
+ symbols = {'16': info16[1], '32seg': info32seg[1], '32flat': info32flat[1]}
+ if config.get('CONFIG_COREBOOT'):
+ entrysym = symbols['16'].get('entry_elf')
+ elif config.get('CONFIG_CSM'):
+ entrysym = symbols['16'].get('entry_csm')
+ else:
+ entrysym = symbols['16'].get('reset_vector')
+ anchorsections = [entrysym.section] + [
+ section for section in allsections
+ if section.name.startswith('.fixedaddr.')]
+ keepsections = findReachable(anchorsections, checkKeep, symbols)
+ sections = [section for section in allsections if section in keepsections]
+
+ # Separate 32bit flat into runtime, init, and special variable parts
+ anchorsections = [
+ section for section in sections
+ if ('.data.varlow.' in section.name or '.data.varfseg.' in section.name
+ or '.fixedaddr.' in section.name or '.runtime.' in section.name)]
+ runtimesections = findReachable(anchorsections, checkRuntime, None)
+ for section in sections:
+ if section.name.startswith('.data.varlow.'):
+ section.category = '32low'
+ elif section.name.startswith('.data.varfseg.'):
+ section.category = '32fseg'
+ elif section.name.startswith('.text.32fseg.'):
+ section.category = '32textfseg'
+ elif section.name.startswith('.fixedaddr.'):
+ section.category = 'fixed'
+ elif section.fileid == '32flat' and section not in runtimesections:
+ section.category = '32init'
+ else:
+ section.category = section.fileid
+
+ # Determine the final memory locations of each kept section.
+ genreloc = '_reloc_abs_start' in symbols['32flat']
+ li = doLayout(sections, config, genreloc)
+
+ # Exported symbols
+ li.varlowsyms = [symbol for symbol in symbols['32flat'].values()
+ if (symbol.section is not None
+ and symbol.section.finalloc is not None
+ and '.data.varlow.' in symbol.section.name
+ and symbol.name != symbol.section.name)]
+ li.entrysym = entrysym
+
+ # Write out linker script files.
+ writeLinkerScripts(li, out16, out32seg, out32flat)
+
+if __name__ == '__main__':
+ main()
diff --git a/roms/seabios/scripts/python23compat.py b/roms/seabios/scripts/python23compat.py
new file mode 100644
index 00000000..572b7f18
--- /dev/null
+++ b/roms/seabios/scripts/python23compat.py
@@ -0,0 +1,14 @@
+# Helper code for compatibility of the code with both Python 2 and Python 3
+#
+# Copyright (C) 2014 Johannes Krampf <johannes.krampf@googlemail.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+
+if (sys.version_info > (3, 0)):
+ def as_bytes(str):
+ return bytes(str, "ASCII")
+else:
+ def as_bytes(str):
+ return str
diff --git a/roms/seabios/scripts/readserial.py b/roms/seabios/scripts/readserial.py
new file mode 100755
index 00000000..a7383e83
--- /dev/null
+++ b/roms/seabios/scripts/readserial.py
@@ -0,0 +1,190 @@
+#!/usr/bin/env python
+# Script that can read from a serial device and show timestamps.
+#
+# Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Usage:
+# scripts/readserial.py /dev/ttyUSB0 115200
+
+import sys, os, time, select, optparse
+
+from python23compat import as_bytes
+
+# Reset time counter after this much idle time.
+RESTARTINTERVAL = 60
+# Number of bits in a transmitted byte - 8N1 is 1 start bit + 8 data
+# bits + 1 stop bit.
+BITSPERBYTE = 10
+
+def calibrateserialwrite(outfile, byteadjust):
+ # Build 4000 bytes of dummy data.
+ data = "0123456789" * 4 + "012345678" + "\n"
+ data = data * 80
+ while 1:
+ st = time.time()
+ outfile.write(as_bytes(data))
+ outfile.flush()
+ et = time.time()
+ sys.stdout.write(
+ "Wrote %d - %.1fus per char (theory states %.1fus)\n" % (
+ len(data), (et-st) / len(data) * 1000000, byteadjust * 1000000))
+ sys.stdout.flush()
+ time.sleep(3)
+
+def calibrateserialread(infile, byteadjust):
+ starttime = lasttime = 0
+ totalchars = 0
+ while 1:
+ select.select([infile], [], [])
+ d = infile.read(4096)
+ curtime = time.time()
+ if curtime - lasttime > 1.0:
+ if starttime and totalchars:
+ sys.stdout.write(
+ "Calibrating on %d bytes - %.1fus per char"
+ " (theory states %.1fus)\n" % (
+ totalchars,
+ float(lasttime - starttime) * 1000000 / totalchars,
+ byteadjust * 1000000))
+ totalchars = 0
+ starttime = curtime
+ else:
+ totalchars += len(d)
+ lasttime = curtime
+
+def readserial(infile, logfile, byteadjust):
+ lasttime = 0
+ while 1:
+ # Read data
+ try:
+ res = select.select([infile, sys.stdin], [], [])
+ except KeyboardInterrupt:
+ sys.stdout.write("\n")
+ return -1
+ if sys.stdin in res[0]:
+ # Got keyboard input - force reset on next serial input
+ sys.stdin.read(1)
+ lasttime = 0
+ if len(res[0]) == 1:
+ continue
+ d = infile.read(4096)
+ if not d:
+ return 0
+ datatime = time.time()
+
+ datatime -= len(d) * byteadjust
+
+ # Reset start time if no data for some time
+ if datatime - lasttime > RESTARTINTERVAL:
+ starttime = datatime
+ charcount = 0
+ isnewline = 1
+ msg = "\n\n======= %s (adjust=%.1fus)\n" % (
+ time.asctime(time.localtime(datatime)), byteadjust * 1000000)
+ sys.stdout.write(msg)
+ logfile.write(as_bytes(msg))
+ lasttime = datatime
+
+ # Translate unprintable chars; add timestamps
+ out = as_bytes("")
+ for c in d:
+ if isnewline:
+ delta = datatime - starttime - (charcount * byteadjust)
+ out += "%06.3f: " % delta
+ isnewline = 0
+ oc = ord(c)
+ charcount += 1
+ datatime += byteadjust
+ if oc == 0x0d:
+ continue
+ if oc == 0x00:
+ out += "<00>\n"
+ isnewline = 1
+ continue
+ if oc == 0x0a:
+ out += "\n"
+ isnewline = 1
+ continue
+ if oc < 0x20 or oc >= 0x7f and oc != 0x09:
+ out += "<%02x>" % oc
+ continue
+ out += c
+
+ if (sys.version_info > (3, 0)):
+ sys.stdout.buffer.write(out)
+ else:
+ sys.stdout.write(out)
+ sys.stdout.flush()
+ logfile.write(out)
+ logfile.flush()
+
+def main():
+ usage = "%prog [options] [<serialdevice> [<baud>]]"
+ opts = optparse.OptionParser(usage)
+ opts.add_option("-f", "--file",
+ action="store_false", dest="serial", default=True,
+ help="read from unix named pipe instead of serialdevice")
+ opts.add_option("-n", "--no-adjust",
+ action="store_false", dest="adjustbaud", default=True,
+ help="don't adjust times by serial rate")
+ opts.add_option("-c", "--calibrate-read",
+ action="store_true", dest="calibrate_read", default=False,
+ help="read from serial port to calibrate it")
+ opts.add_option("-C", "--calibrate-write",
+ action="store_true", dest="calibrate_write", default=False,
+ help="write to serial port to calibrate it")
+ opts.add_option("-t", "--time",
+ type="float", dest="time", default=None,
+ help="time to write one byte on serial port (in us)")
+ options, args = opts.parse_args()
+ serialport = 0
+ baud = 115200
+ if len(args) > 2:
+ opts.error("Too many arguments")
+ if len(args) > 0:
+ serialport = args[0]
+ if len(args) > 1:
+ baud = int(args[1])
+ byteadjust = float(BITSPERBYTE) / baud
+ if options.time is not None:
+ byteadjust = options.time / 1000000.0
+ if not options.adjustbaud:
+ byteadjust = 0.0
+
+ if options.serial:
+ # Read from serial port
+ try:
+ import serial
+ except ImportError:
+ print("""
+Unable to find pyserial package ( http://pyserial.sourceforge.net/ ).
+On Linux machines try: yum install pyserial
+Or: apt-get install python-serial
+""")
+ sys.exit(1)
+ ser = serial.Serial(serialport, baud, timeout=0)
+
+ if options.calibrate_read:
+ calibrateserialread(ser, byteadjust)
+ return
+ if options.calibrate_write:
+ calibrateserialwrite(ser, byteadjust)
+ return
+
+ logname = time.strftime("seriallog-%Y%m%d_%H%M%S.log")
+ f = open(logname, 'wb')
+ if options.serial:
+ readserial(ser, f, byteadjust)
+ else:
+ # Read from a pipe
+ while 1:
+ ser = os.fdopen(os.open(serialport, os.O_RDONLY|os.O_NONBLOCK), 'rb')
+ res = readserial(ser, f, byteadjust)
+ ser.close()
+ if res < 0:
+ break
+
+if __name__ == '__main__':
+ main()
diff --git a/roms/seabios/scripts/tarball.sh b/roms/seabios/scripts/tarball.sh
new file mode 100755
index 00000000..06d85546
--- /dev/null
+++ b/roms/seabios/scripts/tarball.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# Script to create seabios release and snapshot tarballs.
+# Accepts conmmit (hash, tag, branch, ...) as first argument,
+# uses HEAD if unspecified.
+#
+
+commit="${1-HEAD}"
+
+# figure name for the tarball
+reltag="$(git describe --tags --match 'rel-*' --exact $commit 2>/dev/null)"
+if test "$reltag" != ""; then
+ # release
+ name="${reltag#rel-}"
+else
+ # snapshot
+ reltag="$(git describe --tags --match 'rel-*' $commit 2>/dev/null)"
+ name="snap-${reltag#rel-}"
+fi
+
+# export tarball archive from git
+prefix="seabios-${name}/"
+output="seabios-${name}.tar"
+echo "# commit $commit -> tarball: ${output}.gz"
+rm -f "$output" "${output}.gz"
+git archive --format=tar --prefix="$prefix" "$commit" > "$output"
+
+# add .version file to tarball
+dotver="$(mktemp dotver.XXXXXX)"
+echo "$name" > "$dotver"
+tar --append --file="$output" --owner=root --group=root --mode=0664 \
+ --transform "s:${dotver}:${prefix}.version:" "$dotver"
+rm -f "$dotver"
+
+# finally compress it
+gzip "$output"
diff --git a/roms/seabios/scripts/test-build.sh b/roms/seabios/scripts/test-build.sh
new file mode 100755
index 00000000..081f9fd2
--- /dev/null
+++ b/roms/seabios/scripts/test-build.sh
@@ -0,0 +1,103 @@
+#!/bin/sh
+# Script to test if the build works properly.
+
+# Test IASL is installed.
+$IASL -h > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ echo "The SeaBIOS project requires the 'iasl' package be installed." >&2
+ echo "Many Linux distributions have this package." >&2
+ echo "Try: sudo yum install iasl" >&2
+ echo "Or: sudo apt-get install iasl" >&2
+ echo "" >&2
+ echo "Please install iasl and retry." >&2
+ echo -1
+ exit 0
+fi
+
+mkdir -p ${OUT}
+TMPFILE1=${OUT}/tmp_testcompile1.c
+TMPFILE1o=${OUT}/tmp_testcompile1.o
+TMPFILE1_ld=${OUT}/tmp_testcompile1.lds
+TMPFILE2=${OUT}/tmp_testcompile2.c
+TMPFILE2o=${OUT}/tmp_testcompile2.o
+TMPFILE3o=${OUT}/tmp_testcompile3.o
+
+# Test if ld's alignment handling is correct. This is a known problem
+# with the linker that ships with Ubuntu 11.04.
+cat - > $TMPFILE1 <<EOF
+const char v1[] __attribute__((section(".text.v1"))) = "0123456789";
+const char v2[] __attribute__((section(".text.v2"))) = "0123456789";
+EOF
+cat - > $TMPFILE1_ld <<EOF
+SECTIONS
+{
+ .mysection 0x88f0 : {
+. = 0x10 ;
+*(.text.v1)
+. = 0x20 ;
+*(.text.v2)
+. = 0x30 ;
+ }
+}
+EOF
+$CC -O -g -c $TMPFILE1 -o $TMPFILE1o > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ echo "Unable to execute the C compiler ($CC)." >&2
+ echo "" >&2
+ echo "Please install a working compiler and retry." >&2
+ echo -1
+ exit 0
+fi
+$LD -T $TMPFILE1_ld $TMPFILE1o -o $TMPFILE2o > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ echo "The version of LD on this system ($LD) does not properly handle" >&2
+ echo "alignments. As a result, this project can not be built." >&2
+ echo "" >&2
+ echo "The problem may be the result of this LD bug report:" >&2
+ echo " http://sourceware.org/bugzilla/show_bug.cgi?id=12726" >&2
+ echo "" >&2
+ echo "Please update to a working version of binutils and retry." >&2
+ echo -1
+ exit 0
+fi
+
+# Test for "-fwhole-program". Older versions of gcc (pre v4.1) don't
+# support the whole-program optimization - detect that.
+$CC -fwhole-program -S -o /dev/null -xc /dev/null > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ echo " Working around no -fwhole-program" >&2
+ echo 2
+ exit 0
+fi
+
+# Test if "visible" variables and functions are marked global. On
+# OpenSuse 10.3 "visible" variables declared with "extern" first
+# aren't marked as global in the resulting assembler. On Ubuntu 7.10
+# "visible" functions aren't marked as global in the resulting
+# assembler.
+cat - > $TMPFILE1 <<EOF
+void __attribute__((externally_visible)) t1() { }
+extern unsigned char v1;
+unsigned char v1 __attribute__((section(".data16.foo.19"))) __attribute__((externally_visible));
+EOF
+$CC -Os -c -fwhole-program $TMPFILE1 -o $TMPFILE1o > /dev/null 2>&1
+cat - > $TMPFILE2 <<EOF
+void t1();
+extern unsigned char v1;
+int __attribute__((externally_visible)) main() { t1(); return v1; }
+EOF
+$CC -Os -c -fwhole-program $TMPFILE2 -o $TMPFILE2o > /dev/null 2>&1
+$CC -nostdlib -Os $TMPFILE1o $TMPFILE2o -o $TMPFILE3o > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ echo " Working around non-functional -fwhole-program" >&2
+ echo 2
+ exit 0
+fi
+
+echo 0
+
+# Also, the Ubuntu 8.04 compiler has a bug causing corruption when the
+# "ebp" register is clobberred in an "asm" statement. The code has
+# been modified to not clobber "ebp" - no test is available yet.
+
+rm -f $TMPFILE1 $TMPFILE1o $TMPFILE1_ld $TMPFILE2 $TMPFILE2o $TMPFILE3o
diff --git a/roms/seabios/scripts/transdump.py b/roms/seabios/scripts/transdump.py
new file mode 100755
index 00000000..665f04a0
--- /dev/null
+++ b/roms/seabios/scripts/transdump.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+# This script is useful for taking the output of memdump() and
+# converting it back into binary output. This can be useful, for
+# example, when one wants to push that data into other tools like
+# objdump or hexdump.
+#
+# (C) Copyright 2010 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+import struct
+
+def unhex(str):
+ return int(str, 16)
+
+def parseMem(filehdl):
+ mem = []
+ for line in filehdl:
+ parts = line.split(':')
+ if len(parts) < 2:
+ continue
+ try:
+ vaddr = unhex(parts[0])
+ parts = parts[1].split()
+ mem.extend([unhex(v) for v in parts])
+ except ValueError:
+ continue
+ return mem
+
+def printUsage():
+ sys.stderr.write("Usage:\n %s <file | ->\n"
+ % (sys.argv[0],))
+ sys.exit(1)
+
+def main():
+ if len(sys.argv) != 2:
+ printUsage()
+ filename = sys.argv[1]
+ if filename == '-':
+ filehdl = sys.stdin
+ else:
+ filehdl = open(filename, 'r')
+ mem = parseMem(filehdl)
+ for i in mem:
+ if (sys.version_info > (3, 0)):
+ sys.stdout.buffer.write(struct.pack("<I", i))
+ else:
+ sys.stdout.write(struct.pack("<I", i))
+
+if __name__ == '__main__':
+ main()
diff --git a/roms/seabios/scripts/vgafixup.py b/roms/seabios/scripts/vgafixup.py
new file mode 100644
index 00000000..2053cd5d
--- /dev/null
+++ b/roms/seabios/scripts/vgafixup.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+# Work around x86emu bugs by replacing problematic instructions.
+#
+# Copyright (C) 2012 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# The x86emu code widely used in Linux distributions when running Xorg
+# in vesamode is known to have issues with "retl", "leavel", "entryl",
+# "leal", and some variants of "calll". This code modifies those
+# instructions that are known to be generated by gcc to avoid
+# triggering the x86emu bugs.
+
+# It is also known that the Windows vgabios emulator has issues with
+# addressing negative offsets to the %esp register. That has been
+# worked around by not using the gcc parameter "-fomit-frame-pointer"
+# when compiling.
+
+import sys, re
+
+# leal parameter regex - example string: -3(%edx,%eax,8), %eax
+re_leal = re.compile(
+ r'^\s*(?P<offset>[^(]*?)\s*'
+ r'\(\s*(?P<base>[^,)]*?)\s*(?:,\s*(?P<index>[^,)]*?)\s*)?'
+ r'(?:,\s*(?P<scale>[^,)]*?)\s*)?\)\s*'
+ r',\s*(?P<dest>.*?)\s*$')
+
+# Find an alternate set of instructions for a given "leal" instruction
+def handle_leal(sline):
+ m = re_leal.match(sline[5:])
+ if m is None or m.group('index') == '%esp':
+ print("Unable to fixup leal instruction: %s" % (sline,))
+ sys.exit(-1)
+ offset, base, index, scale, dest = m.group(
+ 'offset', 'base', 'index', 'scale', 'dest')
+ if dest == '%esp':
+ # If destination is %esp then just use 16bit leaw instead
+ return 'leaw %s\n' % (sline[5:].replace('%e', '%'),)
+ if not scale:
+ scale = '1'
+ scale = {1: 0, 2: 1, 4: 2, 8: 3}[int(scale, 0)]
+ # Try to rearrange arguments to simplify 'base' (to improve code gen)
+ if not scale and base == index:
+ base, index, scale = '', index, 1
+ elif not index or (not scale and base in (dest, '%esp') and index != dest):
+ base, index, scale = index, base, 0
+ # Produce instructions to calculate "leal"
+ insns = ['pushfw']
+ if base != dest:
+ # Calculate "leal" directly in dest register
+ if index != dest:
+ insns.insert(0, 'movl %s, %s' % (index, dest))
+ if scale:
+ insns.append('shll $%d, %s' % (scale, dest))
+ if base:
+ if base == '%esp':
+ offset += '+2'
+ insns.append('addl %s, %s' % (base, dest))
+ elif base == index:
+ # Use "imull" method
+ insns.append('imull $%d, %s' % ((1<<scale)+1, dest))
+ else:
+ # Backup/restore index register and do scaling in index register
+ insns.append('pushl %s' % (index,))
+ insns.append('shll $%d, %s' % (scale, index))
+ insns.append('addl %s, %s' % (index, dest))
+ insns.append('popl %s' % (index,))
+ if offset and offset != '0':
+ insns.append('addl $%s, %s' % (offset, dest))
+ insns.append('popfw\n')
+ return ' ; '.join(insns)
+
+def main():
+ infilename, outfilename = sys.argv[1:]
+ infile = open(infilename, 'r')
+ out = []
+ for line in infile:
+ sline = line.strip()
+ if sline == 'ret':
+ out.append('retw $2\n')
+ elif sline == 'leave':
+ out.append('movl %ebp, %esp ; popl %ebp\n')
+ elif sline.startswith('call'):
+ out.append('pushw %ax ; callw' + sline[4:] + '\n')
+ elif sline.startswith('leal'):
+ out.append(handle_leal(sline))
+ #print("-> %s\n %s" % (sline, out[-1].strip()))
+ else:
+ out.append(line)
+ infile.close()
+ outfile = open(outfilename, 'w')
+ outfile.write(''.join(out))
+ outfile.close()
+
+if __name__ == '__main__':
+ main()
diff --git a/roms/seabios/src/Kconfig b/roms/seabios/src/Kconfig
new file mode 100644
index 00000000..45ca59cf
--- /dev/null
+++ b/roms/seabios/src/Kconfig
@@ -0,0 +1,516 @@
+# Kconfig SeaBIOS configuration
+
+mainmenu "SeaBIOS Configuration"
+
+menu "General Features"
+
+choice
+ prompt "Build Target"
+ default QEMU
+
+ config COREBOOT
+ bool "Build for coreboot"
+ 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 Compatibilty Support Module for EFI BIOS"
+ 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
+ bool "Support Xen HVM"
+ default y
+ help
+ Configure to be used by xen hvmloader, for a HVM guest.
+
+ config THREADS
+ bool "Parallelize hardware init"
+ default y
+ help
+ Support running hardware initialization in parallel.
+
+ config RELOCATE_INIT
+ bool "Copy init code to high memory"
+ default y
+ 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
+ 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 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 FLASH_FLOPPY
+ depends on COREBOOT_FLASH
+ bool "Floppy images in CBFS"
+ default y
+ help
+ Support floppy images in coreboot flash.
+ config ENTRY_EXTRASTACK
+ bool "Use internal stack for 16bit interrupt entry points"
+ default y
+ 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
+ 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 && QEMU_HARDWARE
+ bool "SD controllers"
+ default y
+ help
+ Support for SD cards on PCI host controllers.
+ config VIRTIO_BLK
+ depends on DRIVES && QEMU_HARDWARE
+ bool "virtio-blk controllers"
+ default y
+ help
+ Support boot from virtio-blk storage.
+ config VIRTIO_SCSI
+ depends on DRIVES && QEMU_HARDWARE
+ bool "virtio-scsi controllers"
+ default y
+ help
+ Support boot from virtio-scsi storage.
+ config PVSCSI
+ depends on DRIVES && QEMU_HARDWARE
+ 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 FLOPPY
+ depends on DRIVES
+ bool "Floppy controller"
+ default y
+ help
+ Support floppy drive access.
+
+ 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
+ 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 LPT
+ bool "Parallel port"
+ default y
+ help
+ Support parallel ports. This also enables int 17 parallel port calls.
+
+ config USE_SMM
+ depends on QEMU
+ 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
+ bool "Initialize MTRRs"
+ default y
+ help
+ Initialize the Memory Type Range Registers (on emulators).
+ config PMTIMER
+ bool "Use ACPI timer"
+ default y
+ help
+ Use the ACPI timer instead of the TSC for timekeeping (on qemu).
+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
+ bool "Option ROMS"
+ default y
+ help
+ Support finding and running option roms during POST.
+ config OPTIONROMS_DEPLOYED
+ depends on OPTIONROMS && QEMU
+ bool "Option roms are already at 0xc0000-0xf0000"
+ default n
+ help
+ Select this if option ROMs are already copied to
+ 0xc0000-0xf0000. This must only be selected when using
+ Bochs or QEMU versions older than 0.12.
+ 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.
+
+endmenu
+
+menu "BIOS Tables"
+ depends on QEMU
+ 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.
+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_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/src/apm.c b/roms/seabios/src/apm.c
new file mode 100644
index 00000000..f7c2306c
--- /dev/null
+++ b/roms/seabios/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/src/asm-offsets.c b/roms/seabios/src/asm-offsets.c
new file mode 100644
index 00000000..b98f3b5a
--- /dev/null
+++ b/roms/seabios/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/src/biosvar.h b/roms/seabios/src/biosvar.h
new file mode 100644
index 00000000..58bcbced
--- /dev/null
+++ b/roms/seabios/src/biosvar.h
@@ -0,0 +1,130 @@
+// 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 "config.h" // SEG_BDA
+#include "farptr.h" // GET_FARVAR
+#include "std/bda.h" // struct bios_data_area_s
+
+
+/****************************************************************
+ * Interupt vector table
+ ****************************************************************/
+
+#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); \
+ })
+
+
+/****************************************************************
+ * Bios Data Area (BDA)
+ ****************************************************************/
+
+// Accessor functions
+#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))
+
+// 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);
+}
+#define GET_GLOBAL(var) \
+ GET_VAR(GLOBAL_SEGREG, *(typeof(&(var)))((void*)&(var) \
+ + get_global_offset()))
+#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
+ ****************************************************************/
+
+extern u8 _zonelow_seg, zonelow_base[];
+#define SEG_LOW ((u32)&_zonelow_seg)
+
+#if MODESEGMENT
+#define GET_LOW(var) GET_FARVAR(SEG_LOW, (var))
+#define SET_LOW(var, val) SET_FARVAR(SEG_LOW, (var), (val))
+#define LOWFLAT2LOW(var) ((typeof(var))((void*)(var) - (u32)zonelow_base))
+#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/src/block.c b/roms/seabios/src/block.c
new file mode 100644
index 00000000..3f7ecb1d
--- /dev/null
+++ b/roms/seabios/src/block.c
@@ -0,0 +1,582 @@
+// 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/blockcmd.h" // cdb_*
+#include "hw/pci.h" // pci_bdf_to_bus
+#include "hw/rtc.h" // rtc_read
+#include "hw/virtio-blk.h" // process_virtio_blk_op
+#include "malloc.h" // malloc_low
+#include "output.h" // dprintf
+#include "stacks.h" // stack_hop
+#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 u8
+get_translation(struct drive_s *drive)
+{
+ u8 type = drive->type;
+ if (CONFIG_QEMU && type == DTYPE_ATA) {
+ // Emulators pass in the translation info via nvram.
+ u8 ataid = drive->cntl_id;
+ u8 channel = ataid / 2;
+ u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + channel/2);
+ translation >>= 2 * (ataid % 4);
+ 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;
+ }
+ // 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=%d\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 = MAKE_FLATPTR(SEG_BDA, 0);
+ 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
+ ****************************************************************/
+
+static int
+fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf
+ , u32 dpte_so, char *iface_type
+ , int bdf, u8 channel, u16 iobase, u64 device_path)
+{
+ 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_GLOBALFLAT(drive_gf->type);
+ u16 npc = GET_GLOBALFLAT(drive_gf->pchs.cylinder);
+ u16 nph = GET_GLOBALFLAT(drive_gf->pchs.head);
+ u16 nps = GET_GLOBALFLAT(drive_gf->pchs.sector);
+ u64 lba = GET_GLOBALFLAT(drive_gf->sectors);
+ u16 blksize = GET_GLOBALFLAT(drive_gf->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 || !iface_type)
+ 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);
+
+ int i;
+ for (i=0; i<sizeof(param_far->iface_type); i++)
+ SET_FARVAR(seg, param_far->iface_type[i], GET_GLOBAL(iface_type[i]));
+
+ if (bdf != -1) {
+ SET_FARVAR(seg, param_far->host_bus[0], 'P');
+ SET_FARVAR(seg, param_far->host_bus[1], 'C');
+ SET_FARVAR(seg, param_far->host_bus[2], 'I');
+ SET_FARVAR(seg, param_far->host_bus[3], ' ');
+
+ u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
+ | (pci_bdf_to_fn(bdf) << 16));
+ if (t13)
+ path |= channel << 24;
+
+ SET_FARVAR(seg, param_far->iface_path, path);
+ } else {
+ // ISA
+ SET_FARVAR(seg, param_far->host_bus[0], 'I');
+ SET_FARVAR(seg, param_far->host_bus[1], 'S');
+ SET_FARVAR(seg, param_far->host_bus[2], 'A');
+ SET_FARVAR(seg, param_far->host_bus[3], ' ');
+
+ SET_FARVAR(seg, param_far->iface_path, iobase);
+ }
+
+ 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;
+}
+
+struct dpte_s DefaultDPTE VARLOW;
+
+static int
+fill_ata_edd(u16 seg, struct int13dpt_s *param_far, 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) {
+ 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);
+
+ return fill_generic_edd(
+ seg, param_far, drive_gf, SEGOFF(SEG_LOW, (u32)&DefaultDPTE).segoff
+ , "ATA ", bdf, channel, iobase1, slave);
+}
+
+int noinline
+fill_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf)
+{
+ switch (GET_GLOBALFLAT(drive_gf->type)) {
+ case DTYPE_ATA:
+ case DTYPE_ATA_ATAPI:
+ return fill_ata_edd(seg, param_far, drive_gf);
+ case DTYPE_VIRTIO_BLK:
+ case DTYPE_VIRTIO_SCSI:
+ return fill_generic_edd(
+ seg, param_far, drive_gf, 0xffffffff
+ , "SCSI ", GET_GLOBALFLAT(drive_gf->cntl_id), 0, 0, 0);
+ default:
+ return fill_generic_edd(seg, param_far, drive_gf, 0, NULL, 0, 0, 0, 0);
+ }
+}
+
+
+/****************************************************************
+ * 16bit calling interface
+ ****************************************************************/
+
+int VISIBLE32FLAT
+process_atapi_op(struct disk_op_s *op)
+{
+ switch (op->command) {
+ case CMD_WRITE:
+ case CMD_FORMAT:
+ return DISK_RET_EWRITEPROTECT;
+ default:
+ return scsi_process_op(op);
+ }
+}
+
+// Execute a disk_op request.
+int
+process_op(struct disk_op_s *op)
+{
+ ASSERT16();
+ int ret, origcount = op->count;
+ if (origcount * GET_GLOBALFLAT(op->drive_gf->blksize) > 64*1024) {
+ op->count = 0;
+ return DISK_RET_EBOUNDARY;
+ }
+ u8 type = GET_GLOBALFLAT(op->drive_gf->type);
+ switch (type) {
+ case DTYPE_FLOPPY:
+ ret = process_floppy_op(op);
+ break;
+ case DTYPE_ATA:
+ ret = process_ata_op(op);
+ break;
+ case DTYPE_RAMDISK:
+ ret = process_ramdisk_op(op);
+ break;
+ case DTYPE_CDEMU:
+ ret = process_cdemu_op(op);
+ break;
+ case DTYPE_VIRTIO_BLK:
+ ret = process_virtio_blk_op(op);
+ break;
+ case DTYPE_AHCI: ;
+ extern void _cfunc32flat_process_ahci_op(void);
+ ret = call32(_cfunc32flat_process_ahci_op
+ , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
+ break;
+ case DTYPE_ATA_ATAPI:
+ ret = process_atapi_op(op);
+ break;
+ case DTYPE_AHCI_ATAPI: ;
+ extern void _cfunc32flat_process_atapi_op(void);
+ ret = call32(_cfunc32flat_process_atapi_op
+ , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
+ break;
+ case DTYPE_SDCARD: ;
+ extern void _cfunc32flat_process_sdcard_op(void);
+ ret = call32(_cfunc32flat_process_sdcard_op
+ , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
+ break;
+ case DTYPE_USB:
+ case DTYPE_UAS:
+ case DTYPE_VIRTIO_SCSI:
+ case DTYPE_LSI_SCSI:
+ case DTYPE_ESP_SCSI:
+ case DTYPE_MEGASAS:
+ ret = scsi_process_op(op);
+ break;
+ case DTYPE_USB_32:
+ case DTYPE_UAS_32:
+ case DTYPE_PVSCSI: ;
+ extern void _cfunc32flat_scsi_process_op(void);
+ ret = call32(_cfunc32flat_scsi_process_op
+ , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
+ break;
+ default:
+ ret = DISK_RET_EPARAM;
+ break;
+ }
+ if (ret && op->count == origcount)
+ // If the count hasn't changed on error, assume no data transferred.
+ op->count = 0;
+ return ret;
+}
+
+// Execute a "disk_op_s" request - this runs on 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));
+
+ dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n"
+ , dop.drive_gf, (u32)dop.lba, dop.buf_fl
+ , dop.count, dop.command);
+
+ 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 by jumping to the extra 16bit stack.
+int
+send_disk_op(struct disk_op_s *op)
+{
+ ASSERT16();
+ if (! CONFIG_DRIVES)
+ return -1;
+
+ return stack_hop((u32)op, GET_SEG(SS), __send_disk_op);
+}
diff --git a/roms/seabios/src/block.h b/roms/seabios/src/block.h
new file mode 100644
index 00000000..8182288d
--- /dev/null
+++ b/roms/seabios/src/block.h
@@ -0,0 +1,109 @@
+#ifndef __BLOCK_H
+#define __BLOCK_H
+
+#include "types.h" // u32
+
+
+/****************************************************************
+ * Disk command request
+ ****************************************************************/
+
+struct disk_op_s {
+ u64 lba;
+ void *buf_fl;
+ struct drive_s *drive_gf;
+ u16 count;
+ u8 command;
+};
+
+#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
+
+
+/****************************************************************
+ * 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
+};
+
+#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_SDCARD 0x90
+
+#define MAXDESCSIZE 80
+
+#define TRANSLATION_NONE 0
+#define TRANSLATION_LBA 1
+#define TRANSLATION_LARGE 2
+#define TRANSLATION_RECHS 3
+
+#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(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf);
+int process_op(struct disk_op_s *op);
+int send_disk_op(struct disk_op_s *op);
+int create_bounce_buf(void);
+
+#endif // block.h
diff --git a/roms/seabios/src/bmp.c b/roms/seabios/src/bmp.c
new file mode 100644
index 00000000..d8e76b78
--- /dev/null
+++ b/roms/seabios/src/bmp.c
@@ -0,0 +1,117 @@
+/*
+* Basic BMP data process and Raw picture data handle functions.
+* Could be used to adjust pixel data format, get infomation, 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_24bpp(u8 *src, u8 *dest, int width,
+ int height, int bytes_per_line_dest)
+{
+ int bytes_per_line_src = 3 * width;
+ 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_size(struct bmp_decdata *bmp, int *width, int *height)
+{
+ *width = bmp->width;
+ *height = bmp->height;
+}
+
+/* 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;
+ /* now only support 24bpp bmp file */
+ if ((depth == 24) && (bmp->bpp == 24)) {
+ raw_data_format_adjust_24bpp(bmp->datap, pic, width, height,
+ bytes_per_line_dest);
+ return 0;
+ }
+ return 1;
+}
diff --git a/roms/seabios/src/boot.c b/roms/seabios/src/boot.c
new file mode 100644
index 00000000..f23e9e15
--- /dev/null
+++ b/roms/seabios/src/boot.c
@@ -0,0 +1,756 @@
+// 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/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
+
+
+/****************************************************************
+ * 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);
+}
+
+// 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++;
+ }
+}
+
+// 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;
+}
+
+#define FW_PCI_DOMAIN "/pci@i0cf8"
+
+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 {
+ if (pci->rootbus)
+ p += snprintf(p, max, "/pci-root@%x", pci->rootbus);
+ p += snprintf(p, buf+max-p, "%s", FW_PCI_DOMAIN);
+ }
+
+ 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;
+}
+
+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_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;
+ // Find scsi drive - for example: /pci@i0cf8/scsi@5/channel@0/disk@1,0
+ char desc[256], *p;
+ p = build_pci_path(desc, sizeof(desc), "*", pci);
+ snprintf(p, desc+sizeof(desc)-p, "/*@0/*@%x,%x", 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;
+ // Find ata drive - for example: /pci@i0cf8/ide@1,1/drive@1/disk@0
+ char desc[256], *p;
+ p = build_pci_path(desc, sizeof(desc), "*", pci);
+ snprintf(p, desc+sizeof(desc)-p, "/drive@%x/disk@%x", 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 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", hub->usbdev->port+1);
+ return p;
+}
+
+int bootprio_find_usb(struct usbdevice_s *usbdev, int lun)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ // Find usb - for example: /pci@i0cf8/usb@1,2/storage@1/channel@0/disk@0,0
+ char desc[256], *p;
+ p = build_pci_path(desc, sizeof(desc), "usb", usbdev->hub->cntl->pci);
+ p = build_usb_path(p, desc+sizeof(desc)-p, usbdev->hub);
+ snprintf(p, desc+sizeof(desc)-p, "/storage@%x/*@0/*@0,%x"
+ , usbdev->port+1, 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", usbdev->port+1);
+ 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();
+}
+
+
+/****************************************************************
+ * 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_g, const char *desc, int prio)
+{
+ bootentry_add(IPL_TYPE_FLOPPY, defPrio(prio, DefaultFloppyPrio)
+ , (u32)drive_g, desc);
+}
+
+void
+boot_add_hd(struct drive_s *drive_g, const char *desc, int prio)
+{
+ bootentry_add(IPL_TYPE_HARDDISK, defPrio(prio, DefaultHDPrio)
+ , (u32)drive_g, desc);
+}
+
+void
+boot_add_cd(struct drive_s *drive_g, const char *desc, int prio)
+{
+ bootentry_add(IPL_TYPE_CDROM, defPrio(prio, DefaultCDPrio)
+ , (u32)drive_g, 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.ah;
+}
+
+// Read a keystroke - waiting up to 'msec' milliseconds.
+static int
+get_keystroke(int msec)
+{
+ u32 end = irqtimer_calc(msec);
+ for (;;) {
+ if (check_for_keystroke())
+ return get_raw_keystroke();
+ if (irqtimer_check(end))
+ return -1;
+ yield_toirq();
+ }
+}
+
+
+/****************************************************************
+ * Boot menu and BCV execution
+ ****************************************************************/
+
+#define DEFAULT_BOOTMENU_WAIT 2500
+
+// Show IPL option menu.
+void
+interactive_bootmenu(void)
+{
+ // XXX - show available drives?
+
+ if (! CONFIG_BOOTMENU || !romfile_loadint("etc/show-boot-menu", 1))
+ return;
+
+ while (get_keystroke(0) >= 0)
+ ;
+
+ char *bootmsg = romfile_loadfile("etc/boot-menu-message", NULL);
+ int menukey = romfile_loadint("etc/boot-menu-key", 0x86);
+ printf("%s", bootmsg ?: "\nPress F12 for boot menu.\n\n");
+ 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;
+ hlist_for_each_entry(pos, &BootList, node) {
+ char desc[60];
+ maxmenu++;
+ printf("%d. %s\n", maxmenu
+ , strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
+ }
+
+ // Get key press
+ for (;;) {
+ scan_code = get_keystroke(1000);
+ if (scan_code >= 1 && scan_code <= maxmenu+1)
+ break;
+ }
+ printf("\n");
+ if (scan_code == 0x01)
+ // ESC
+ return;
+
+ // Find entry and make top priority.
+ int choice = scan_code - 1;
+ hlist_for_each_entry(pos, &BootList, node) {
+ if (! --choice)
+ break;
+ }
+ hlist_del(&pos->node);
+ pos->priority = 0;
+ hlist_add_head(&pos->node, &BootList);
+}
+
+// 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;
+ }
+ }
+
+ /* 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_g)
+{
+ if (! CONFIG_CDROM_BOOT)
+ return;
+ printf("Booting from DVD/CD...\n");
+
+ int status = cdrom_boot(drive_g);
+ 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;
+ /* 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/src/bootsplash.c b/roms/seabios/src/bootsplash.c
new file mode 100644
index 00000000..c572685d
--- /dev/null
+++ b/roms/seabios/src/bootsplash.c
@@ -0,0 +1,254 @@
+// 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)
+ 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_size(bmp, &width, &height);
+ bpp_require = 24;
+ }
+ /* jpeg would use 16 or 24 bpp video mode, BMP use 24bpp mode only */
+
+ // 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/src/bregs.h b/roms/seabios/src/bregs.h
new file mode 100644
index 00000000..d4052634
--- /dev/null
+++ b/roms/seabios/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/src/byteorder.h b/roms/seabios/src/byteorder.h
new file mode 100644
index 00000000..928c1b80
--- /dev/null
+++ b/roms/seabios/src/byteorder.h
@@ -0,0 +1,71 @@
+#ifndef __BYTEORDER_H
+#define __BYTEORDER_H
+
+#include "types.h" // u32
+
+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) {
+ asm("bswapl %0" : "+r"(val));
+ 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))
+
+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);
+}
+
+#endif // byteorder.h
diff --git a/roms/seabios/src/cdrom.c b/roms/seabios/src/cdrom.c
new file mode 100644
index 00000000..92f34f42
--- /dev/null
+++ b/roms/seabios/src/cdrom.c
@@ -0,0 +1,281 @@
+// 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
+
+// Locks for removable devices
+u8 CDRom_locks[BUILD_MAX_EXTDRIVE] VARLOW;
+
+
+/****************************************************************
+ * 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_gf = 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
+process_cdemu_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;
+ case CMD_VERIFY:
+ case CMD_RESET:
+ case CMD_SEEK:
+ case CMD_ISREADY:
+ return DISK_RET_SUCCESS;
+ default:
+ return DISK_RET_EPARAM;
+ }
+}
+
+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();
+ free(drive);
+ 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_gf = drive;
+ if (!dop.drive_gf || cdid < 0)
+ return 1;
+
+ int ret = scsi_is_ready(&dop);
+ if (ret)
+ dprintf(1, "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 = scsi_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 = scsi_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
+
+ // 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 = scsi_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;
+}
diff --git a/roms/seabios/src/clock.c b/roms/seabios/src/clock.c
new file mode 100644
index 00000000..9ab0ac02
--- /dev/null
+++ b/roms/seabios/src/clock.c
@@ -0,0 +1,462 @@
+// 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/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));
+ 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);
+}
+
+// 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;
+ default: handle_1aXX(regs); break;
+ }
+}
+
+// INT 08h System Timer ISR Entry Point
+void VISIBLE16
+handle_08(void)
+{
+ debug_isr(DEBUG_ISR_08);
+
+ // Update counter
+ u32 counter = GET_BDA(timer_counter);
+ counter++;
+ // compare to one days worth of timer ticks at 18.2 hz
+ 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();
+
+ // 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();
+}
+
+
+/****************************************************************
+ * 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)
+{
+ // 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)
+{
+ 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)
+{
+ 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/src/code16gcc.s b/roms/seabios/src/code16gcc.s
new file mode 100644
index 00000000..8f7121b8
--- /dev/null
+++ b/roms/seabios/src/code16gcc.s
@@ -0,0 +1 @@
+.code16gcc
diff --git a/roms/seabios/src/config.h b/roms/seabios/src/config.h
new file mode 100644
index 00000000..6da067d0
--- /dev/null
+++ b/roms/seabios/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
+
+#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
+// 32KB for shadow ram copying (works around emulator deficiencies)
+#define BUILD_BIOS_TMP_ADDR 0x30000
+#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_10 20
+#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
+
+#endif // config.h
diff --git a/roms/seabios/src/disk.c b/roms/seabios/src/disk.c
new file mode 100644
index 00000000..0e0af24b
--- /dev/null
+++ b/roms/seabios/src/disk.c
@@ -0,0 +1,748 @@
+// 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_gf)
+{
+ struct chs_s res = { };
+ if (CONFIG_CDROM_EMU && drive_gf == 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_GLOBALFLAT(drive_gf->lchs.cylinder);
+ res.head = GET_GLOBALFLAT(drive_gf->lchs.head);
+ res.sector = GET_GLOBALFLAT(drive_gf->lchs.sector);
+ return res;
+}
+
+// Perform read/write/verify using old-style chs accesses
+static void noinline
+basic_access(struct bregs *regs, struct drive_s *drive_gf, u16 command)
+{
+ struct disk_op_s dop;
+ dop.drive_gf = drive_gf;
+ 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_gf);
+ 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_gf, 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_gf = drive_gf;
+ if (dop.lba >= GET_GLOBALFLAT(drive_gf->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_gf)
+{
+ struct disk_op_s dop;
+ dop.drive_gf = drive_gf;
+ 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_gf)
+{
+ 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_gf)
+{
+ basic_access(regs, drive_gf, CMD_READ);
+}
+
+// write disk sectors
+static void
+disk_1303(struct bregs *regs, struct drive_s *drive_gf)
+{
+ basic_access(regs, drive_gf, CMD_WRITE);
+}
+
+// verify disk sectors
+static void
+disk_1304(struct bregs *regs, struct drive_s *drive_gf)
+{
+ basic_access(regs, drive_gf, CMD_VERIFY);
+}
+
+// format disk track
+static void noinline
+disk_1305(struct bregs *regs, struct drive_s *drive_gf)
+{
+ debug_stub(regs);
+
+ struct chs_s chs = getLCHS(drive_gf);
+ 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_gf = drive_gf;
+ 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_gf)
+{
+ // Get logical geometry from table
+ struct chs_s chs = getLCHS(drive_gf);
+ 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_gf == GET_GLOBAL(cdemu_drive_gf))
+ regs->bx = GET_LOW(CDEmu.media) * 2;
+ else
+ regs->bx = GET_GLOBALFLAT(drive_gf->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_gf)
+{
+ DISK_STUB(regs);
+}
+
+// seek to specified cylinder
+static void
+disk_130c(struct bregs *regs, struct drive_s *drive_gf)
+{
+ DISK_STUB(regs);
+}
+
+// alternate disk reset
+static void
+disk_130d(struct bregs *regs, struct drive_s *drive_gf)
+{
+ DISK_STUB(regs);
+}
+
+// check drive ready
+static void
+disk_1310(struct bregs *regs, struct drive_s *drive_gf)
+{
+ // should look at 40:8E also???
+
+ struct disk_op_s dop;
+ dop.drive_gf = drive_gf;
+ 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_gf)
+{
+ DISK_STUB(regs);
+}
+
+// controller internal diagnostic
+static void
+disk_1314(struct bregs *regs, struct drive_s *drive_gf)
+{
+ DISK_STUB(regs);
+}
+
+// read disk drive size
+static void noinline
+disk_1315(struct bregs *regs, struct drive_s *drive_gf)
+{
+ 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_gf);
+ 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_gf)
+{
+ 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_gf)
+{
+ 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_gf)
+{
+ extended_access(regs, drive_gf, CMD_READ);
+}
+
+// IBM/MS extended write
+static void
+disk_1343(struct bregs *regs, struct drive_s *drive_gf)
+{
+ extended_access(regs, drive_gf, CMD_WRITE);
+}
+
+// IBM/MS verify
+static void
+disk_1344(struct bregs *regs, struct drive_s *drive_gf)
+{
+ extended_access(regs, drive_gf, CMD_VERIFY);
+}
+
+// lock
+static void
+disk_134500(struct bregs *regs, struct drive_s *drive_gf)
+{
+ 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_gf)
+{
+ 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_gf)
+{
+ 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_gf)
+{
+ disk_ret_unimplemented(regs, DISK_RET_EPARAM);
+}
+
+// IBM/MS lock/unlock drive
+static void
+disk_1345(struct bregs *regs, struct drive_s *drive_gf)
+{
+ 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_gf); break;
+ case 0x01: disk_134501(regs, drive_gf); break;
+ case 0x02: disk_134502(regs, drive_gf); break;
+ default: disk_1345XX(regs, drive_gf); break;
+ }
+}
+
+// IBM/MS eject media
+static void noinline
+disk_1346(struct bregs *regs, struct drive_s *drive_gf)
+{
+ 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_gf)
+{
+ extended_access(regs, drive_gf, CMD_SEEK);
+}
+
+// IBM/MS get drive parameters
+static void
+disk_1348(struct bregs *regs, struct drive_s *drive_gf)
+{
+ int ret = fill_edd(regs->ds, (void*)(regs->si+0), drive_gf);
+ disk_ret(regs, ret);
+}
+
+// IBM/MS extended media change
+static void
+disk_1349(struct bregs *regs, struct drive_s *drive_gf)
+{
+ 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_gf)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e03(struct bregs *regs, struct drive_s *drive_gf)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e04(struct bregs *regs, struct drive_s *drive_gf)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e06(struct bregs *regs, struct drive_s *drive_gf)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134eXX(struct bregs *regs, struct drive_s *drive_gf)
+{
+ disk_ret(regs, DISK_RET_EPARAM);
+}
+
+// IBM/MS set hardware configuration
+static void
+disk_134e(struct bregs *regs, struct drive_s *drive_gf)
+{
+ switch (regs->al) {
+ case 0x01: disk_134e01(regs, drive_gf); break;
+ case 0x03: disk_134e03(regs, drive_gf); break;
+ case 0x04: disk_134e04(regs, drive_gf); break;
+ case 0x06: disk_134e06(regs, drive_gf); break;
+ default: disk_134eXX(regs, drive_gf); break;
+ }
+}
+
+static void
+disk_13XX(struct bregs *regs, struct drive_s *drive_gf)
+{
+ disk_ret_unimplemented(regs, DISK_RET_EPARAM);
+}
+
+static void
+disk_13(struct bregs *regs, struct drive_s *drive_gf)
+{
+ //debug_stub(regs);
+
+ // clear completion flag
+ SET_BDA(disk_interrupt_flag, 0);
+
+ switch (regs->ah) {
+ case 0x00: disk_1300(regs, drive_gf); break;
+ case 0x01: disk_1301(regs, drive_gf); break;
+ case 0x02: disk_1302(regs, drive_gf); break;
+ case 0x03: disk_1303(regs, drive_gf); break;
+ case 0x04: disk_1304(regs, drive_gf); break;
+ case 0x05: disk_1305(regs, drive_gf); break;
+ case 0x08: disk_1308(regs, drive_gf); break;
+ case 0x09: disk_1309(regs, drive_gf); break;
+ case 0x0c: disk_130c(regs, drive_gf); break;
+ case 0x0d: disk_130d(regs, drive_gf); break;
+ case 0x10: disk_1310(regs, drive_gf); break;
+ case 0x11: disk_1311(regs, drive_gf); break;
+ case 0x14: disk_1314(regs, drive_gf); break;
+ case 0x15: disk_1315(regs, drive_gf); break;
+ case 0x16: disk_1316(regs, drive_gf); break;
+ case 0x41: disk_1341(regs, drive_gf); break;
+ case 0x42: disk_1342(regs, drive_gf); break;
+ case 0x43: disk_1343(regs, drive_gf); break;
+ case 0x44: disk_1344(regs, drive_gf); break;
+ case 0x45: disk_1345(regs, drive_gf); break;
+ case 0x46: disk_1346(regs, drive_gf); break;
+ case 0x47: disk_1347(regs, drive_gf); break;
+ case 0x48: disk_1348(regs, drive_gf); break;
+ case 0x49: disk_1349(regs, drive_gf); break;
+ case 0x4e: disk_134e(regs, drive_gf); break;
+ default: disk_13XX(regs, drive_gf); break;
+ }
+}
+
+static void
+floppy_13(struct bregs *regs, struct drive_s *drive_gf)
+{
+ // 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_gf);
+ break;
+ default: disk_13XX(regs, drive_gf); 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_gf = getDrive(EXTTYPE_FLOPPY, extdrive);
+ if (!drive_gf)
+ goto fail;
+ floppy_13(regs, drive_gf);
+ return;
+ }
+
+ struct drive_s *drive_gf;
+ if (extdrive >= EXTSTART_CD)
+ drive_gf = getDrive(EXTTYPE_CD, extdrive - EXTSTART_CD);
+ else
+ drive_gf = getDrive(EXTTYPE_HD, extdrive - EXTSTART_HD);
+ if (!drive_gf)
+ goto fail;
+ disk_13(regs, drive_gf);
+ 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/src/entryfuncs.S b/roms/seabios/src/entryfuncs.S
new file mode 100644
index 00000000..7368bb6d
--- /dev/null
+++ b/roms/seabios/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/src/farptr.h b/roms/seabios/src/farptr.h
new file mode 100644
index 00000000..0a4db68b
--- /dev/null
+++ b/roms/seabios/src/farptr.h
@@ -0,0 +1,208 @@
+// 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 "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.
+#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)))
+
+
+#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.
+#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)
+#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/src/font.c b/roms/seabios/src/font.c
new file mode 100644
index 00000000..67e5d46b
--- /dev/null
+++ b/roms/seabios/src/font.c
@@ -0,0 +1,139 @@
+#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
+ */
+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,
+};
diff --git a/roms/seabios/src/fw/acpi-dsdt-cpu-hotplug.dsl b/roms/seabios/src/fw/acpi-dsdt-cpu-hotplug.dsl
new file mode 100644
index 00000000..0f3e83b1
--- /dev/null
+++ b/roms/seabios/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/src/fw/acpi-dsdt-dbug.dsl b/roms/seabios/src/fw/acpi-dsdt-dbug.dsl
new file mode 100644
index 00000000..276321f6
--- /dev/null
+++ b/roms/seabios/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/src/fw/acpi-dsdt-hpet.dsl b/roms/seabios/src/fw/acpi-dsdt-hpet.dsl
new file mode 100644
index 00000000..f33e5279
--- /dev/null
+++ b/roms/seabios/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/src/fw/acpi-dsdt-isa.dsl b/roms/seabios/src/fw/acpi-dsdt-isa.dsl
new file mode 100644
index 00000000..23761dbb
--- /dev/null
+++ b/roms/seabios/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/src/fw/acpi-dsdt-pci-crs.dsl b/roms/seabios/src/fw/acpi-dsdt-pci-crs.dsl
new file mode 100644
index 00000000..d4218914
--- /dev/null
+++ b/roms/seabios/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/src/fw/acpi-dsdt.dsl b/roms/seabios/src/fw/acpi-dsdt.dsl
new file mode 100644
index 00000000..3556dcaf
--- /dev/null
+++ b/roms/seabios/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/src/fw/acpi.c b/roms/seabios/src/fw/acpi.c
new file mode 100644
index 00000000..ecd1adcf
--- /dev/null
+++ b/roms/seabios/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/pci.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 "src/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 "src/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 "src/fw/ssdt-misc.hex"
+#include "src/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/src/fw/biostables.c b/roms/seabios/src/fw/biostables.c
new file mode 100644
index 00000000..50a891be
--- /dev/null
+++ b/roms/seabios/src/fw/biostables.c
@@ -0,0 +1,461 @@
+// 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 "malloc.h" // malloc_fseg
+#include "output.h" // dprintf
+#include "hw/pci.h" // pci_config_writeb
+#include "std/acpi.h" // struct rsdp_descriptor
+#include "std/mptable.h" // MPTABLE_SIGNATURE
+#include "std/pirtable.h" // struct pir_header
+#include "std/smbios.h" // struct smbios_entry_point
+#include "romfile.h"
+#include "string.h" // memcpy
+#include "util.h" // copy_table
+#include "x86.h" // outb
+
+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;
+ // 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)
+{
+ extern u8 zonefseg_start[], zonefseg_end[];
+ unsigned long start = (unsigned long)zonefseg_start;
+ unsigned long end = (unsigned long)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;
+}
+
+static struct fadt_descriptor_rev1 *
+find_fadt(void)
+{
+ dprintf(4, "rsdp=%p\n", RsdpAddr);
+ if (!RsdpAddr || RsdpAddr->signature != RSDP_SIGNATURE)
+ return NULL;
+ struct rsdt_descriptor_rev1 *rsdt = (void*)RsdpAddr->rsdt_physical_address;
+ dprintf(4, "rsdt=%p\n", rsdt);
+ if (!rsdt || rsdt->signature != RSDT_SIGNATURE)
+ return NULL;
+ void *end = (void*)rsdt + rsdt->length;
+ int i;
+ for (i=0; (void*)&rsdt->table_offset_entry[i] < end; i++) {
+ struct fadt_descriptor_rev1 *fadt = (void*)rsdt->table_offset_entry[i];
+ if (!fadt || fadt->signature != FACP_SIGNATURE)
+ continue;
+ dprintf(4, "fadt=%p\n", fadt);
+ return fadt;
+ }
+ dprintf(4, "no fadt found\n");
+ return NULL;
+}
+
+u32
+find_resume_vector(void)
+{
+ struct fadt_descriptor_rev1 *fadt = find_fadt();
+ 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_fadt();
+ 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));
+ }
+}
+
+
+/****************************************************************
+ * 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 (memcmp(p->anchor_string, "_SM_", 4))
+ 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;
+
+ 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;
+ 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/src/fw/coreboot.c b/roms/seabios/src/fw/coreboot.c
new file mode 100644
index 00000000..8fd84493
--- /dev/null
+++ b/roms/seabios/src/fw/coreboot.c
@@ -0,0 +1,553 @@
+// 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 "hw/pci.h" // pci_probe_devices
+#include "lzmadecode.h" // LzmaDecode
+#include "malloc.h" // free
+#include "memmap.h" // add_e820
+#include "output.h" // dprintf
+#include "paravirt.h" // PlatformRunningOn
+#include "romfile.h" // romfile_findprefix
+#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 buffer_size;
+ u32 buffer_cursor;
+ u8 buffer_body[0];
+} PACKED;
+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;
+ add_e820(m->start, m->size, type);
+ }
+
+ // Ughh - coreboot likes to set a map at 0x0000-0x1000, but this
+ // confuses grub. So, override it.
+ add_e820(0, 16*1024, E820_RAM);
+
+ 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");
+ add_e820(0, 16*1024*1024, E820_RAM);
+ return;
+}
+
+void coreboot_debug_putc(char c)
+{
+ if (!CONFIG_DEBUG_COREBOOT)
+ return;
+ if (!cbcon)
+ return;
+ u32 cursor = cbcon->buffer_cursor++;
+ if (cursor < cbcon->buffer_size)
+ cbcon->buffer_body[cursor] = c;
+}
+
+/****************************************************************
+ * 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 (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)() = 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/src/fw/csm.c b/roms/seabios/src/fw/csm.c
new file mode 100644
index 00000000..7cdb398f
--- /dev/null
+++ b/roms/seabios/src/fw/csm.c
@@ -0,0 +1,344 @@
+// 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"
+#include "config.h" // CONFIG_*
+#include "farptr.h" // MAKE_FLATPTR
+#include "hw/pci.h"
+#include "hw/pic.h"
+#include "malloc.h" // csm_malloc_preinit
+#include "memmap.h"
+#include "output.h" // dprintf
+#include "stacks.h" // wait_threads
+#include "std/acpi.h" // RSDP_SIGNATURE
+#include "std/bda.h" // struct bios_data_area_s
+#include "std/optionrom.h" // struct rom_header
+#include "util.h" // copy_smbios
+#include "paravirt.h" // qemu_preinit
+
+#define UINT8 u8
+#define UINT16 u16
+#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();
+ extern u8 final_readonly_start[];
+
+ dprintf(3, "handle_csm returning AX=%04x\n", regs->ax);
+
+ csm_compat_table.UmaAddress = rommax;
+ csm_compat_table.UmaSize = (u32)final_readonly_start - rommax;
+
+ 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);
+
+ csm_malloc_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++)
+ add_e820(p[i].start, p[i].size, p[i].type);
+
+ if (csm_init_table->HiPmmMemorySizeInBytes > BUILD_MAX_HIGHTABLE) {
+ u32 hi_pmm_end = csm_init_table->HiPmmMemory + csm_init_table->HiPmmMemorySizeInBytes;
+ add_e820(hi_pmm_end - BUILD_MAX_HIGHTABLE, BUILD_MAX_HIGHTABLE, E820_RESERVED);
+ }
+
+ // 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 = MAKE_FLATPTR(SEG_BDA, 0);
+ bda->hdcount = 0;
+
+ 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;
+
+ if (!region)
+ region = 3;
+
+ dprintf(3, "Legacy16GetTableAddress size %x align %x region %d\n",
+ size, align, region);
+
+ 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);
+
+ 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);
+}
+
+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 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 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 bbs[i].BootPriority;
+ }
+ }
+ return -1;
+}
diff --git a/roms/seabios/src/fw/dev-piix.h b/roms/seabios/src/fw/dev-piix.h
new file mode 100644
index 00000000..c389f171
--- /dev/null
+++ b/roms/seabios/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/src/fw/dev-q35.h b/roms/seabios/src/fw/dev-q35.h
new file mode 100644
index 00000000..c6f8bd9e
--- /dev/null
+++ b/roms/seabios/src/fw/dev-q35.h
@@ -0,0 +1,49 @@
+#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 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/src/fw/lzmadecode.c b/roms/seabios/src/fw/lzmadecode.c
new file mode 100644
index 00000000..65819b53
--- /dev/null
+++ b/roms/seabios/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/src/fw/lzmadecode.h b/roms/seabios/src/fw/lzmadecode.h
new file mode 100644
index 00000000..dedde0de
--- /dev/null
+++ b/roms/seabios/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/src/fw/mptable.c b/roms/seabios/src/fw/mptable.c
new file mode 100644
index 00000000..8e01e004
--- /dev/null
+++ b/roms/seabios/src/fw/mptable.c
@@ -0,0 +1,196 @@
+// 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"
+#include "hw/pci_regs.h"
+#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/src/fw/mtrr.c b/roms/seabios/src/fw/mtrr.c
new file mode 100644
index 00000000..913580e7
--- /dev/null
+++ b/roms/seabios/src/fw/mtrr.c
@@ -0,0 +1,106 @@
+// 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 "hw/pci.h" // pcimem_start
+#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/src/fw/paravirt.c b/roms/seabios/src/fw/paravirt.c
new file mode 100644
index 00000000..db22ae8f
--- /dev/null
+++ b/roms/seabios/src/fw/paravirt.c
@@ -0,0 +1,448 @@
+// 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 "hw/pci.h" // create_pirtable
+#include "hw/pci_regs.h" // PCI_DEVICE_ID
+#include "hw/rtc.h" // CMOS_*
+#include "malloc.h" // malloc_tmp
+#include "memmap.h" // add_e820
+#include "output.h" // dprintf
+#include "paravirt.h" // qemu_cfg_preinit
+#include "romfile.h" // romfile_loadint
+#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
+
+// Amount of continuous ram under 4Gig
+u32 RamSize;
+// Amount of continuous ram >4Gig
+u64 RamSizeOver4G;
+// Type of emulator platform.
+int PlatformRunningOn VARFSEG;
+
+/* 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;
+ }
+}
+
+static void qemu_detect(void)
+{
+ if (!CONFIG_QEMU_HARDWARE)
+ return;
+
+ // 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;
+ }
+ kvm_detect();
+}
+
+void
+qemu_preinit(void)
+{
+ qemu_detect();
+
+ if (!CONFIG_QEMU)
+ return;
+
+ if (runningOnXen()) {
+ xen_ramsize_preinit();
+ return;
+ }
+
+ if (!runningOnQEMU()) {
+ dprintf(1, "Warning: No QEMU Northbridge found (isapc?)\n");
+ PlatformRunningOn |= PF_QEMU;
+ kvm_detect();
+ }
+
+ // On emulators, 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;
+ add_e820(0, rs, E820_RAM);
+
+ /* reserve 256KB BIOS area at the end of 4 GB */
+ add_e820(0xfffc0000, 256*1024, E820_RESERVED);
+
+ dprintf(1, "RamSize: 0x%08x [cmos]\n", RamSize);
+}
+
+void
+qemu_platform_setup(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ if (runningOnXen()) {
+ pci_probe_devices();
+ xen_hypercall_setup();
+ xen_biostable_setup();
+ return;
+ }
+
+ // Initialize pci
+ pci_setup();
+ smm_device_setup();
+ smm_setup();
+
+ // Initialize mtrr and smp
+ mtrr_setup();
+ smp_setup();
+
+ // Create bios tables
+ 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)
+ 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_NUMA 0x0d
+#define QEMU_CFG_BOOT_MENU 0x0e
+#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_read(void *buf, int len)
+{
+ insb(PORT_QEMU_CFG_DATA, buf, len);
+}
+
+static void
+qemu_cfg_skip(int len)
+{
+ while (len--)
+ inb(PORT_QEMU_CFG_DATA);
+}
+
+static void
+qemu_cfg_read_entry(void *buf, int e, int len)
+{
+ qemu_cfg_select(e);
+ qemu_cfg_read(buf, len);
+}
+
+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);
+ qemu_cfg_select(qfile->select);
+ qemu_cfg_skip(qfile->skip);
+ qemu_cfg_read(dst, file->size);
+ return file->size;
+}
+
+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);
+}
+
+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)
+{
+ struct e820_reservation *table;
+ int i, size;
+
+ if (!CONFIG_QEMU)
+ return;
+
+ // "etc/e820" has both ram and reservations
+ table = romfile_loadfile("etc/e820", &size);
+ if (table) {
+ for (i = 0; i < size / sizeof(struct e820_reservation); i++) {
+ switch (table[i].type) {
+ case E820_RAM:
+ dprintf(1, "RamBlock: addr 0x%016llx len 0x%016llx [e820]\n",
+ table[i].address, table[i].length);
+ if (table[i].address < RamSize)
+ // ignore, preinit got it from cmos already and
+ // adding this again would ruin any reservations
+ // done so far
+ continue;
+ if (table[i].address < 0x100000000LL) {
+ // below 4g -- adjust RamSize to mark highest lowram addr
+ if (RamSize < table[i].address + table[i].length)
+ RamSize = table[i].address + table[i].length;
+ } else {
+ // above 4g -- adjust RamSizeOver4G to mark highest ram addr
+ if (0x100000000LL + RamSizeOver4G < table[i].address + table[i].length)
+ RamSizeOver4G = table[i].address + table[i].length - 0x100000000LL;
+ }
+ /* fall through */
+ case E820_RESERVED:
+ add_e820(table[i].address, table[i].length, table[i].type);
+ break;
+ default:
+ /*
+ * Qemu 1.7 uses RAM + RESERVED only. Ignore
+ * everything else, so we have the option to
+ * extend this in the future without breakage.
+ */
+ break;
+ }
+ }
+ 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));
+ add_e820(entry.address, entry.length, entry.type);
+ }
+ } else if (runningOnKVM()) {
+ // Backwards compatibility - provide hard coded range.
+ // 4 pages before the bios, 3 pages for vmx tss pages, the
+ // other page for EPT real mode pagetable
+ add_e820(0xfffbc000, 4*4096, E820_RESERVED);
+ }
+
+ // 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;
+ add_e820(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];
+};
+
+void qemu_cfg_init(void)
+{
+ if (!runningOnQEMU())
+ return;
+
+ // 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;
+ dprintf(1, "Found QEMU fw_cfg\n");
+
+ // 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);
+ }
+}
diff --git a/roms/seabios/src/fw/paravirt.h b/roms/seabios/src/fw/paravirt.h
new file mode 100644
index 00000000..95ffb92a
--- /dev/null
+++ b/roms/seabios/src/fw/paravirt.h
@@ -0,0 +1,37 @@
+#ifndef __PV_H
+#define __PV_H
+
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+
+// Types of paravirtualized platforms.
+#define PF_QEMU (1<<0)
+#define PF_XEN (1<<1)
+#define PF_KVM (1<<2)
+
+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
+#define PORT_QEMU_CFG_CTL 0x0510
+#define PORT_QEMU_CFG_DATA 0x0511
+
+void qemu_preinit(void);
+void qemu_platform_setup(void);
+void qemu_cfg_init(void);
+
+#endif
diff --git a/roms/seabios/src/fw/pciinit.c b/roms/seabios/src/fw/pciinit.c
new file mode 100644
index 00000000..46ae7090
--- /dev/null
+++ b/roms/seabios/src/fw/pciinit.c
@@ -0,0 +1,954 @@
+// 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 "hw/ata.h" // PORT_ATA1_CMD_BASE
+#include "hw/pci.h" // pci_config_readl
+#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "hw/pci_regs.h" // PCI_COMMAND
+#include "list.h" // struct hlist_node
+#include "malloc.h" // free
+#include "memmap.h" // add_e820
+#include "output.h" // dprintf
+#include "paravirt.h" // RamSize
+#include "romfile.h" // romfile_loadint
+#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
+
+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]);
+}
+
+/* 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]);
+
+ /* 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);
+
+ acpi_pm1a_cnt = acpi_pm_base + 0x04;
+ pmtimer_setup(acpi_pm_base + 0x08);
+}
+
+static void storage_ide_setup(struct pci_device *pci, void *arg)
+{
+ /* 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);
+}
+
+/* ICH9 SMBUS */
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_SMBUS */
+static void ich9_smbus_setup(struct pci_device *dev, void *arg)
+{
+ u16 bdf = dev->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 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, MIPC & 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),
+
+ PCI_DEVICE_END,
+};
+
+void pci_resume(void)
+{
+ if (!CONFIG_QEMU) {
+ return;
+ }
+
+ if (PiixPmBDF >= 0) {
+ piix4_pm_config_setup(PiixPmBDF);
+ }
+}
+
+static void pci_bios_init_device(struct pci_device *pci)
+{
+ u16 bdf = pci->bdf;
+ dprintf(1, "PCI: init bdf=%02x:%02x.%x id=%04x:%04x\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf)
+ , pci->vendor, pci->device);
+
+ /* map the interrupt */
+ 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);
+}
+
+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 %02x:%02x.%x for primary VGA\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ pci_bdf_to_fn(pci->bdf));
+ return;
+ }
+ }
+
+ pci = pci_find_class(PCI_CLASS_DISPLAY_VGA);
+ if (!pci) {
+ dprintf(1, "PCI: No VGA devices found\n");
+ return;
+ }
+
+ dprintf(1, "PCI: Enabling %02x:%02x.%x for primary VGA\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ pci_bdf_to_fn(pci->bdf));
+
+ 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 %02x:%02x.%x\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ pci_bdf_to_fn(pci->bdf));
+
+ 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_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 */
+ u16 bdf = dev->bdf;
+ 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);
+ add_e820(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;
+}
+
+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;
+ foreachpci(pci) {
+ pci_init_device(pci_platform_tbl, pci, NULL);
+ }
+}
+
+
+/****************************************************************
+ * 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) {
+ dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n",
+ subbus, *pci_bus);
+ subbus = *pci_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 = pci_find_capability(bus->bus_dev, PCI_CAP_ID_EXP);
+ 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, PCI_CAP_ID_SHPC);
+ return !!shpc_cap;
+}
+
+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;
+ int hotplug_support = pci_bus_hotplug_support(s);
+ 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;
+ if (pci_region_align(&s->r[type]) > align)
+ align = pci_region_align(&s->r[type]);
+ u64 sum = pci_region_sum(&s->r[type]);
+ if (!sum && hotplug_support)
+ sum = align; /* reserve min size for hot-plug */
+ u64 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) {
+ /* traditional region is big enougth, 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)
+{
+ u16 bdf = entry->dev->bdf;
+ if (entry->bar >= 0) {
+ dprintf(1, "PCI: map device bdf=%02x:%02x.%x"
+ " bar %d, addr %08llx, size %08llx [%s]\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf),
+ entry->bar, addr, entry->size, region_type_name[entry->type]);
+
+ pci_set_io_region_addr(entry->dev, entry->bar, addr, entry->is64);
+ return;
+ }
+
+ 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/src/fw/pirtable.c b/roms/seabios/src/fw/pirtable.c
new file mode 100644
index 00000000..a4944080
--- /dev/null
+++ b/roms/seabios/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: 4rd 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: 5rd 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/src/fw/q35-acpi-dsdt.dsl b/roms/seabios/src/fw/q35-acpi-dsdt.dsl
new file mode 100644
index 00000000..5dec5414
--- /dev/null
+++ b/roms/seabios/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/src/fw/romfile_loader.c b/roms/seabios/src/fw/romfile_loader.c
new file mode 100644
index 00000000..f4b17ff9
--- /dev/null
+++ b/roms/seabios/src/fw/romfile_loader.c
@@ -0,0 +1,177 @@
+#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 "output.h" // warn_*
+
+struct romfile_loader_file {
+ struct romfile_s *file;
+ void *data;
+};
+struct romfile_loader_files {
+ int nfiles;
+ struct romfile_loader_file files[];
+};
+
+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;
+}
+
+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();
+}
+
+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);
+ 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/src/fw/romfile_loader.h b/roms/seabios/src/fw/romfile_loader.h
new file mode 100644
index 00000000..15eab2ac
--- /dev/null
+++ b/roms/seabios/src/fw/romfile_loader.h
@@ -0,0 +1,72 @@
+#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 alloc_file[ROMFILE_LOADER_FILESZ];
+ u32 alloc_align;
+ u8 alloc_zone;
+ };
+
+ /*
+ * 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 pointer_dest_file[ROMFILE_LOADER_FILESZ];
+ char pointer_src_file[ROMFILE_LOADER_FILESZ];
+ u32 pointer_offset;
+ u8 pointer_size;
+ };
+
+ /*
+ * 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 cksum_file[ROMFILE_LOADER_FILESZ];
+ u32 cksum_offset;
+ u32 cksum_start;
+ u32 cksum_length;
+ };
+
+ /* padding */
+ char pad[124];
+ };
+};
+
+enum {
+ ROMFILE_LOADER_COMMAND_ALLOCATE = 0x1,
+ ROMFILE_LOADER_COMMAND_ADD_POINTER = 0x2,
+ ROMFILE_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
+};
+
+enum {
+ ROMFILE_LOADER_ALLOC_ZONE_HIGH = 0x1,
+ ROMFILE_LOADER_ALLOC_ZONE_FSEG = 0x2,
+};
+
+int romfile_loader_execute(const char *name);
+
+#endif
diff --git a/roms/seabios/src/fw/shadow.c b/roms/seabios/src/fw/shadow.c
new file mode 100644
index 00000000..4f00006b
--- /dev/null
+++ b/roms/seabios/src/fw/shadow.c
@@ -0,0 +1,171 @@
+// 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
+
+// Enable shadowing and copy bios.
+static void
+__make_bios_writable_intel(u16 bdf, u32 pam0)
+{
+ // Make ram from 0xc0000-0xf0000 writable
+ int clear = 0;
+ int i;
+ for (i=0; i<6; i++) {
+ u32 pam = pam0 + 1 + i;
+ int reg = pci_config_readb(bdf, pam);
+ if (CONFIG_OPTIONROMS_DEPLOYED && (reg & 0x11) != 0x11) {
+ // Need to copy optionroms to work around qemu implementation
+ void *mem = (void*)(BUILD_ROM_START + i * 32*1024);
+ memcpy((void*)BUILD_BIOS_TMP_ADDR, mem, 32*1024);
+ pci_config_writeb(bdf, pam, 0x33);
+ memcpy(mem, (void*)BUILD_BIOS_TMP_ADDR, 32*1024);
+ clear = 1;
+ } else {
+ pci_config_writeb(bdf, pam, 0x33);
+ }
+ }
+ if (clear)
+ memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024);
+
+ // Make ram from 0xf0000-0x100000 writable
+ int reg = pci_config_readb(bdf, pam0);
+ pci_config_writeb(bdf, pam0, 0x30);
+ if (reg & 0x10)
+ // Ram already present.
+ return;
+
+ // Copy bios.
+ extern u8 code32flat_start[], code32flat_end[];
+ memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
+ , code32flat_end - 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 wont 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();
+
+ // 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;
+ u32 pam = pam0 + 1 + i;
+ if (romlast < mem + 16*1024 || rommax < mem + 32*1024) {
+ if (romlast >= mem && rommax >= mem + 16*1024)
+ pci_config_writeb(bdf, pam, 0x31);
+ break;
+ }
+ pci_config_writeb(bdf, pam, 0x11);
+ }
+
+ // Write protect 0xf0000-0x100000
+ pci_config_writeb(bdf, pam0, 0x10);
+}
+
+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);
+ 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);
+ 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_prep_reset(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.
+ make_bios_writable();
+ extern u8 code32flat_start[], code32flat_end[];
+ memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
+ , code32flat_end - code32flat_start);
+}
diff --git a/roms/seabios/src/fw/smbios.c b/roms/seabios/src/fw/smbios.c
new file mode 100644
index 00000000..dba05413
--- /dev/null
+++ b/roms/seabios/src/fw/smbios.c
@@ -0,0 +1,585 @@
+// 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));
+ memcpy(ep.anchor_string, "_SM_", 4);
+ 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++;
+
+ 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/src/fw/smm.c b/roms/seabios/src/fw/smm.c
new file mode 100644
index 00000000..6cb484e7
--- /dev/null
+++ b/roms/seabios/src/fw/smm.c
@@ -0,0 +1,259 @@
+// 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/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;
+ u8 stack[0x7c00];
+ 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);
+ dprintf(DEBUG_HDL_smi, "handle_smi cmd=%x smbase=%p\n", cmd, smm);
+
+ if (smm == (void*)BUILD_SMM_INIT_ADDR) {
+ // relocate SMBASE to 0xa0000
+ u32 rev = smm->cpu.i32.smm_rev & SMM_REV_MASK;
+ if (rev == SMM_REV_I32) {
+ smm->cpu.i32.smm_base = BUILD_SMM_ADDR;
+ } else if (rev == SMM_REV_I64) {
+ 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 (smm->cpu.i32.smm_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];
+ } 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));
+ smm->cpu.i32.eip = regs[3];
+ }
+ } else if (smm->cpu.i64.smm_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];
+ } 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));
+ 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(acpi_pm_base + PIIX_PMIO_GLBCTL, value | PIIX_PMIO_GLBCTL_SMI_EN);
+
+ 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/src/fw/smp.c b/roms/seabios/src/fw/smp.c
new file mode 100644
index 00000000..a466ea6e
--- /dev/null
+++ b/roms/seabios/src/fw/smp.c
@@ -0,0 +1,153 @@
+// 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
+#include "x86.h" // wrmsr
+
+#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
+
+static struct { u32 index; u64 val; } smp_mtrr[32];
+static u32 smp_mtrr_count;
+
+void
+wrmsr_smp(u32 index, u64 val)
+{
+ wrmsr(index, val);
+ if (smp_mtrr_count >= ARRAY_SIZE(smp_mtrr)) {
+ warn_noalloc();
+ return;
+ }
+ smp_mtrr[smp_mtrr_count].index = index;
+ smp_mtrr[smp_mtrr_count].val = val;
+ smp_mtrr_count++;
+}
+
+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)));
+}
+
+void VISIBLE32FLAT
+handle_smp(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ // Enable CPU caching
+ setcr0(getcr0() & ~(CR0_CD|CR0_NW));
+
+ // Detect apic_id
+ u32 eax, ebx, ecx, cpuid_features;
+ cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+ u8 apic_id = ebx>>24;
+ dprintf(DEBUG_HDL_smp, "handle_smp: apic_id=%d\n", apic_id);
+
+ // MTRR setup
+ int i;
+ for (i=0; i<smp_mtrr_count; i++)
+ wrmsr(smp_mtrr[i].index, smp_mtrr[i].val);
+
+ // Set bit on FoundAPICIDs
+ FoundAPICIDs[apic_id/32] |= (1 << (apic_id % 32));
+
+ 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
+void
+smp_setup(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ 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;
+ MaxCountCPUs = 1;
+ return;
+ }
+
+ // mark the BSP initial APIC ID as found, too:
+ u8 apic_id = ebx>>24;
+ FoundAPICIDs[apic_id/32] |= (1 << (apic_id % 32));
+ 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);
+
+ // Wait for other CPUs to process the SIPI.
+ u8 cmos_smp_count = rtc_read(CMOS_BIOS_SMP_COUNT) + 1;
+ while (cmos_smp_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;
+
+ MaxCountCPUs = romfile_loadint("etc/max-cpus", 0);
+ if (!MaxCountCPUs || MaxCountCPUs < CountCPUs)
+ MaxCountCPUs = CountCPUs;
+
+ dprintf(1, "Found %d cpu(s) max supported %d cpu(s)\n", CountCPUs,
+ MaxCountCPUs);
+}
diff --git a/roms/seabios/src/fw/ssdt-misc.dsl b/roms/seabios/src/fw/ssdt-misc.dsl
new file mode 100644
index 00000000..acc850e8
--- /dev/null
+++ b/roms/seabios/src/fw/ssdt-misc.dsl
@@ -0,0 +1,104 @@
+ACPI_EXTRACT_ALL_CODE ssdp_misc_aml
+
+DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 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/src/fw/ssdt-pcihp.dsl b/roms/seabios/src/fw/ssdt-pcihp.dsl
new file mode 100644
index 00000000..cb24c11c
--- /dev/null
+++ b/roms/seabios/src/fw/ssdt-pcihp.dsl
@@ -0,0 +1,36 @@
+ACPI_EXTRACT_ALL_CODE ssdp_pcihp_aml
+
+DefinitionBlock ("ssdt-pcihp.aml", "SSDT", 0x01, "BXPC", "BXSSDTPCIHP", 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/src/fw/ssdt-proc.dsl b/roms/seabios/src/fw/ssdt-proc.dsl
new file mode 100644
index 00000000..407d61ea
--- /dev/null
+++ b/roms/seabios/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/src/fw/xen.c b/roms/seabios/src/fw/xen.c
new file mode 100644
index 00000000..dd8e8afd
--- /dev/null
+++ b/roms/seabios/src/fw/xen.c
@@ -0,0 +1,147 @@
+// Xen HVM support
+//
+// Copyright (C) 2011 Citrix Systems.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h"
+#include "hw/serialio.h" // DebugOutputPort
+#include "malloc.h" // memalign_high
+#include "memmap.h" // add_e820
+#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"
+
+#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. */
+ 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];
+ add_e820(e->start, e->size, e->type);
+ }
+}
diff --git a/roms/seabios/src/fw/xen.h b/roms/seabios/src/fw/xen.h
new file mode 100644
index 00000000..f00f8407
--- /dev/null
+++ b/roms/seabios/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/src/gen-defs.h b/roms/seabios/src/gen-defs.h
new file mode 100644
index 00000000..dabf64cd
--- /dev/null
+++ b/roms/seabios/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/src/hw/ahci.c b/roms/seabios/src/hw/ahci.c
new file mode 100644
index 00000000..3193d81a
--- /dev/null
+++ b/roms/seabios/src/hw/ahci.c
@@ -0,0 +1,639 @@
+// 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" // 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)
+{
+ u32 addr = ctrl->iobase + reg;
+ return readl((void*)addr);
+}
+
+static void ahci_ctrl_writel(struct ahci_ctrl_s *ctrl, u32 reg, u32 val)
+{
+ u32 addr = ctrl->iobase + reg;
+ writel((void*)addr, 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_SCR_ACT, 1);
+ 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_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ if (! CONFIG_AHCI)
+ return 0;
+
+ struct ahci_port_s *port_gf = container_of(
+ op->drive_gf, struct ahci_port_s, drive);
+ struct ahci_cmd_s *cmd = port_gf->cmd;
+ u8 *atapi = cdbcmd;
+ int i, rc;
+
+ sata_prep_atapi(&cmd->fis, blocksize);
+ for (i = 0; i < CDROM_CDB_SIZE; i++) {
+ cmd->atapi[i] = atapi[i];
+ }
+ rc = ahci_command(port_gf, 0, 1, op->buf_fl,
+ op->count * blocksize);
+ 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_gf, 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 VISIBLE32FLAT
+process_ahci_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);
+ case CMD_FORMAT:
+ case CMD_RESET:
+ case CMD_ISREADY:
+ case CMD_VERIFY:
+ case CMD_SEEK:
+ return DISK_RET_SUCCESS;
+ default:
+ dprintf(1, "AHCI: unknown disk command %d\n", op->command);
+ return DISK_RET_EPARAM;
+ }
+}
+
+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;
+ }
+ 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);
+ 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);
+
+ 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);
+ } 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);
+ }
+ 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_ctrl_s *ctrl = malloc_fseg(sizeof(*ctrl));
+ struct ahci_port_s *port;
+ u16 bdf = pci->bdf;
+ u32 val, pnr, max;
+
+ if (!ctrl) {
+ warn_noalloc();
+ return;
+ }
+
+ if (create_bounce_buf() < 0) {
+ warn_noalloc();
+ free(ctrl);
+ return;
+ }
+
+ ctrl->pci_tmp = pci;
+ ctrl->pci_bdf = bdf;
+ ctrl->iobase = pci_config_readl(bdf, PCI_BASE_ADDRESS_5);
+ ctrl->irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+ dprintf(1, "AHCI controller at %02x.%x, iobase %x, irq %d\n",
+ bdf >> 3, bdf & 7, ctrl->iobase, ctrl->irq);
+
+ pci_config_maskw(bdf, PCI_COMMAND, 0,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ 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/src/hw/ahci.h b/roms/seabios/src/hw/ahci.h
new file mode 100644
index 00000000..c8c755a3
--- /dev/null
+++ b/roms/seabios/src/hw/ahci.h
@@ -0,0 +1,202 @@
+#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;
+ u16 pci_bdf;
+ u8 irq;
+ u32 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 process_ahci_op(struct disk_op_s *op);
+int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+
+#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/src/hw/ata.c b/roms/seabios/src/hw/ata.c
new file mode 100644
index 00000000..d805706d
--- /dev/null
+++ b/roms/seabios/src/hw/ata.c
@@ -0,0 +1,1043 @@
+// 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" // 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, u16 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(u16 base)
+{
+ return await_ide(ATA_CB_STAT_BSY, 0, base, IDE_TIMEOUT);
+}
+
+// Wait for the device to be ready.
+static int
+await_rdy(u16 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(u16 iobase1, u16 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(u16 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);
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u16 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);
+ u16 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);
+ u16 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(u16 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);
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u16 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_gf'.
+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_gf, iswrite, op->count, blocksize, op->buf_fl);
+
+ struct atadrive_s *adrive_gf = container_of(
+ op->drive_gf, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u16 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_gf, 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_gf, 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)
+{
+ ASSERT16();
+ if (! CONFIG_ATA_DMA)
+ return -1;
+ 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_gf, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ u16 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_gf, op->buf_fl);
+
+ struct atadrive_s *adrive_gf = container_of(
+ op->drive_gf, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ u16 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);
+
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u16 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_gf, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u16 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_gf, 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
+process_ata_op(struct disk_op_s *op)
+{
+ if (!CONFIG_ATA)
+ return 0;
+
+ struct atadrive_s *adrive_gf = container_of(
+ op->drive_gf, 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);
+ case CMD_FORMAT:
+ case CMD_VERIFY:
+ case CMD_SEEK:
+ return DISK_RET_SUCCESS;
+ default:
+ return DISK_RET_EPARAM;
+ }
+}
+
+
+/****************************************************************
+ * ATAPI functions
+ ****************************************************************/
+
+#define CDROM_CDB_SIZE 12
+
+// Low-level atapi command transmit function.
+int
+atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ if (! CONFIG_ATA)
+ return 0;
+
+ struct atadrive_s *adrive_gf = container_of(
+ op->drive_gf, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u16 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_gf = &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] = 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->chanid * 2 + dummy->slave;
+ adrive->drive.removable = (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 = ((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->chanid, 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_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 = buffer[1];
+ adrive->drive.pchs.head = buffer[3];
+ adrive->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
+ 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->chanid, 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);
+ // 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(u16 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.
+ u16 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->chanid, 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 = 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 irq
+ , u32 port1, u32 port2, u32 master)
+{
+ static int chanid = 0;
+ struct ata_channel_s *chan_gf = malloc_fseg(sizeof(*chan_gf));
+ if (!chan_gf) {
+ warn_noalloc();
+ return;
+ }
+ 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"
+ , chanid, 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)
+{
+ pci->have_driver = 1;
+ u16 bdf = pci->bdf;
+ u8 pciirq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+ int master = 0;
+ if (CONFIG_ATA_DMA && prog_if & 0x80) {
+ // Check for bus-mastering.
+ u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_4);
+ if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
+ master = bar & PCI_BASE_ADDRESS_IO_MASK;
+ pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+ }
+ }
+
+ u32 port1, port2, irq;
+ if (prog_if & 1) {
+ port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_0)
+ & PCI_BASE_ADDRESS_IO_MASK);
+ port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_1)
+ & PCI_BASE_ADDRESS_IO_MASK);
+ irq = pciirq;
+ } else {
+ port1 = PORT_ATA1_CMD_BASE;
+ port2 = PORT_ATA1_CTRL_BASE;
+ irq = IRQ_ATA1;
+ }
+ init_controller(pci, irq, port1, port2, master);
+
+ if (prog_if & 4) {
+ port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_2)
+ & PCI_BASE_ADDRESS_IO_MASK);
+ port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_3)
+ & PCI_BASE_ADDRESS_IO_MASK);
+ irq = pciirq;
+ } else {
+ port1 = PORT_ATA2_CMD_BASE;
+ port2 = PORT_ATA2_CTRL_BASE;
+ irq = IRQ_ATA2;
+ }
+ init_controller(pci, 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, IRQ_ATA1
+ , PORT_ATA1_CMD_BASE, PORT_ATA1_CTRL_BASE, 0);
+ init_controller(NULL, 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/src/hw/ata.h b/roms/seabios/src/hw/ata.h
new file mode 100644
index 00000000..c73892bb
--- /dev/null
+++ b/roms/seabios/src/hw/ata.h
@@ -0,0 +1,158 @@
+#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 {
+ u16 iobase1;
+ u16 iobase2;
+ u16 iomaster;
+ u8 irq;
+ u8 chanid;
+ 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 cdrom_read(struct disk_op_s *op);
+int atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+void ata_setup(void);
+int process_ata_op(struct disk_op_s *op);
+
+#define PORT_ATA2_CMD_BASE 0x0170
+#define PORT_ATA1_CMD_BASE 0x01f0
+#define PORT_ATA2_CTRL_BASE 0x0374
+#define PORT_ATA1_CTRL_BASE 0x03f4
+
+// 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
+
+#endif // ata.h
diff --git a/roms/seabios/src/hw/blockcmd.c b/roms/seabios/src/hw/blockcmd.c
new file mode 100644
index 00000000..78c0e65f
--- /dev/null
+++ b/roms/seabios/src/hw/blockcmd.c
@@ -0,0 +1,319 @@
+// 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 "ahci.h" // atapi_cmd_data
+#include "ata.h" // atapi_cmd_data
+#include "biosvar.h" // GET_GLOBALFLAT
+#include "block.h" // struct disk_op_s
+#include "blockcmd.h" // struct cdb_request_sense
+#include "byteorder.h" // be32_to_cpu
+#include "esp-scsi.h" // esp_scsi_cmd_data
+#include "lsi-scsi.h" // lsi_scsi_cmd_data
+#include "megasas.h" // megasas_cmd_data
+#include "pvscsi.h" // pvscsi_cmd_data
+#include "output.h" // dprintf
+#include "std/disk.h" // DISK_RET_EPARAM
+#include "string.h" // memset
+#include "usb-msc.h" // usb_cmd_data
+#include "usb-uas.h" // usb_cmd_data
+#include "util.h" // timer_calc
+#include "virtio-scsi.h" // virtio_scsi_cmd_data
+
+// Route command to low-level handler.
+static int
+cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ u8 type = GET_GLOBALFLAT(op->drive_gf->type);
+ switch (type) {
+ case DTYPE_ATA_ATAPI:
+ return atapi_cmd_data(op, cdbcmd, blocksize);
+ case DTYPE_USB:
+ return usb_cmd_data(op, cdbcmd, blocksize);
+ case DTYPE_UAS:
+ return uas_cmd_data(op, cdbcmd, blocksize);
+ case DTYPE_VIRTIO_SCSI:
+ return virtio_scsi_cmd_data(op, cdbcmd, blocksize);
+ case DTYPE_LSI_SCSI:
+ return lsi_scsi_cmd_data(op, cdbcmd, blocksize);
+ case DTYPE_ESP_SCSI:
+ return esp_scsi_cmd_data(op, cdbcmd, blocksize);
+ case DTYPE_MEGASAS:
+ return megasas_cmd_data(op, cdbcmd, blocksize);
+ case DTYPE_USB_32:
+ if (!MODESEGMENT)
+ return usb_cmd_data(op, cdbcmd, blocksize);
+ case DTYPE_UAS_32:
+ if (!MODESEGMENT)
+ return uas_cmd_data(op, cdbcmd, blocksize);
+ case DTYPE_PVSCSI:
+ if (!MODESEGMENT)
+ return pvscsi_cmd_data(op, cdbcmd, blocksize);
+ case DTYPE_AHCI_ATAPI:
+ if (!MODESEGMENT)
+ return ahci_cmd_data(op, cdbcmd, blocksize);
+ default:
+ return DISK_RET_EPARAM;
+ }
+}
+
+// Determine if the command is a request to pull data from the device
+int
+cdb_is_read(u8 *cdbcmd, u16 blocksize)
+{
+ return blocksize && cdbcmd[0] != CDB_CMD_WRITE_10;
+}
+
+
+/****************************************************************
+ * 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->count = 1;
+ op->buf_fl = data;
+ return cdb_cmd_data(op, &cmd, sizeof(*data));
+}
+
+// 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->count = 1;
+ op->buf_fl = data;
+ return cdb_cmd_data(op, &cmd, sizeof(*data));
+}
+
+// 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->count = 0;
+ op->buf_fl = NULL;
+ return cdb_cmd_data(op, &cmd, 0);
+}
+
+// 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->count = 1;
+ op->buf_fl = data;
+ return cdb_cmd_data(op, &cmd, sizeof(*data));
+}
+
+// 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->count = 1;
+ op->buf_fl = data;
+ return cdb_cmd_data(op, &cmd, sizeof(*data));
+}
+
+// Read sectors.
+static int
+cdb_read(struct disk_op_s *op)
+{
+ struct cdb_rwdata_10 cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.command = CDB_CMD_READ_10;
+ cmd.lba = cpu_to_be32(op->lba);
+ cmd.count = cpu_to_be16(op->count);
+ return cdb_cmd_data(op, &cmd, GET_GLOBALFLAT(op->drive_gf->blksize));
+}
+
+// Write sectors.
+static int
+cdb_write(struct disk_op_s *op)
+{
+ struct cdb_rwdata_10 cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.command = CDB_CMD_WRITE_10;
+ cmd.lba = cpu_to_be32(op->lba);
+ cmd.count = cpu_to_be16(op->count);
+ return cdb_cmd_data(op, &cmd, GET_GLOBALFLAT(op->drive_gf->blksize));
+}
+
+
+/****************************************************************
+ * Main SCSI commands
+ ****************************************************************/
+
+int VISIBLE32FLAT
+scsi_process_op(struct disk_op_s *op)
+{
+ switch (op->command) {
+ case CMD_READ:
+ return cdb_read(op);
+ case CMD_WRITE:
+ return cdb_write(op);
+ case CMD_FORMAT:
+ case CMD_RESET:
+ case CMD_ISREADY:
+ case CMD_VERIFY:
+ case CMD_SEEK:
+ return DISK_RET_SUCCESS;
+ default:
+ return DISK_RET_EPARAM;
+ }
+}
+
+int
+scsi_is_ready(struct disk_op_s *op)
+{
+ dprintf(6, "scsi_is_ready (drive=%p)\n", op->drive_gf);
+
+ /* Retry TEST UNIT READY for 5 seconds unless MEDIUM NOT PRESENT is
+ * reported by the device. If the device reports "IN PROGRESS",
+ * 30 seconds is added. */
+ 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 */
+ dprintf(1, "Device reports MEDIUM NOT PRESENT\n");
+ return -1;
+ }
+
+ if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) {
+ /* IN PROGRESS OF BECOMING READY */
+ printf("Waiting for device to detect medium... ");
+ /* Allow 30 seconds more */
+ end = timer_calc(30000);
+ in_progress = 1;
+ }
+ }
+ return 0;
+}
+
+// Validate drive, find block size / sector count, and register drive.
+int
+scsi_drive_setup(struct drive_s *drive, const char *s, int prio)
+{
+ struct disk_op_s dop;
+ memset(&dop, 0, sizeof(dop));
+ dop.drive_gf = 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;
+ }
+
+ 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=%d\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/src/hw/blockcmd.h b/roms/seabios/src/hw/blockcmd.h
new file mode 100644
index 00000000..df12a6d4
--- /dev/null
+++ b/roms/seabios/src/hw/blockcmd.h
@@ -0,0 +1,110 @@
+// 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
+int cdb_is_read(u8 *cdbcmd, u16 blocksize);
+struct disk_op_s;
+int scsi_process_op(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);
+
+#endif // blockcmd.h
diff --git a/roms/seabios/src/hw/dma.c b/roms/seabios/src/hw/dma.c
new file mode 100644
index 00000000..20c9fbb7
--- /dev/null
+++ b/roms/seabios/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/src/hw/esp-scsi.c b/roms/seabios/src/hw/esp-scsi.c
new file mode 100644
index 00000000..33cc4498
--- /dev/null
+++ b/roms/seabios/src/hw/esp-scsi.c
@@ -0,0 +1,238 @@
+// 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 "pci.h" // foreachpci
+#include "pci_ids.h" // PCI_DEVICE_ID
+#include "pci_regs.h" // PCI_VENDOR_ID
+#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);
+}
+
+static int
+esp_scsi_cmd(struct esp_lun_s *llun_gf, struct disk_op_s *op,
+ u8 *cdbcmd, u16 target, u16 lun, u16 blocksize)
+{
+ 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,
+ cdb_is_read(cdbcmd, blocksize));
+ 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;
+}
+
+int
+esp_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ if (!CONFIG_ESP_SCSI)
+ return DISK_RET_EBADTRACK;
+
+ struct esp_lun_s *llun_gf =
+ container_of(op->drive_gf, struct esp_lun_s, drive);
+
+ return esp_scsi_cmd(llun_gf, op, cdbcmd,
+ GET_GLOBALFLAT(llun_gf->target),
+ GET_GLOBALFLAT(llun_gf->lun),
+ blocksize);
+}
+
+static int
+esp_scsi_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun)
+{
+ struct esp_lun_s *llun = malloc_fseg(sizeof(*llun));
+ if (!llun) {
+ warn_noalloc();
+ return -1;
+ }
+ 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;
+
+ char *name = znprintf(16, "esp %02x:%02x.%x %d:%d",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ pci_bdf_to_fn(pci->bdf), target, lun);
+ int prio = bootprio_find_scsi_device(pci, target, lun);
+ int ret = scsi_drive_setup(&llun->drive, name, prio);
+ 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)
+{
+ esp_scsi_add_lun(pci, iobase, target, 0);
+}
+
+static void
+init_esp_scsi(struct pci_device *pci)
+{
+ u16 bdf = pci->bdf;
+ u32 iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
+ & PCI_BASE_ADDRESS_IO_MASK;
+
+ dprintf(1, "found esp at %02x:%02x.%x, io @ %x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ pci_bdf_to_fn(bdf), iobase);
+
+ pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+
+ // reset
+ outb(ESP_CMD_RESET, iobase + ESP_CMD);
+
+ int i;
+ for (i = 0; i <= 7; i++)
+ esp_scsi_scan_target(pci, iobase, i);
+
+ return;
+}
+
+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;
+ init_esp_scsi(pci);
+ }
+}
diff --git a/roms/seabios/src/hw/esp-scsi.h b/roms/seabios/src/hw/esp-scsi.h
new file mode 100644
index 00000000..dc555f39
--- /dev/null
+++ b/roms/seabios/src/hw/esp-scsi.h
@@ -0,0 +1,8 @@
+#ifndef __ESP_SCSI_H
+#define __ESP_SCSI_H
+
+struct disk_op_s;
+int esp_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+void esp_scsi_setup(void);
+
+#endif /* __ESP_SCSI_H */
diff --git a/roms/seabios/src/hw/floppy.c b/roms/seabios/src/hw/floppy.c
new file mode 100644
index 00000000..d60362a3
--- /dev/null
+++ b/roms/seabios/src/hw/floppy.c
@@ -0,0 +1,673 @@
+// 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 "pci.h" // pci_to_bdf
+#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
+
+// 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 = 0xAF, // step rate 12ms, head unload 240ms
+ .specify2 = 0x02, // head load time 4ms, DMA used
+ .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 = 0x08, // 1 second
+ },
+ .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 void
+floppy_dor_write(u8 val)
+{
+ outb(val, PORT_FD_DOR);
+ SET_LOW(FloppyDOR, val);
+}
+
+static void
+floppy_disable_controller(void)
+{
+ dprintf(2, "Floppy_disable_controller\n");
+ floppy_dor_write(0x00);
+}
+
+static int
+floppy_wait_irq(void)
+{
+ u8 frs = GET_BDA(floppy_recalibration_status);
+ SET_BDA(floppy_recalibration_status, frs & ~FRS_IRQ);
+ for (;;) {
+ if (!GET_BDA(floppy_motor_counter)) {
+ 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)
+
+// 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");
+ SET_BDA(floppy_motor_counter, FLOPPY_MOTOR_TICKS);
+ floppy_dor_write(0x00);
+ floppy_dor_write(0x0c);
+ int ret = floppy_wait_irq();
+ if (ret)
+ return ret;
+
+ u8 param[2];
+ return floppy_pio(FC_CHECKIRQ, param);
+}
+
+// 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 (!(GET_LOW(FloppyDOR) & 0x04)) {
+ int ret = floppy_enable_controller();
+ if (ret)
+ return ret;
+ }
+
+ // reset the disk motor timeout value of INT 08
+ SET_BDA(floppy_motor_counter, FLOPPY_MOTOR_TICKS);
+
+ // Turn on motor of selected drive, DMA & int enabled, normal operation
+ floppy_dor_write((floppyid ? 0x20 : 0x10) | 0x0c | floppyid);
+
+ // Send command.
+ int ret = floppy_pio(command, param);
+ 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_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;
+ }
+
+ // 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_gf->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_gf->lchs.sector);
+ res.sector = (tmp % nls) + 1;
+
+ tmp /= nls;
+ u16 nlh = GET_GLOBALFLAT(op->drive_gf->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_gf, chs.cylinder);
+ if (ret)
+ return ret;
+
+ // send read-normal-data command to controller
+ u8 floppyid = GET_GLOBALFLAT(op->drive_gf->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_gf, chs.cylinder);
+ if (ret)
+ return ret;
+
+ // send write-normal-data command to controller
+ u8 floppyid = GET_GLOBALFLAT(op->drive_gf->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_gf, 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_gf, chs.cylinder);
+ if (ret)
+ return ret;
+
+ // send format-track command to controller
+ u8 floppyid = GET_GLOBALFLAT(op->drive_gf->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
+process_floppy_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_write(GET_LOW(FloppyDOR) & ~0xf0);
+ }
+}
diff --git a/roms/seabios/src/hw/lsi-scsi.c b/roms/seabios/src/hw/lsi-scsi.c
new file mode 100644
index 00000000..b1d6bbf4
--- /dev/null
+++ b/roms/seabios/src/hw/lsi-scsi.c
@@ -0,0 +1,217 @@
+// (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 "fw/paravirt.h" // runningOnQEMU
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "pci.h" // foreachpci
+#include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
+#include "pci_regs.h" // PCI_VENDOR_ID
+#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;
+};
+
+static int
+lsi_scsi_cmd(struct lsi_lun_s *llun_gf, struct disk_op_s *op,
+ void *cdbcmd, u16 target, u16 lun, u16 blocksize)
+{
+ u32 iobase = GET_GLOBALFLAT(llun_gf->iobase);
+ u32 dma = ((cdb_is_read(cdbcmd, blocksize) ? 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);
+
+ 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;
+}
+
+int
+lsi_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ if (!CONFIG_LSI_SCSI)
+ return DISK_RET_EBADTRACK;
+
+ struct lsi_lun_s *llun_gf =
+ container_of(op->drive_gf, struct lsi_lun_s, drive);
+
+ return lsi_scsi_cmd(llun_gf, op, cdbcmd,
+ GET_GLOBALFLAT(llun_gf->target),
+ GET_GLOBALFLAT(llun_gf->lun),
+ blocksize);
+}
+
+static int
+lsi_scsi_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun)
+{
+ struct lsi_lun_s *llun = malloc_fseg(sizeof(*llun));
+ if (!llun) {
+ warn_noalloc();
+ return -1;
+ }
+ 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;
+
+ char *name = znprintf(16, "lsi %02x:%02x.%x %d:%d",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ pci_bdf_to_fn(pci->bdf), target, lun);
+ int prio = bootprio_find_scsi_device(pci, target, lun);
+ int ret = scsi_drive_setup(&llun->drive, name, prio);
+ 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)
+{
+ /* TODO: send REPORT LUNS. For now, only LUN 0 is recognized. */
+ lsi_scsi_add_lun(pci, iobase, target, 0);
+}
+
+static void
+init_lsi_scsi(struct pci_device *pci)
+{
+ u16 bdf = pci->bdf;
+ u32 iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
+ & PCI_BASE_ADDRESS_IO_MASK;
+
+ pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+
+ dprintf(1, "found lsi53c895a at %02x:%02x.%x, io @ %x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ pci_bdf_to_fn(bdf), 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);
+
+ return;
+}
+
+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;
+ init_lsi_scsi(pci);
+ }
+}
diff --git a/roms/seabios/src/hw/lsi-scsi.h b/roms/seabios/src/hw/lsi-scsi.h
new file mode 100644
index 00000000..9c5a9b21
--- /dev/null
+++ b/roms/seabios/src/hw/lsi-scsi.h
@@ -0,0 +1,8 @@
+#ifndef __LSI_SCSI_H
+#define __LSI_SCSI_H
+
+struct disk_op_s;
+int lsi_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+void lsi_scsi_setup(void);
+
+#endif /* __LSI_SCSI_H */
diff --git a/roms/seabios/src/hw/megasas.c b/roms/seabios/src/hw/megasas.c
new file mode 100644
index 00000000..b2a65e48
--- /dev/null
+++ b/roms/seabios/src/hw/megasas.c
@@ -0,0 +1,404 @@
+// 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" // 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_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ struct megasas_lun_s *mlun_gf =
+ container_of(op->drive_gf, struct megasas_lun_s, drive);
+ u8 *cdb = cdbcmd;
+ struct megasas_cmd_frame *frame = GET_GLOBALFLAT(mlun_gf->frame);
+ u16 pci_id = GET_GLOBALFLAT(mlun_gf->pci_id);
+ int i;
+
+ if (!CONFIG_MEGASAS)
+ return DISK_RET_EBADTRACK;
+
+ memset_fl(frame, 0, sizeof(*frame));
+ SET_LOWFLAT(frame->cmd, MFI_CMD_LD_SCSI_IO);
+ SET_LOWFLAT(frame->cmd_status, 0xFF);
+ 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;
+ }
+ name = znprintf(36, "MegaRAID SAS (PCI %02x:%02x.%x) LD %d:%d",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ pci_bdf_to_fn(pci->bdf), target, lun);
+ prio = bootprio_find_scsi_device(pci, target, lun);
+ ret = scsi_drive_setup(&mlun->drive, name, prio);
+ 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));
+ int i;
+
+ 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);
+ 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(ioaddr + MFI_DB, mfi_flags);
+ } else {
+ outl(ioaddr + MFI_IDB, mfi_flags);
+ }
+ 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(ioaddr + MFI_DB, mfi_flags);
+ 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 {
+ outw(ioaddr + MFI_IDB, mfi_flags);
+ }
+ 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(struct pci_device *pci)
+{
+ u16 bdf = pci->bdf;
+ u32 iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_2)
+ & PCI_BASE_ADDRESS_IO_MASK;
+
+ if (!iobase)
+ iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
+ & PCI_BASE_ADDRESS_IO_MASK;
+
+ dprintf(1, "found MegaRAID SAS at %02x:%02x.%x, io @ %x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ pci_bdf_to_fn(bdf), iobase);
+
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ // reset
+ if (megasas_transition_to_ready(pci, iobase) == 0)
+ megasas_scan_target(pci, iobase);
+
+ return;
+}
+
+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)
+ init_megasas(pci);
+ }
+}
diff --git a/roms/seabios/src/hw/megasas.h b/roms/seabios/src/hw/megasas.h
new file mode 100644
index 00000000..124042e1
--- /dev/null
+++ b/roms/seabios/src/hw/megasas.h
@@ -0,0 +1,8 @@
+#ifndef __MEGASAS_H
+#define __MEGASAS_H
+
+struct disk_op_s;
+int megasas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+void megasas_setup(void);
+
+#endif /* __MEGASAS_H */
diff --git a/roms/seabios/src/hw/pci.c b/roms/seabios/src/hw/pci.c
new file mode 100644
index 00000000..0379b558
--- /dev/null
+++ b/roms/seabios/src/hw/pci.c
@@ -0,0 +1,277 @@
+// 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 "malloc.h" // malloc_tmp
+#include "output.h" // dprintf
+#include "pci.h" // pci_config_writel
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "romfile.h" // romfile_loadint
+#include "string.h" // memset
+#include "util.h" // udelay
+#include "x86.h" // outl
+
+void pci_config_writel(u16 bdf, u32 addr, u32 val)
+{
+ outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+ outl(val, PORT_PCI_DATA);
+}
+
+void pci_config_writew(u16 bdf, u32 addr, u16 val)
+{
+ outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+ outw(val, PORT_PCI_DATA + (addr & 2));
+}
+
+void pci_config_writeb(u16 bdf, u32 addr, u8 val)
+{
+ outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+ outb(val, PORT_PCI_DATA + (addr & 3));
+}
+
+u32 pci_config_readl(u16 bdf, u32 addr)
+{
+ outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+ return inl(PORT_PCI_DATA);
+}
+
+u16 pci_config_readw(u16 bdf, u32 addr)
+{
+ outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+ return inw(PORT_PCI_DATA + (addr & 2));
+}
+
+u8 pci_config_readb(u16 bdf, u32 addr)
+{
+ outl(0x80000000 | (bdf << 8) | (addr & 0xfc), 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);
+}
+
+// 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;
+ }
+}
+
+struct hlist_head PCIDevices VARVERIFY32INIT;
+int MaxPCIBus VARFSEG;
+
+// 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;
+}
+
+// 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 %02x:%02x.%x (vd=%04x:%04x c=%04x)\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
+ , pci_bdf_to_fn(bdf)
+ , 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;
+}
+
+u8 pci_find_capability(struct pci_device *pci, u8 cap_id)
+{
+ int i;
+ u8 cap;
+ u16 status = pci_config_readw(pci->bdf, PCI_STATUS);
+
+ if (!(status & PCI_STATUS_CAP_LIST))
+ return 0;
+
+ cap = pci_config_readb(pci->bdf, PCI_CAPABILITY_LIST);
+ for (i = 0; cap && i <= 0xff; i++) {
+ if (pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_ID) == cap_id)
+ return cap;
+ cap = pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_NEXT);
+ }
+
+ return 0;
+}
+
+/* Test whether bridge support forwarding of transactions
+ * of a specific type.
+ * Note: disables bridge's window registers as a side effect.
+ */
+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;
+}
+
+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/src/hw/pci.h b/roms/seabios/src/hw/pci.h
new file mode 100644
index 00000000..0aaa84c1
--- /dev/null
+++ b/roms/seabios/src/hw/pci.h
@@ -0,0 +1,131 @@
+#ifndef __PCI_H
+#define __PCI_H
+
+#include "types.h" // u32
+#include "list.h" // hlist_node
+
+#define PORT_PCI_CMD 0x0cf8
+#define PORT_PCI_REBOOT 0x0cf9
+#define PORT_PCI_DATA 0x0cfc
+
+#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 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;
+}
+
+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);
+
+struct pci_device *pci_find_device(u16 vendid, u16 devid);
+struct pci_device *pci_find_class(u16 classid);
+
+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 u64 pcimem_start, pcimem_end;
+extern u64 pcimem64_start, pcimem64_end;
+extern struct hlist_head PCIDevices;
+extern int MaxPCIBus;
+int pci_probe_host(void);
+void pci_probe_devices(void);
+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)
+
+int pci_next(int bdf, int bus);
+#define foreachbdf(BDF, BUS) \
+ for (BDF=pci_next(pci_bus_devfn_to_bdf((BUS), 0)-1, (BUS)) \
+ ; BDF >= 0 \
+ ; BDF=pci_next(BDF, (BUS)))
+
+#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, \
+ }
+
+int pci_init_device(const struct pci_device_id *ids
+ , struct pci_device *pci, void *arg);
+struct pci_device *pci_find_init_device(const struct pci_device_id *ids
+ , void *arg);
+u8 pci_find_capability(struct pci_device *pci, u8 cap_id);
+int pci_bridge_has_region(struct pci_device *pci,
+ enum pci_region_type region_type);
+void pci_reboot(void);
+
+#endif
diff --git a/roms/seabios/src/hw/pci_ids.h b/roms/seabios/src/hw/pci_ids.h
new file mode 100644
index 00000000..1cd4f726
--- /dev/null
+++ b/roms/seabios/src/hw/pci_ids.h
@@ -0,0 +1,2623 @@
+/*
+ * 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_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_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
+#define PCI_DEVICE_ID_VIRTIO_BLK 0x1001
+#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004
+
+#define PCI_VENDOR_ID_VMWARE 0x15ad
+#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0
diff --git a/roms/seabios/src/hw/pci_regs.h b/roms/seabios/src/hw/pci_regs.h
new file mode 100644
index 00000000..e5effd47
--- /dev/null
+++ b/roms/seabios/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/src/hw/pic.c b/roms/seabios/src/hw/pic.c
new file mode 100644
index 00000000..6ff69676
--- /dev/null
+++ b/roms/seabios/src/hw/pic.c
@@ -0,0 +1,101 @@
+// 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)
+{
+ return inb(PORT_PIC1_DATA) | (inb(PORT_PIC2_DATA) << 8);
+}
+
+void
+pic_irqmask_write(u16 mask)
+{
+ outb(mask, PORT_PIC1_DATA);
+ outb(mask >> 8, PORT_PIC2_DATA);
+}
+
+void
+pic_irqmask_mask(u16 off, u16 on)
+{
+ 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)
+{
+ // 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)
+{
+ 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)
+{
+ // 0x0b == select OCW1 + read ISR
+ outb(0x0b, PORT_PIC1_CMD);
+ return inb(PORT_PIC1_CMD);
+}
+
+static u8
+pic_isr2_read(void)
+{
+ // 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(struct bregs *regs)
+{
+ dprintf(DEBUG_ISR_hwpic1, "handle_hwpic1 irq=%x\n", pic_isr1_read());
+ pic_eoi1();
+}
+
+void VISIBLE16
+handle_hwpic2(struct bregs *regs)
+{
+ dprintf(DEBUG_ISR_hwpic2, "handle_hwpic2 irq=%x\n", pic_isr2_read());
+ pic_eoi2();
+}
diff --git a/roms/seabios/src/hw/pic.h b/roms/seabios/src/hw/pic.h
new file mode 100644
index 00000000..6947b6e8
--- /dev/null
+++ b/roms/seabios/src/hw/pic.h
@@ -0,0 +1,56 @@
+// 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)
+{
+ // Send eoi (select OCW2 + eoi)
+ outb(0x20, PORT_PIC1_CMD);
+}
+
+static inline void
+pic_eoi2(void)
+{
+ // 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/src/hw/ps2port.c b/roms/seabios/src/hw/ps2port.c
new file mode 100644
index 00000000..04995c88
--- /dev/null
+++ b/roms/seabios/src/hw/ps2port.c
@@ -0,0 +1,507 @@
+// 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)) {
+ // Don't warn on second byte of a reset
+ if (timeout > 100)
+ 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;
+
+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.
+ if (aux)
+ newctr &= ~I8042_CTR_AUXDIS;
+ else
+ newctr &= ~I8042_CTR_KBDDIS;
+ ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr);
+ if (ret)
+ goto fail;
+
+ if (command == ATKBD_CMD_RESET_BAT) {
+ // Reset is special wrt timeouts and bytes received.
+
+ // 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;
+ ret = ps2_recvbyte(aux, 0, 100);
+ if (ret < 0)
+ // Some devices only respond with one byte on reset.
+ ret = 0;
+ 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.
+ 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 | I8042_CTR_AUXINT) & ~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();
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static void
+ps2_keyboard_setup(void *data)
+{
+ /* flush incoming keys */
+ int 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;
+ }
+
+ // Disable keyboard and mouse events.
+ SET_LOW(Ps2ctr, I8042_CTR_KBDDIS | I8042_CTR_AUXDIS);
+
+
+ /* ------------------- 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
+ SET_LOW(Ps2ctr, I8042_CTR_AUXDIS | I8042_CTR_XLATE | I8042_CTR_KBDINT);
+
+ /* 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;
+ 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/src/hw/ps2port.h b/roms/seabios/src/hw/ps2port.h
new file mode 100644
index 00000000..e5d9014b
--- /dev/null
+++ b/roms/seabios/src/hw/ps2port.h
@@ -0,0 +1,66 @@
+// 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 0x02ff
+
+// 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 ps2port_setup(void);
+
+#endif // ps2port.h
diff --git a/roms/seabios/src/hw/pvscsi.c b/roms/seabios/src/hw/pvscsi.c
new file mode 100644
index 00000000..601a551d
--- /dev/null
+++ b/roms/seabios/src/hw/pvscsi.c
@@ -0,0 +1,354 @@
+// 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 "output.h" // dprintf
+#include "pci.h" // foreachpci
+#include "pci_ids.h" // PCI_DEVICE_ID_VMWARE_PVSCSI
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "pvscsi.h" // pvscsi_setup
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // usleep
+#include "virtio-ring.h" // PAGE_SHIFT, virt_to_phys
+#include "x86.h" // writel
+
+#define MASK(n) ((1 << (n)) - 1)
+
+#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 = memalign_low(sizeof(*dsc), PAGE_SIZE);
+ if (!dsc) {
+ warn_noalloc();
+ return;
+ }
+
+ dsc->ring_state =
+ (struct PVSCSIRingsState *)memalign_low(PAGE_SIZE, PAGE_SIZE);
+ dsc->ring_reqs =
+ (struct PVSCSIRingReqDesc *)memalign_low(PAGE_SIZE, PAGE_SIZE);
+ dsc->ring_cmps =
+ (struct PVSCSIRingCmpDesc *)memalign_low(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 void pvscsi_fill_req(struct PVSCSIRingsState *s,
+ struct PVSCSIRingReqDesc *req,
+ u16 target, u16 lun, void *cdbcmd, u16 blocksize,
+ struct disk_op_s *op)
+{
+ req->bus = 0;
+ req->target = target;
+ memset(req->lun, 0, sizeof(req->lun));
+ req->lun[1] = lun;
+ req->senseLen = 0;
+ req->senseAddr = 0;
+ req->cdbLen = 16;
+ req->vcpuHint = 0;
+ memcpy(req->cdb, cdbcmd, 16);
+ req->tag = SIMPLE_QUEUE_TAG;
+ req->flags = cdb_is_read(cdbcmd, blocksize) ?
+ PVSCSI_FLAG_CMD_DIR_TOHOST : PVSCSI_FLAG_CMD_DIR_TODEVICE;
+
+ req->dataLen = op->count * blocksize;
+ req->dataAddr = (u32)op->buf_fl;
+ s->reqProdIdx = s->reqProdIdx + 1;
+}
+
+static u32
+pvscsi_get_rsp(struct PVSCSIRingsState *s,
+ struct PVSCSIRingCmpDesc *rsp)
+{
+ u32 status = rsp->hostStatus;
+ s->cmpConsIdx = s->cmpConsIdx + 1;
+ return status;
+}
+
+static int
+pvscsi_cmd(struct pvscsi_lun_s *plun, struct disk_op_s *op,
+ void *cdbcmd, u16 target, u16 lun, u16 blocksize)
+{
+ 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));
+ pvscsi_fill_req(s, req, target, lun, cdbcmd, blocksize, op);
+
+ 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;
+}
+
+int
+pvscsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ if (!CONFIG_PVSCSI)
+ return DISK_RET_EBADTRACK;
+
+ struct pvscsi_lun_s *plun =
+ container_of(op->drive_gf, struct pvscsi_lun_s, drive);
+
+ return pvscsi_cmd(plun, op, cdbcmd, plun->target, plun->lun, blocksize);
+}
+
+static int
+pvscsi_add_lun(struct pci_device *pci, void *iobase,
+ struct pvscsi_ring_dsc_s *ring_dsc, u8 target, u8 lun)
+{
+ 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;
+
+ char *name = znprintf(16, "pvscsi %02x:%02x.%x %d:%d",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ pci_bdf_to_fn(pci->bdf), target, lun);
+ int prio = bootprio_find_scsi_device(pci, target, lun);
+ int ret = scsi_drive_setup(&plun->drive, name, prio);
+ 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)
+{
+ /* TODO: send REPORT LUNS. For now, only LUN 0 is recognized. */
+ pvscsi_add_lun(pci, iobase, ring_dsc, target, 0);
+}
+
+static void
+init_pvscsi(struct pci_device *pci)
+{
+ struct pvscsi_ring_dsc_s *ring_dsc = NULL;
+ int i;
+ u16 bdf = pci->bdf;
+ void *iobase = (void*)(pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
+ & PCI_BASE_ADDRESS_MEM_MASK);
+
+ pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+
+ dprintf(1, "found pvscsi at %02x:%02x.%x, io @ %p\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ pci_bdf_to_fn(bdf), iobase);
+
+ pvscsi_write_cmd_desc(iobase, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
+
+ pvscsi_init_rings(iobase, &ring_dsc);
+ for (i = 0; i < 7; i++)
+ pvscsi_scan_target(pci, iobase, ring_dsc, i);
+
+ return;
+}
+
+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;
+ init_pvscsi(pci);
+ }
+}
diff --git a/roms/seabios/src/hw/pvscsi.h b/roms/seabios/src/hw/pvscsi.h
new file mode 100644
index 00000000..fde9f0b9
--- /dev/null
+++ b/roms/seabios/src/hw/pvscsi.h
@@ -0,0 +1,8 @@
+#ifndef _PVSCSI_H_
+#define _PVSCSI_H_
+
+struct disk_op_s;
+int pvscsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+void pvscsi_setup(void);
+
+#endif /* _PVSCSI_H_ */
diff --git a/roms/seabios/src/hw/ramdisk.c b/roms/seabios/src/hw/ramdisk.c
new file mode 100644
index 00000000..1177bc00
--- /dev/null
+++ b/roms/seabios/src/hw/ramdisk.c
@@ -0,0 +1,111 @@
+// 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 "malloc.h" // malloc_fseg
+#include "memmap.h" // add_e820
+#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;
+ }
+ add_e820((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 CBFS 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_gf->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
+process_ramdisk_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);
+ case CMD_VERIFY:
+ case CMD_FORMAT:
+ case CMD_RESET:
+ return DISK_RET_SUCCESS;
+ default:
+ return DISK_RET_EPARAM;
+ }
+}
diff --git a/roms/seabios/src/hw/rtc.c b/roms/seabios/src/hw/rtc.c
new file mode 100644
index 00000000..628d5429
--- /dev/null
+++ b/roms/seabios/src/hw/rtc.c
@@ -0,0 +1,93 @@
+// 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)
+{
+ 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)
+{
+ 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)
+{
+ 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)
+{
+ 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/src/hw/rtc.h b/roms/seabios/src/hw/rtc.h
new file mode 100644
index 00000000..252e73a4
--- /dev/null
+++ b/roms/seabios/src/hw/rtc.h
@@ -0,0 +1,75 @@
+#ifndef __RTC_H
+#define __RTC_H
+
+#define PORT_CMOS_INDEX 0x0070
+#define PORT_CMOS_DATA 0x0071
+
+// 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/src/hw/sdcard.c b/roms/seabios/src/hw/sdcard.c
new file mode 100644
index 00000000..6ff93c85
--- /dev/null
+++ b/roms/seabios/src/hw/sdcard.c
@@ -0,0 +1,321 @@
+// 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 "fw/paravirt.h" // runningOnQEMU
+#include "malloc.h" // malloc_fseg
+#include "output.h" // znprintf
+#include "pci.h" // pci_config_readl
+#include "pci_ids.h" // PCI_CLASS_SYSTEM_SDHCI
+#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "stacks.h" // wait_preempt
+#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;
+ u8 pad_3E[2];
+ u64 cap;
+ 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 SC_ALL_SEND_CID ((2<<8) | 0x21)
+#define SC_SEND_RELATIVE_ADDR ((3<<8) | 0x22)
+#define SC_SELECT_DESELECT_CARD ((7<<8) | 0x23)
+#define SC_READ_SINGLE ((17<<8) | 0x22)
+#define SC_READ_MULTIPLE ((18<<8) | 0x22)
+#define SC_WRITE_SINGLE ((24<<8) | 0x22)
+#define SC_WRITE_MULTIPLE ((25<<8) | 0x22)
+#define SC_APP_CMD ((55<<8) | 0x22)
+#define SC_APP_SEND_OP_COND ((41<<8) | 0x22)
+
+// 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)
+
+// SDHCI present_state flags
+#define SP_CMD_INHIBIT (1<<0)
+#define SP_DAT_INHIBIT (1<<1)
+
+// 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 result flags
+#define SR_OCR_CCS (1<<30)
+
+// SDHCI timeouts
+#define SDHCI_PIO_TIMEOUT 1000 // XXX - these are just made up
+#define SDHCI_TRANSFER_TIMEOUT 10000
+
+// 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 0
+#define SF_SDSC 1
+#define SF_SDHC 2
+
+// Repeatedly read a u16 register until the specific value is found
+static int
+waitw(u16 *reg, u16 mask, u16 value, u32 end)
+{
+ for (;;) {
+ u16 v = readw(reg);
+ if ((v & mask) == value)
+ return 0;
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+}
+
+// Send a command to the card.
+static int
+sdcard_pio(struct sdhci_s *regs, int cmd, u32 *param)
+{
+ u32 end = timer_calc(SDHCI_PIO_TIMEOUT);
+ u16 busyf = SP_CMD_INHIBIT | ((cmd & 0x03) == 0x03 ? SP_DAT_INHIBIT : 0);
+ int ret = waitw((u16*)&regs->present_state, busyf, 0, end);
+ if (ret)
+ return ret;
+ // Send command
+ writel(&regs->arg, *param);
+ writew(&regs->cmd, cmd);
+ ret = waitw(&regs->irq_status, SI_CMD_COMPLETE, SI_CMD_COMPLETE, end);
+ if (ret)
+ return ret;
+ writew(&regs->irq_status, SI_CMD_COMPLETE);
+ // Read response
+ memcpy(param, regs->response, sizeof(regs->response));
+ 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
+ writel(&drive->regs->block_size, DISK_SECTOR_SIZE);
+ writew(&drive->regs->block_count, count); // XXX - SC_SET_BLOCK_COUNT?
+ int isread = cmd != SC_WRITE_SINGLE && cmd != SC_WRITE_MULTIPLE;
+ u16 tmode = ((count > 1 ? ST_MULTIPLE|ST_AUTO_CMD12|ST_BLOCKCOUNT : 0)
+ | (isread ? ST_READ : 0));
+ writew(&drive->regs->transfer_mode, tmode);
+ if (drive->card_type < SF_SDHC)
+ addr *= DISK_SECTOR_SIZE;
+ u32 param[4] = { addr };
+ int ret = sdcard_pio(drive->regs, cmd, param);
+ if (ret)
+ return ret;
+ // Read/write data
+ u32 end = timer_calc(SDHCI_TRANSFER_TIMEOUT);
+ u16 cbit = isread ? SI_READ_READY : SI_WRITE_READY;
+ while (count--) {
+ ret = waitw(&drive->regs->irq_status, cbit, cbit, end);
+ if (ret)
+ 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
+ // XXX - SC_STOP_TRANSMISSION?
+ ret = waitw(&drive->regs->irq_status, SI_TRANS_DONE, SI_TRANS_DONE, end);
+ if (ret)
+ 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_gf, 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 VISIBLE32FLAT
+process_sdcard_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);
+ case CMD_FORMAT:
+ case CMD_RESET:
+ case CMD_ISREADY:
+ case CMD_VERIFY:
+ case CMD_SEEK:
+ return DISK_RET_SUCCESS;
+ default:
+ return DISK_RET_EPARAM;
+ }
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+// Initialize an SD card
+static int
+sdcard_card_setup(struct sdhci_s *regs)
+{
+ // XXX - works on QEMU; probably wont on real hardware!
+ u32 param[4] = { 0x01 };
+ int ret = sdcard_pio_app(regs, SC_APP_SEND_OP_COND, param);
+ if (ret)
+ return ret;
+ int card_type = (param[0] & SR_OCR_CCS) ? SF_SDHC : SF_SDSC;
+ param[0] = 0x00;
+ ret = sdcard_pio(regs, SC_ALL_SEND_CID, param);
+ if (ret)
+ return ret;
+ param[0] = 0x01 << 16;
+ ret = sdcard_pio(regs, SC_SEND_RELATIVE_ADDR, param);
+ if (ret)
+ return ret;
+ u16 rca = param[0] >> 16;
+ param[0] = rca << 16;
+ ret = sdcard_pio(regs, SC_SELECT_DESELECT_CARD, param);
+ if (ret)
+ return ret;
+ return card_type;
+}
+
+// Setup and configure an SD card controller
+static void
+sdcard_controller_setup(void *data)
+{
+ struct pci_device *pci = data;
+ u16 bdf = pci->bdf;
+ wait_preempt(); // Avoid pci_config_readl when preempting
+ struct sdhci_s *regs = (void*)pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
+ pci_config_maskw(bdf, PCI_COMMAND, 0,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ // Initialize controller
+ if (!runningOnQEMU())
+ // XXX - this init logic will probably only work on qemu!
+ return;
+ writew(&regs->irq_signal, 0);
+ writew(&regs->irq_enable, 0xffff);
+ writew(&regs->error_signal, 0);
+ writeb(&regs->power_control, 0x0f);
+ writew(&regs->clock_control, 0x0005);
+
+ // Initialize card
+ int card_type = sdcard_card_setup(regs);
+ if (card_type < 0)
+ return;
+
+ // Register drive
+ struct sddrive_s *drive = malloc_fseg(sizeof(*drive));
+ if (!drive) {
+ warn_noalloc();
+ return;
+ }
+ memset(drive, 0, sizeof(*drive));
+ drive->drive.type = DTYPE_SDCARD;
+ drive->drive.blksize = DISK_SECTOR_SIZE;
+ drive->drive.sectors = (u64)-1; // XXX
+ drive->regs = regs;
+ drive->card_type = card_type;
+
+ dprintf(1, "Found SD Card at %02x:%02x.%x\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf));
+ char *desc = znprintf(MAXDESCSIZE, "SD Card"); // XXX
+ boot_add_hd(&drive->drive, desc, bootprio_find_pci_device(pci));
+}
+
+void
+sdcard_setup(void)
+{
+ if (!CONFIG_SDCARD)
+ 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_controller_setup, pci);
+ }
+}
diff --git a/roms/seabios/src/hw/serialio.c b/roms/seabios/src/hw/serialio.c
new file mode 100644
index 00000000..6486fc08
--- /dev/null
+++ b/roms/seabios/src/hw/serialio.c
@@ -0,0 +1,89 @@
+// 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
+
+// Setup the debug serial port for output.
+void
+serial_debug_preinit(void)
+{
+ if (!CONFIG_DEBUG_SERIAL)
+ return;
+ // setup for serial logging: 8N1
+ u8 oldparam, newparam = 0x03;
+ oldparam = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
+ outb(newparam, CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
+ // Disable irqs
+ u8 oldier, newier = 0;
+ oldier = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
+ outb(newier, CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
+
+ 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)
+ return;
+ int timeout = DEBUG_TIMEOUT;
+ while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x20) != 0x20)
+ if (!timeout--)
+ // Ran out of time.
+ return;
+ outb(c, CONFIG_DEBUG_SERIAL_PORT+SEROFF_DATA);
+}
+
+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)
+ return;
+ int timeout = DEBUG_TIMEOUT;
+ while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x60) != 0x60)
+ if (!timeout--)
+ // Ran out of time.
+ return;
+}
+
+
+/****************************************************************
+ * QEMU debug port
+ ****************************************************************/
+
+u16 DebugOutputPort VARFSEG = 0x402;
+
+// Write a character to the special debugging port.
+void
+qemu_debug_putc(char c)
+{
+ if (CONFIG_DEBUG_IO && runningOnQEMU())
+ // Send character to debug port.
+ outb(c, GET_GLOBAL(DebugOutputPort));
+}
diff --git a/roms/seabios/src/hw/serialio.h b/roms/seabios/src/hw/serialio.h
new file mode 100644
index 00000000..88296fe7
--- /dev/null
+++ b/roms/seabios/src/hw/serialio.h
@@ -0,0 +1,29 @@
+#ifndef __SERIALIO_H
+#define __SERIALIO_H
+
+#include "types.h" // u16
+
+#define PORT_LPT2 0x0278
+#define PORT_SERIAL4 0x02e8
+#define PORT_SERIAL2 0x02f8
+#define PORT_LPT1 0x0378
+#define PORT_SERIAL3 0x03e8
+#define PORT_SERIAL1 0x03f8
+
+// 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 u16 DebugOutputPort;
+void qemu_debug_putc(char c);
+
+#endif // serialio.h
diff --git a/roms/seabios/src/hw/timer.c b/roms/seabios/src/hw/timer.c
new file mode 100644
index 00000000..5edc9fdb
--- /dev/null
+++ b/roms/seabios/src/hw/timer.c
@@ -0,0 +1,257 @@
+// 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;
+u16 TimerPort VARFSEG;
+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);
+
+ dprintf(1, "CPU Mhz=%u\n", (TimerKHz << ShiftTSC) / 1000);
+}
+
+// Setup internal timers.
+void
+timer_setup(void)
+{
+ if (CONFIG_PMTIMER && TimerPort) {
+ dprintf(3, "pmtimer already configured; will not calibrate TSC\n");
+ return;
+ }
+
+ u32 eax, ebx, ecx, edx, cpuid_features = 0;
+ cpuid(0, &eax, &ebx, &ecx, &edx);
+ if (eax > 0)
+ cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+
+ if (!(cpuid_features & CPUID_TSC)) {
+ TimerPort = PORT_PIT_COUNTER0;
+ TimerKHz = DIV_ROUND_UP(PMTIMER_HZ, 1000 * PMTIMER_TO_PIT);
+ dprintf(3, "386/486 class CPU. Using TSC emulation\n");
+ return;
+ }
+
+ tsctimer_setup();
+}
+
+void
+pmtimer_setup(u16 ioport)
+{
+ if (!CONFIG_PMTIMER)
+ return;
+ 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 (!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);
+}
+
+// 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 diff)
+{
+ u32 start = timer_read();
+ u32 end = start + diff;
+ while (!timer_check(end))
+ cpu_relax();
+}
+
+static void
+timer_sleep(u32 diff)
+{
+ u32 start = timer_read();
+ u32 end = start + diff;
+ while (!timer_check(end))
+ yield();
+}
+
+void ndelay(u32 count) {
+ timer_delay(DIV_ROUND_UP(count * GET_GLOBAL(TimerKHz), 1000000));
+}
+void udelay(u32 count) {
+ timer_delay(DIV_ROUND_UP(count * GET_GLOBAL(TimerKHz), 1000));
+}
+void mdelay(u32 count) {
+ timer_delay(count * GET_GLOBAL(TimerKHz));
+}
+
+void nsleep(u32 count) {
+ timer_sleep(DIV_ROUND_UP(count * GET_GLOBAL(TimerKHz), 1000000));
+}
+void usleep(u32 count) {
+ timer_sleep(DIV_ROUND_UP(count * GET_GLOBAL(TimerKHz), 1000));
+}
+void msleep(u32 count) {
+ timer_sleep(count * GET_GLOBAL(TimerKHz));
+}
+
+// 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)
+{
+ return timer_read() + DIV_ROUND_UP(GET_GLOBAL(TimerKHz) * usecs, 1000);
+}
+
+
+/****************************************************************
+ * 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)
+{
+ // 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/src/hw/usb-ehci.c b/roms/seabios/src/hw/usb-ehci.c
new file mode 100644
index 00000000..41f8579c
--- /dev/null
+++ b/roms/seabios/src/hw/usb-ehci.c
@@ -0,0 +1,648 @@
+// 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 "pci.h" // pci_bdf_to_bus
+#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)
+{
+ wait_preempt(); // Avoid pci_config_readl when preempting
+ u16 bdf = pci->bdf;
+ u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
+ struct ehci_caps *caps = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK);
+ 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 %02x:%02x.%x (regs=%p)\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
+ , pci_bdf_to_fn(bdf), cntl->regs);
+
+ pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+
+ // 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.
+ while (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);
+ 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/src/hw/usb-ehci.h b/roms/seabios/src/hw/usb-ehci.h
new file mode 100644
index 00000000..88f7b6a1
--- /dev/null
+++ b/roms/seabios/src/hw/usb-ehci.h
@@ -0,0 +1,176 @@
+#ifndef __USB_EHCI_H
+#define __USB_EHCI_H
+
+// usb-ehci.c
+void ehci_setup(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/src/hw/usb-hid.c b/roms/seabios/src/hw/usb-hid.c
new file mode 100644
index 00000000..09a6cf45
--- /dev/null
+++ b/roms/seabios/src/hw/usb-hid.c
@@ -0,0 +1,432 @@
+// 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
+
+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 != 8)
+ 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)
+ return -1;
+
+ keyboard_pipe = usb_alloc_pipe(usbdev, epdesc);
+ if (!keyboard_pipe)
+ return -1;
+
+ dprintf(1, "USB keyboard initialized\n");
+ return 0;
+}
+
+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 < 3 || epdesc->wMaxPacketSize > 8)
+ 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,
+ 0xe11d, 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
+
+// Format of USB keyboard event data
+struct keyevent {
+ u8 modifiers;
+ u8 reserved;
+ u8 keys[6];
+};
+
+// Translate data from KeyToScanCode[] to calls to process_key().
+static void
+prockeys(u16 keys)
+{
+ if (keys > 0xff) {
+ u8 key = keys>>8;
+ if (key == 0xe1) {
+ // Pause key
+ process_key(0xe1);
+ process_key(0x1d | (keys & RELEASEBIT));
+ process_key(0x45 | (keys & RELEASEBIT));
+ return;
+ }
+ process_key(key);
+ }
+ process_key(keys);
+}
+
+// Handle a USB key press/release event.
+static void
+procscankey(u8 key, u8 flags)
+{
+ if (key >= ARRAY_SIZE(KeyToScanCode))
+ return;
+ u16 keys = GET_GLOBAL(KeyToScanCode[key]);
+ if (keys)
+ prockeys(keys | flags);
+}
+
+// Handle a USB modifier press/release event.
+static void
+procmodkey(u8 mods, u8 flags)
+{
+ int i;
+ for (i=0; mods; i++)
+ if (mods & (1<<i)) {
+ // Modifier key change.
+ prockeys(GET_GLOBAL(ModifierToScanCode[i]) | flags);
+ 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);
+ 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);
+ 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);
+ 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 (;;) {
+ struct keyevent data;
+ int ret = usb_poll_intr(pipe, &data);
+ if (ret)
+ break;
+ handle_key(&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
+ ****************************************************************/
+
+// Format of USB mouse event data
+struct mouseevent {
+ u8 buttons;
+ u8 x, y;
+ u8 reserved[5];
+};
+
+// 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 (;;) {
+ struct mouseevent data;
+ int ret = usb_poll_intr(pipe, &data);
+ if (ret)
+ break;
+ handle_mouse(&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/src/hw/usb-hid.h b/roms/seabios/src/hw/usb-hid.h
new file mode 100644
index 00000000..ef34e796
--- /dev/null
+++ b/roms/seabios/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);
+inline int usb_kbd_active(void);
+inline int usb_kbd_command(int command, u8 *param);
+inline int usb_mouse_active(void);
+inline int usb_mouse_command(int command, u8 *param);
+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/src/hw/usb-hub.c b/roms/seabios/src/hw/usb-hub.c
new file mode 100644
index 00000000..54e341b7
--- /dev/null
+++ b/roms/seabios/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/src/hw/usb-hub.h b/roms/seabios/src/hw/usb-hub.h
new file mode 100644
index 00000000..880378ca
--- /dev/null
+++ b/roms/seabios/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/src/hw/usb-msc.c b/roms/seabios/src/hw/usb-msc.c
new file mode 100644
index 00000000..d90319f5
--- /dev/null
+++ b/roms/seabios/src/hw/usb-msc.c
@@ -0,0 +1,220 @@
+// 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_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ if (!CONFIG_USB_MSC)
+ return 0;
+
+ dprintf(16, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n"
+ , op->drive_gf, 0, op->count, blocksize, op->buf_fl);
+ struct usbdrive_s *udrive_gf = container_of(
+ op->drive_gf, struct usbdrive_s, drive);
+
+ // Setup command block wrapper.
+ u32 bytes = blocksize * op->count;
+ struct cbw_s cbw;
+ memset(&cbw, 0, sizeof(cbw));
+ memcpy(cbw.CBWCB, cdbcmd, USB_CDB_SIZE);
+ cbw.dCBWSignature = CBW_SIGNATURE;
+ cbw.dCBWTag = 999; // XXX
+ cbw.dCBWDataTransferLength = bytes;
+ cbw.bmCBWFlags = cdb_is_read(cdbcmd, blocksize) ? USB_DIR_IN : USB_DIR_OUT;
+ cbw.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);
+ 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/src/hw/usb-msc.h b/roms/seabios/src/hw/usb-msc.h
new file mode 100644
index 00000000..c40d7555
--- /dev/null
+++ b/roms/seabios/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_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+struct usbdevice_s;
+int usb_msc_setup(struct usbdevice_s *usbdev);
+
+#endif // ush-msc.h
diff --git a/roms/seabios/src/hw/usb-ohci.c b/roms/seabios/src/hw/usb-ohci.c
new file mode 100644
index 00000000..42f8a068
--- /dev/null
+++ b/roms/seabios/src/hw/usb-ohci.c
@@ -0,0 +1,569 @@
+// 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 "pci.h" // pci_bdf_to_bus
+#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-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();
+ // 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 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;
+
+ wait_preempt(); // Avoid pci_config_readl when preempting
+ u16 bdf = pci->bdf;
+ u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
+ cntl->regs = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK);
+
+ dprintf(1, "OHCI init on dev %02x:%02x.%x (regs=%p)\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
+ , pci_bdf_to_fn(bdf), cntl->regs);
+
+ // Enable bus mastering and memory access.
+ pci_config_maskw(bdf, PCI_COMMAND
+ , 0, PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY);
+
+ // 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/src/hw/usb-ohci.h b/roms/seabios/src/hw/usb-ohci.h
new file mode 100644
index 00000000..5a275a33
--- /dev/null
+++ b/roms/seabios/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/src/hw/usb-uas.c b/roms/seabios/src/hw/usb-uas.c
new file mode 100644
index 00000000..6ef8d091
--- /dev/null
+++ b/roms/seabios/src/hw/usb-uas.c
@@ -0,0 +1,274 @@
+// 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 usb_pipe *command, *status, *data_in, *data_out;
+ int lun;
+};
+
+int
+uas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ if (!CONFIG_USB_UAS)
+ return DISK_RET_EBADTRACK;
+
+ struct uasdrive_s *drive_gf = container_of(
+ op->drive_gf, 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);
+ memcpy(ui.command.cdb, cdbcmd, sizeof(ui.command.cdb));
+ 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 int
+uas_lun_setup(struct usbdevice_s *usbdev,
+ struct usb_pipe *command, struct usb_pipe *status,
+ struct usb_pipe *data_in, struct usb_pipe *data_out,
+ int lun)
+{
+ // Allocate drive structure.
+ struct uasdrive_s *drive = malloc_fseg(sizeof(*drive));
+ if (!drive) {
+ warn_noalloc();
+ return -1;
+ }
+ memset(drive, 0, sizeof(*drive));
+ if (usb_32bit_pipe(data_in))
+ drive->drive.type = DTYPE_UAS_32;
+ else
+ drive->drive.type = DTYPE_UAS;
+ drive->command = command;
+ drive->status = status;
+ drive->data_in = data_in;
+ drive->data_out = data_out;
+ drive->lun = lun;
+
+ int prio = bootprio_find_usb(usbdev, lun);
+ int ret = scsi_drive_setup(&drive->drive, "USB UAS", prio);
+ 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;
+
+ /* TODO: send REPORT LUNS. For now, only LUN 0 is recognized. */
+ int ret = uas_lun_setup(usbdev, command, status, data_in, data_out, 0);
+ 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/src/hw/usb-uas.h b/roms/seabios/src/hw/usb-uas.h
new file mode 100644
index 00000000..ad91c5f6
--- /dev/null
+++ b/roms/seabios/src/hw/usb-uas.h
@@ -0,0 +1,9 @@
+#ifndef __USB_UAS_H
+#define __USB_UAS_H
+
+struct disk_op_s;
+int uas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+struct usbdevice_s;
+int usb_uas_setup(struct usbdevice_s *usbdev);
+
+#endif /* __USB_UAS_H */
diff --git a/roms/seabios/src/hw/usb-uhci.c b/roms/seabios/src/hw/usb-uhci.c
new file mode 100644
index 00000000..69c33ee3
--- /dev/null
+++ b/roms/seabios/src/hw/usb-uhci.c
@@ -0,0 +1,567 @@
+// 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_bdf_to_bus
+#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-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();
+ 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 bdf = pci->bdf;
+ struct usb_uhci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+ if (!cntl) {
+ warn_noalloc();
+ return;
+ }
+ wait_preempt(); // Avoid pci_config_readl when preempting
+ memset(cntl, 0, sizeof(*cntl));
+ cntl->usb.pci = pci;
+ cntl->usb.type = USB_TYPE_UHCI;
+ cntl->iobase = (pci_config_readl(bdf, PCI_BASE_ADDRESS_4)
+ & PCI_BASE_ADDRESS_IO_MASK);
+
+ dprintf(1, "UHCI init on dev %02x:%02x.%x (io=%x)\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
+ , pci_bdf_to_fn(bdf), cntl->iobase);
+
+ pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+
+ reset_uhci(cntl, 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/src/hw/usb-uhci.h b/roms/seabios/src/hw/usb-uhci.h
new file mode 100644
index 00000000..bff70c66
--- /dev/null
+++ b/roms/seabios/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/src/hw/usb-xhci.c b/roms/seabios/src/hw/usb-xhci.c
new file mode 100644
index 00000000..fd58334d
--- /dev/null
+++ b/roms/seabios/src/hw/usb-xhci.c
@@ -0,0 +1,1139 @@
+// 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 "pci.h" // pci_bdf_to_bus
+#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 usb_xhci_s {
+ struct usb_s usb;
+
+ /* devinfo */
+ u32 baseaddr;
+ u32 xcap;
+ u32 ports;
+ u32 slots;
+ u8 context64;
+
+ /* 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 const int eptype_to_xhci_in[] = {
+ [ USB_ENDPOINT_XFER_CONTROL] = 4,
+ [ USB_ENDPOINT_XFER_ISOC ] = 5,
+ [ USB_ENDPOINT_XFER_BULK ] = 6,
+ [ USB_ENDPOINT_XFER_INT ] = 7,
+};
+
+static const int eptype_to_xhci_out[] = {
+ [ USB_ENDPOINT_XFER_CONTROL] = 4,
+ [ USB_ENDPOINT_XFER_ISOC ] = 1,
+ [ USB_ENDPOINT_XFER_BULK ] = 2,
+ [ USB_ENDPOINT_XFER_INT ] = 3,
+};
+
+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);
+ int rc;
+
+ switch (xhci_get_field(portsc, XHCI_PORTSC_PLS)) {
+ case PLS_U0:
+ rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)];
+ break;
+ case PLS_POLLING:
+ xhci_print_port_state(3, __func__, port, portsc);
+ portsc |= XHCI_PORTSC_PR;
+ writel(&xhci->pr[port].portsc, portsc);
+ if (wait_bit(&xhci->pr[port].portsc, XHCI_PORTSC_PED, XHCI_PORTSC_PED, 100) != 0)
+ return -1;
+ portsc = readl(&xhci->pr[port].portsc);
+ rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)];
+ break;
+ default:
+ rc = -1;
+ break;
+ }
+
+ xhci_print_port_state(1, "XHCI", port, portsc);
+ return rc;
+}
+
+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,
+ .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, 100) != 0)
+ goto fail;
+ if (wait_bit(&xhci->op->usbsts, XHCI_STS_CNR, 0, 100) != 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 >> 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 void
+xhci_controller_setup(struct pci_device *pci)
+{
+ struct usb_xhci_s *xhci = malloc_high(sizeof(*xhci));
+ if (!xhci) {
+ warn_noalloc();
+ return;
+ }
+ memset(xhci, 0, sizeof(*xhci));
+
+ wait_preempt(); // Avoid pci_config_readl when preempting
+ xhci->baseaddr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
+ & PCI_BASE_ADDRESS_MEM_MASK;
+ xhci->caps = (void*)(xhci->baseaddr);
+ xhci->op = (void*)(xhci->baseaddr + readb(&xhci->caps->caplength));
+ xhci->pr = (void*)(xhci->baseaddr + readb(&xhci->caps->caplength) + 0x400);
+ xhci->db = (void*)(xhci->baseaddr + readl(&xhci->caps->dboff));
+ xhci->ir = (void*)(xhci->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.pci = pci;
+ xhci->usb.type = USB_TYPE_XHCI;
+
+ dprintf(1, "XHCI init on dev %02x:%02x.%x: regs @ %p, %d ports, %d slots"
+ ", %d byte contexts\n"
+ , pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf)
+ , pci_bdf_to_fn(pci->bdf), xhci->caps
+ , xhci->ports, xhci->slots, xhci->context64 ? 64 : 32);
+
+ if (xhci->xcap) {
+ u32 off, addr = xhci->baseaddr + xhci->xcap;
+ do {
+ struct xhci_xcap *xcap = (void*)addr;
+ u32 ports, name, cap = readl(&xcap->cap);
+ switch (cap & 0xff) {
+ case 0x02:
+ name = readl(&xcap->data[0]);
+ ports = readl(&xcap->data[1]);
+ 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
+ , (cap >> 24) & 0xff
+ , (cap >> 16) & 0xff
+ , (ports >> 8) & 0xff
+ , (ports >> 0) & 0xff
+ , ports >> 16);
+ break;
+ default:
+ dprintf(1, "XHCI extcap 0x%x @ %x\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;
+ }
+
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+
+ 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);
+ }
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+static void xhci_doorbell(struct usb_xhci_s *xhci, u32 slotid, u32 value)
+{
+ struct xhci_db *db = xhci->db;
+ void *addr = &db[slotid].doorbell;
+ writel(addr, value);
+}
+
+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 portid = (etrb->ptr_low >> 24) & 0xff;
+ dprintf(3, "%s: status change port #%d\n",
+ __func__, portid);
+ 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);
+ }
+}
+
+static int xhci_ring_busy(struct xhci_ring *ring)
+{
+ u32 eidx = ring->eidx;
+ u32 nidx = ring->nidx;
+ return (eidx != nidx);
+}
+
+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();
+ }
+}
+
+static void xhci_trb_queue(struct xhci_ring *ring,
+ struct xhci_trb *trb)
+{
+ u32 nidx = ring->nidx;
+ u32 cs = ring->cs;
+ struct xhci_trb *dst;
+ u32 control;
+
+ if (nidx == XHCI_RING_ITEMS-1) {
+ dst = ring->ring + nidx;
+ control = (TR_LINK << 10); // trb type
+ control |= TRB_LK_TC;
+ control |= (cs ? TRB_C : 0);
+ dst->ptr_low = (u32)&ring[0];
+ dst->ptr_high = 0;
+ dst->status = 0;
+ dst->control = control;
+ nidx = 0;
+ cs = cs ? 0 : 1;
+ ring->nidx = nidx;
+ ring->cs = cs;
+
+ dprintf(5, "%s: ring %p [linked]\n", __func__, ring);
+ }
+
+ dst = ring->ring + nidx;
+ control = trb->control | (cs ? TRB_C : 0);
+
+ dst->ptr_low = trb->ptr_low;
+ dst->ptr_high = trb->ptr_high;
+ dst->status = trb->status;
+ dst->control = control;
+ nidx++;
+ ring->nidx = nidx;
+
+ dprintf(5, "%s: ring %p [nidx %d, len %d]\n",
+ __func__, ring, nidx,
+ trb->status & 0xffff);
+}
+
+static int xhci_cmd_submit(struct usb_xhci_s *xhci,
+ struct xhci_trb *cmd)
+{
+ int rc;
+
+ mutex_lock(&xhci->cmds->lock);
+ xhci_trb_queue(xhci->cmds, cmd);
+ xhci_doorbell(xhci, 0, 0);
+ 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)
+{
+ struct xhci_trb cmd = {
+ .ptr_low = 0,
+ .ptr_high = 0,
+ .status = 0,
+ .control = (CR_ENABLE_SLOT << 10)
+ };
+ dprintf(3, "%s:\n", __func__);
+ int cc = xhci_cmd_submit(xhci, &cmd);
+ if (cc != CC_SUCCESS)
+ return -1;
+ return (xhci->cmds->evt.control >> 24) & 0xff;
+}
+
+#if 0
+static int xhci_cmd_disable_slot(struct usb_xhci_s *xhci, u32 slotid)
+{
+ struct xhci_trb cmd = {
+ .ptr_low = 0,
+ .ptr_high = 0,
+ .status = 0,
+ .control = (slotid << 24) | (CR_DISABLE_SLOT << 10)
+ };
+ dprintf(3, "%s: slotid %d\n", __func__, slotid);
+ return xhci_cmd_submit(xhci, &cmd);
+}
+#endif
+
+static int xhci_cmd_address_device(struct usb_xhci_s *xhci, u32 slotid
+ , struct xhci_inctx *inctx)
+{
+ struct xhci_trb cmd = {
+ .ptr_low = (u32)inctx,
+ .ptr_high = 0,
+ .status = 0,
+ .control = (slotid << 24) | (CR_ADDRESS_DEVICE << 10)
+ };
+ dprintf(3, "%s: slotid %d\n", __func__, slotid);
+ return xhci_cmd_submit(xhci, &cmd);
+}
+
+static int xhci_cmd_configure_endpoint(struct usb_xhci_s *xhci, u32 slotid
+ , struct xhci_inctx *inctx)
+{
+ struct xhci_trb cmd = {
+ .ptr_low = (u32)inctx,
+ .ptr_high = 0,
+ .status = 0,
+ .control = (slotid << 24) | (CR_CONFIGURE_ENDPOINT << 10)
+ };
+ dprintf(3, "%s: slotid %d, add 0x%x, del 0x%x\n", __func__,
+ slotid, inctx->add, inctx->del);
+ return xhci_cmd_submit(xhci, &cmd);
+}
+
+static int xhci_cmd_evaluate_context(struct usb_xhci_s *xhci, u32 slotid
+ , struct xhci_inctx *inctx)
+{
+ struct xhci_trb cmd = {
+ .ptr_low = (u32)inctx,
+ .ptr_high = 0,
+ .status = 0,
+ .control = (slotid << 24) | (CR_EVALUATE_CONTEXT << 10)
+ };
+ dprintf(3, "%s: slotid %d, add 0x%x, del 0x%x\n", __func__,
+ slotid, inctx->add, inctx->del);
+ return xhci_cmd_submit(xhci, &cmd);
+}
+
+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);
+
+ // 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);
+ pipe->slotid = usbdev->slotid = slotid;
+ 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);
+ goto fail;
+ }
+ } else {
+ pipe->slotid = usbdev->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);
+ 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;
+}
+
+static void xhci_xfer_queue(struct xhci_pipe *pipe,
+ void *data, int datalen, u32 flags)
+{
+ struct xhci_trb trb;
+ memset(&trb, 0, sizeof(trb));
+ if (flags & TRB_TR_IDT)
+ memcpy(&trb.ptr_low, data, datalen);
+ else
+ trb.ptr_low = (u32)data;
+ trb.status = datalen;
+ trb.control = flags;
+ xhci_trb_queue(&pipe->reqs, &trb);
+}
+
+static void xhci_xfer_kick(struct xhci_pipe *pipe)
+{
+ struct usb_xhci_s *xhci = container_of(
+ pipe->pipe.cntl, struct usb_xhci_s, usb);
+ u32 slotid = pipe->slotid;
+ u32 epid = pipe->epid;
+
+ dprintf(5, "%s: ring %p, slotid %d, epid %d\n",
+ __func__, &pipe->reqs, slotid, epid);
+ xhci_doorbell(xhci, slotid, epid);
+}
+
+static void xhci_xfer_normal(struct xhci_pipe *pipe,
+ void *data, int datalen)
+{
+ xhci_xfer_queue(pipe, data, datalen, (TR_NORMAL << 10) | TRB_TR_IOC);
+ xhci_xfer_kick(pipe);
+}
+
+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_queue(pipe, (void*)req, USB_CONTROL_SETUP_SIZE
+ , (TR_SETUP << 10) | TRB_TR_IDT
+ | ((datalen ? (dir ? 3 : 2) : 0) << 16));
+ if (datalen)
+ xhci_xfer_queue(pipe, data, datalen, (TR_DATA << 10)
+ | ((dir ? 1 : 0) << 16));
+ xhci_xfer_queue(pipe, NULL, 0, (TR_STATUS << 10) | TRB_TR_IOC
+ | ((dir ? 0 : 1) << 16));
+ xhci_xfer_kick(pipe);
+ } 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/src/hw/usb-xhci.h b/roms/seabios/src/hw/usb-xhci.h
new file mode 100644
index 00000000..c768c5b5
--- /dev/null
+++ b/roms/seabios/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/src/hw/usb.c b/roms/seabios/src/hw/usb.c
new file mode 100644
index 00000000..1b4ea8be
--- /dev/null
+++ b/roms/seabios/src/hw/usb.c
@@ -0,0 +1,500 @@
+// 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 "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: ;
+ extern void _cfunc32flat_xhci_poll_intr(void);
+ return call32_params(_cfunc32flat_xhci_poll_intr, (u32)pipe_fl
+ , (u32)MAKE_FLATPTR(GET_SEG(SS), (u32)data), 0, -1);
+ }
+}
+
+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;
+
+ void *config = malloc_tmphigh(cfg.wTotalLength);
+ if (!config)
+ return NULL;
+ req.wLength = cfg.wTotalLength;
+ ret = usb_send_default_control(pipe, &req, config);
+ if (ret) {
+ 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
+ // first interface of the first configuration.
+ struct usb_interface_descriptor *iface = (void*)(&config[1]);
+ if (iface->bInterfaceClass != USB_CLASS_HID
+ && iface->bInterfaceClass != USB_CLASS_MASS_STORAGE
+ && iface->bInterfaceClass != USB_CLASS_HUB)
+ // Not a supported device.
+ goto fail;
+
+ // 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;
+}
+
+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 *data)
+{
+ dprintf(3, "init usb\n");
+ xhci_setup();
+ ehci_setup();
+ uhci_setup();
+ ohci_setup();
+}
+
+void
+usb_setup(void)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_USB)
+ return;
+ run_thread(__usb_setup, NULL);
+}
diff --git a/roms/seabios/src/hw/usb.h b/roms/seabios/src/hw/usb.h
new file mode 100644
index 00000000..efb5e6f9
--- /dev/null
+++ b/roms/seabios/src/hw/usb.h
@@ -0,0 +1,254 @@
+// 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 slotid;
+ 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;
+ 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);
+ 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/src/hw/virtio-blk.c b/roms/seabios/src/hw/virtio-blk.c
new file mode 100644
index 00000000..e2dbd3c9
--- /dev/null
+++ b/roms/seabios/src/hw/virtio-blk.c
@@ -0,0 +1,177 @@
+// 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 "pci.h" // foreachpci
+#include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // usleep
+#include "virtio-pci.h"
+#include "virtio-ring.h"
+#include "virtio-blk.h"
+
+struct virtiodrive_s {
+ struct drive_s drive;
+ struct vring_virtqueue *vq;
+ u16 ioaddr;
+};
+
+static int
+virtio_blk_op(struct disk_op_s *op, int write)
+{
+ struct virtiodrive_s *vdrive_gf =
+ container_of(op->drive_gf, struct virtiodrive_s, drive);
+ struct vring_virtqueue *vq = GET_GLOBALFLAT(vdrive_gf->vq);
+ struct 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 = MAKE_FLATPTR(GET_SEG(SS), &hdr),
+ .length = sizeof(hdr),
+ },
+ {
+ .addr = op->buf_fl,
+ .length = GET_GLOBALFLAT(vdrive_gf->drive.blksize) * op->count,
+ },
+ {
+ .addr = MAKE_FLATPTR(GET_SEG(SS), &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(GET_GLOBALFLAT(vdrive_gf->ioaddr), 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(GET_GLOBALFLAT(vdrive_gf->ioaddr));
+
+ return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
+}
+
+int
+process_virtio_blk_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);
+ case CMD_FORMAT:
+ case CMD_RESET:
+ case CMD_ISREADY:
+ case CMD_VERIFY:
+ case CMD_SEEK:
+ return DISK_RET_SUCCESS;
+ default:
+ return DISK_RET_EPARAM;
+ }
+}
+
+static void
+init_virtio_blk(struct pci_device *pci)
+{
+ u16 bdf = pci->bdf;
+ dprintf(1, "found virtio-blk at %x:%x\n", pci_bdf_to_bus(bdf),
+ pci_bdf_to_dev(bdf));
+ struct virtiodrive_s *vdrive = malloc_fseg(sizeof(*vdrive));
+ if (!vdrive) {
+ warn_noalloc();
+ return;
+ }
+ memset(vdrive, 0, sizeof(*vdrive));
+ vdrive->drive.type = DTYPE_VIRTIO_BLK;
+ vdrive->drive.cntl_id = bdf;
+
+ u16 ioaddr = vp_init_simple(bdf);
+ vdrive->ioaddr = ioaddr;
+ if (vp_find_vq(ioaddr, 0, &vdrive->vq) < 0 ) {
+ dprintf(1, "fail to find vq for virtio-blk %x:%x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+ goto fail;
+ }
+
+ struct virtio_blk_config cfg;
+ vp_get(ioaddr, 0, &cfg, sizeof(cfg));
+
+ u32 f = vp_get_features(ioaddr);
+ vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ?
+ cfg.blk_size : DISK_SECTOR_SIZE;
+
+ vdrive->drive.sectors = cfg.capacity;
+ dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ vdrive->drive.blksize, (u32)vdrive->drive.sectors);
+
+ if (vdrive->drive.blksize != DISK_SECTOR_SIZE) {
+ dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ vdrive->drive.blksize);
+ goto fail;
+ }
+
+ vdrive->drive.pchs.cylinder = cfg.cylinders;
+ vdrive->drive.pchs.head = cfg.heads;
+ vdrive->drive.pchs.sector = cfg.sectors;
+ char *desc = znprintf(MAXDESCSIZE, "Virtio disk PCI:%x:%x",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+
+ boot_add_hd(&vdrive->drive, desc, bootprio_find_pci_device(pci));
+
+ vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+ VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
+ return;
+
+fail:
+ vp_reset(ioaddr);
+ free(vdrive->vq);
+ free(vdrive);
+}
+
+void
+virtio_blk_setup(void)
+{
+ 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)
+ continue;
+ init_virtio_blk(pci);
+ }
+}
diff --git a/roms/seabios/src/hw/virtio-blk.h b/roms/seabios/src/hw/virtio-blk.h
new file mode 100644
index 00000000..b233c744
--- /dev/null
+++ b/roms/seabios/src/hw/virtio-blk.h
@@ -0,0 +1,43 @@
+#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 process_virtio_blk_op(struct disk_op_s *op);
+void virtio_blk_setup(void);
+
+#endif /* _VIRTIO_BLK_H */
diff --git a/roms/seabios/src/hw/virtio-pci.c b/roms/seabios/src/hw/virtio-pci.c
new file mode 100644
index 00000000..b9b3ab1e
--- /dev/null
+++ b/roms/seabios/src/hw/virtio-pci.c
@@ -0,0 +1,97 @@
+/* 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 "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "string.h" // memset
+#include "virtio-pci.h"
+#include "virtio-ring.h"
+
+int vp_find_vq(unsigned int ioaddr, int queue_index,
+ struct vring_virtqueue **p_vq)
+{
+ u16 num;
+
+ ASSERT32FLAT();
+ struct vring_virtqueue *vq = *p_vq = memalign_low(PAGE_SIZE, sizeof(*vq));
+ if (!vq) {
+ warn_noalloc();
+ goto fail;
+ }
+ memset(vq, 0, sizeof(*vq));
+
+ /* select the queue */
+
+ outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+ /* check if the queue is available */
+
+ num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM);
+ if (!num) {
+ dprintf(1, "ERROR: queue size is 0\n");
+ goto fail;
+ }
+
+ if (num > MAX_QUEUE_NUM) {
+ dprintf(1, "ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
+ goto fail;
+ }
+
+ /* check if the queue is already active */
+
+ if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
+ dprintf(1, "ERROR: queue already active\n");
+ goto fail;
+ }
+
+ 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()
+ */
+
+ outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
+ ioaddr + VIRTIO_PCI_QUEUE_PFN);
+
+ return num;
+
+fail:
+ free(vq);
+ *p_vq = NULL;
+ return -1;
+}
+
+u16 vp_init_simple(u16 bdf)
+{
+ u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) &
+ PCI_BASE_ADDRESS_IO_MASK;
+
+ vp_reset(ioaddr);
+ pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+ vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+ VIRTIO_CONFIG_S_DRIVER );
+ return ioaddr;
+}
diff --git a/roms/seabios/src/hw/virtio-pci.h b/roms/seabios/src/hw/virtio-pci.h
new file mode 100644
index 00000000..bc04b039
--- /dev/null
+++ b/roms/seabios/src/hw/virtio-pci.h
@@ -0,0 +1,105 @@
+#ifndef _VIRTIO_PCI_H
+#define _VIRTIO_PCI_H
+
+#include "x86.h" // inl
+
+/* A 32-bit r/o bitmask of the features supported by the host */
+#define VIRTIO_PCI_HOST_FEATURES 0
+
+/* A 32-bit r/w bitmask of features activated by the guest */
+#define VIRTIO_PCI_GUEST_FEATURES 4
+
+/* A 32-bit r/w PFN for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_PFN 8
+
+/* A 16-bit r/o queue size for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_NUM 12
+
+/* A 16-bit r/w queue selector */
+#define VIRTIO_PCI_QUEUE_SEL 14
+
+/* A 16-bit r/w queue notifier */
+#define VIRTIO_PCI_QUEUE_NOTIFY 16
+
+/* An 8-bit device status register. */
+#define VIRTIO_PCI_STATUS 18
+
+/* An 8-bit r/o interrupt status register. Reading the value will return the
+ * current contents of the ISR and will also clear it. This is effectively
+ * a read-and-acknowledge. */
+#define VIRTIO_PCI_ISR 19
+
+/* The bit of the ISR which indicates a device configuration change. */
+#define VIRTIO_PCI_ISR_CONFIG 0x2
+
+/* The remaining space is defined by each driver as the per-driver
+ * configuration space */
+#define VIRTIO_PCI_CONFIG 20
+
+/* Virtio ABI version, this must match exactly */
+#define VIRTIO_PCI_ABI_VERSION 0
+
+static inline u32 vp_get_features(unsigned int ioaddr)
+{
+ return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES);
+}
+
+static inline void vp_set_features(unsigned int ioaddr, u32 features)
+{
+ outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES);
+}
+
+static inline void vp_get(unsigned int ioaddr, unsigned offset,
+ void *buf, unsigned len)
+{
+ u8 *ptr = buf;
+ unsigned i;
+
+ for (i = 0; i < len; i++)
+ ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i);
+}
+
+static inline u8 vp_get_status(unsigned int ioaddr)
+{
+ return inb(ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static inline void vp_set_status(unsigned int ioaddr, u8 status)
+{
+ if (status == 0) /* reset */
+ return;
+ outb(status, ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static inline u8 vp_get_isr(unsigned int ioaddr)
+{
+ return inb(ioaddr + VIRTIO_PCI_ISR);
+}
+
+static inline void vp_reset(unsigned int ioaddr)
+{
+ outb(0, ioaddr + VIRTIO_PCI_STATUS);
+ (void)inb(ioaddr + VIRTIO_PCI_ISR);
+}
+
+static inline void vp_notify(unsigned int ioaddr, int queue_index)
+{
+ outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
+}
+
+static inline void vp_del_vq(unsigned int ioaddr, int queue_index)
+{
+ /* select the queue */
+
+ outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+ /* deactivate the queue */
+
+ outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN);
+}
+
+struct vring_virtqueue;
+u16 vp_init_simple(u16 bdf);
+int vp_find_vq(unsigned int ioaddr, int queue_index,
+ struct vring_virtqueue **p_vq);
+#endif /* _VIRTIO_PCI_H_ */
diff --git a/roms/seabios/src/hw/virtio-ring.c b/roms/seabios/src/hw/virtio-ring.c
new file mode 100644
index 00000000..97e0b348
--- /dev/null
+++ b/roms/seabios/src/hw/virtio-ring.c
@@ -0,0 +1,149 @@
+/* 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 "biosvar.h" // GET_GLOBAL
+#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 = GET_LOWFLAT(vq->vring.used);
+ int more = GET_LOWFLAT(vq->last_used_idx) != GET_LOWFLAT(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 (GET_LOWFLAT(desc[i].flags) & VRING_DESC_F_NEXT)
+ i = GET_LOWFLAT(desc[i].next);
+
+ /* link it with free list and point to it */
+
+ SET_LOWFLAT(desc[i].next, GET_LOWFLAT(vq->free_head));
+ SET_LOWFLAT(vq->free_head, head);
+}
+
+/*
+ * 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 = GET_LOWFLAT(vq->vring.used);
+ u32 id;
+ int ret;
+
+// BUG_ON(!vring_more_used(vq));
+
+ elem = &used->ring[GET_LOWFLAT(vq->last_used_idx) % GET_LOWFLAT(vr->num)];
+ id = GET_LOWFLAT(elem->id);
+ if (len != NULL)
+ *len = GET_LOWFLAT(elem->len);
+
+ ret = GET_LOWFLAT(vq->vdata[id]);
+
+ vring_detach(vq, id);
+
+ SET_LOWFLAT(vq->last_used_idx, GET_LOWFLAT(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 = GET_LOWFLAT(vr->desc);
+ struct vring_avail *avail = GET_LOWFLAT(vr->avail);
+
+ BUG_ON(out + in == 0);
+
+ prev = 0;
+ head = GET_LOWFLAT(vq->free_head);
+ for (i = head; out; i = GET_LOWFLAT(desc[i].next), out--) {
+ SET_LOWFLAT(desc[i].flags, VRING_DESC_F_NEXT);
+ SET_LOWFLAT(desc[i].addr, (u64)virt_to_phys(list->addr));
+ SET_LOWFLAT(desc[i].len, list->length);
+ prev = i;
+ list++;
+ }
+ for ( ; in; i = GET_LOWFLAT(desc[i].next), in--) {
+ SET_LOWFLAT(desc[i].flags, VRING_DESC_F_NEXT|VRING_DESC_F_WRITE);
+ SET_LOWFLAT(desc[i].addr, (u64)virt_to_phys(list->addr));
+ SET_LOWFLAT(desc[i].len, list->length);
+ prev = i;
+ list++;
+ }
+ SET_LOWFLAT(desc[prev].flags,
+ GET_LOWFLAT(desc[prev].flags) & ~VRING_DESC_F_NEXT);
+
+ SET_LOWFLAT(vq->free_head, i);
+
+ SET_LOWFLAT(vq->vdata[head], index);
+
+ av = (GET_LOWFLAT(avail->idx) + num_added) % GET_LOWFLAT(vr->num);
+ SET_LOWFLAT(avail->ring[av], head);
+}
+
+void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
+{
+ struct vring *vr = &vq->vring;
+ struct vring_avail *avail = GET_LOWFLAT(vr->avail);
+
+ /* Make sure idx update is done after ring write. */
+ smp_wmb();
+ SET_LOWFLAT(avail->idx, GET_LOWFLAT(avail->idx) + num_added);
+
+ vp_notify(ioaddr, GET_LOWFLAT(vq->queue_index));
+}
diff --git a/roms/seabios/src/hw/virtio-ring.h b/roms/seabios/src/hw/virtio-ring.h
new file mode 100644
index 00000000..b7a7aafb
--- /dev/null
+++ b/roms/seabios/src/hw/virtio-ring.h
@@ -0,0 +1,131 @@
+#ifndef _VIRTIO_RING_H
+#define _VIRTIO_RING_H
+
+#include "types.h" // u64
+#include "memmap.h" // PAGE_SIZE
+
+#define PAGE_SHIFT 12
+#define PAGE_MASK (PAGE_SIZE-1)
+
+#define virt_to_phys(v) (unsigned long)(v)
+#define phys_to_virt(p) (void*)(p)
+/* Compiler barrier is enough as an x86 CPU does not reorder reads or writes */
+#define smp_rmb() barrier()
+#define smp_wmb() barrier()
+
+/* Status byte for guest to report progress, and synchronize features. */
+/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
+/* 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
+/* We've given up on this device. */
+#define VIRTIO_CONFIG_S_FAILED 0x80
+
+#define MAX_QUEUE_NUM (128)
+
+#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) \
+ (((((sizeof(struct vring_desc) * num) + \
+ (sizeof(struct vring_avail) + sizeof(u16) * num)) \
+ + PAGE_MASK) & ~PAGE_MASK) + \
+ (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
+
+typedef unsigned char virtio_queue_t[vring_size(MAX_QUEUE_NUM)];
+
+struct vring_virtqueue {
+ virtio_queue_t queue;
+ struct vring vring;
+ u16 free_head;
+ u16 last_used_idx;
+ u16 vdata[MAX_QUEUE_NUM];
+ /* PCI */
+ int queue_index;
+};
+
+struct vring_list {
+ char *addr;
+ unsigned int length;
+};
+
+static inline void vring_init(struct vring *vr,
+ unsigned int num, unsigned char *queue)
+{
+ unsigned int i;
+ unsigned long pa;
+
+ ASSERT32FLAT();
+ vr->num = num;
+
+ /* physical address of desc must be page aligned */
+
+ pa = virt_to_phys(queue);
+ pa = (pa + PAGE_MASK) & ~PAGE_MASK;
+ vr->desc = phys_to_virt(pa);
+
+ vr->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 */
+
+ pa = virt_to_phys(&vr->avail->ring[num]);
+ pa = (pa + PAGE_MASK) & ~PAGE_MASK;
+ vr->used = phys_to_virt(pa);
+
+ for (i = 0; i < num - 1; i++)
+ vr->desc[i].next = i + 1;
+ vr->desc[i].next = 0;
+}
+
+int vring_more_used(struct vring_virtqueue *vq);
+void vring_detach(struct vring_virtqueue *vq, unsigned int head);
+int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len);
+void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[],
+ unsigned int out, unsigned int in,
+ int index, int num_added);
+void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added);
+
+#endif /* _VIRTIO_RING_H_ */
diff --git a/roms/seabios/src/hw/virtio-scsi.c b/roms/seabios/src/hw/virtio-scsi.c
new file mode 100644
index 00000000..8f966875
--- /dev/null
+++ b/roms/seabios/src/hw/virtio-scsi.c
@@ -0,0 +1,187 @@
+// 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 "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" // foreachpci
+#include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "std/disk.h" // DISK_RET_SUCCESS
+#include "string.h" // memset
+#include "util.h" // usleep
+#include "virtio-pci.h"
+#include "virtio-ring.h"
+#include "virtio-scsi.h"
+
+struct virtio_lun_s {
+ struct drive_s drive;
+ struct pci_device *pci;
+ struct vring_virtqueue *vq;
+ u16 ioaddr;
+ u16 target;
+ u16 lun;
+};
+
+static int
+virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
+ void *cdbcmd, u16 target, u16 lun, u16 blocksize)
+{
+ struct virtio_scsi_req_cmd req;
+ struct virtio_scsi_resp_cmd resp;
+ struct vring_list sg[3];
+
+ memset(&req, 0, sizeof(req));
+ req.lun[0] = 1;
+ req.lun[1] = target;
+ req.lun[2] = (lun >> 8) | 0x40;
+ req.lun[3] = (lun & 0xff);
+ memcpy(req.cdb, cdbcmd, 16);
+
+ u32 len = op->count * blocksize;
+ int datain = cdb_is_read(cdbcmd, blocksize);
+ int in_num = (datain ? 2 : 1);
+ int out_num = (len ? 3 : 2) - in_num;
+
+ sg[0].addr = MAKE_FLATPTR(GET_SEG(SS), &req);
+ sg[0].length = sizeof(req);
+
+ sg[out_num].addr = MAKE_FLATPTR(GET_SEG(SS), &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(ioaddr, 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(ioaddr);
+
+ if (resp.response == VIRTIO_SCSI_S_OK && resp.status == 0) {
+ return DISK_RET_SUCCESS;
+ }
+ return DISK_RET_EBADTRACK;
+}
+
+int
+virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ struct virtio_lun_s *vlun_gf =
+ container_of(op->drive_gf, struct virtio_lun_s, drive);
+
+ return virtio_scsi_cmd(GET_GLOBALFLAT(vlun_gf->ioaddr),
+ GET_GLOBALFLAT(vlun_gf->vq), op, cdbcmd,
+ GET_GLOBALFLAT(vlun_gf->target),
+ GET_GLOBALFLAT(vlun_gf->lun),
+ blocksize);
+}
+
+static int
+virtio_scsi_add_lun(struct pci_device *pci, u16 ioaddr,
+ struct vring_virtqueue *vq, u16 target, u16 lun)
+{
+ struct virtio_lun_s *vlun = malloc_fseg(sizeof(*vlun));
+ if (!vlun) {
+ warn_noalloc();
+ return -1;
+ }
+ memset(vlun, 0, sizeof(*vlun));
+ vlun->drive.type = DTYPE_VIRTIO_SCSI;
+ vlun->drive.cntl_id = pci->bdf;
+ vlun->pci = pci;
+ vlun->ioaddr = ioaddr;
+ vlun->vq = vq;
+ vlun->target = target;
+ vlun->lun = lun;
+
+ int prio = bootprio_find_scsi_device(pci, target, lun);
+ int ret = scsi_drive_setup(&vlun->drive, "virtio-scsi", prio);
+ if (ret)
+ goto fail;
+ return 0;
+
+fail:
+ free(vlun);
+ return -1;
+}
+
+static int
+virtio_scsi_scan_target(struct pci_device *pci, u16 ioaddr,
+ struct vring_virtqueue *vq, u16 target)
+{
+ /* TODO: send REPORT LUNS. For now, only LUN 0 is recognized. */
+ int ret = virtio_scsi_add_lun(pci, ioaddr, vq, target, 0);
+ return ret < 0 ? 0 : 1;
+}
+
+static void
+init_virtio_scsi(struct pci_device *pci)
+{
+ u16 bdf = pci->bdf;
+ dprintf(1, "found virtio-scsi at %x:%x\n", pci_bdf_to_bus(bdf),
+ pci_bdf_to_dev(bdf));
+ struct vring_virtqueue *vq = NULL;
+ u16 ioaddr = vp_init_simple(bdf);
+ if (vp_find_vq(ioaddr, 2, &vq) < 0 ) {
+ dprintf(1, "fail to find vq for virtio-scsi %x:%x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+ goto fail;
+ }
+
+ vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+ VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
+
+ int i, tot;
+ for (tot = 0, i = 0; i < 256; i++)
+ tot += virtio_scsi_scan_target(pci, ioaddr, vq, i);
+
+ if (!tot)
+ goto fail;
+
+ return;
+
+fail:
+ vp_reset(ioaddr);
+ free(vq);
+}
+
+void
+virtio_scsi_setup(void)
+{
+ 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)
+ continue;
+ init_virtio_scsi(pci);
+ }
+}
diff --git a/roms/seabios/src/hw/virtio-scsi.h b/roms/seabios/src/hw/virtio-scsi.h
new file mode 100644
index 00000000..96c3701d
--- /dev/null
+++ b/roms/seabios/src/hw/virtio-scsi.h
@@ -0,0 +1,47 @@
+#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_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+void virtio_scsi_setup(void);
+
+#endif /* _VIRTIO_SCSI_H */
diff --git a/roms/seabios/src/jpeg.c b/roms/seabios/src/jpeg.c
new file mode 100644
index 00000000..c2138eda
--- /dev/null
+++ b/roms/seabios/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/src/kbd.c b/roms/seabios/src/kbd.c
new file mode 100644
index 00000000..a5a1ad9a
--- /dev/null
+++ b/roms/seabios/src/kbd.c
@@ -0,0 +1,576 @@
+// 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
+
+// Bit definitions for BDA kbd_flag[012]
+#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 KF1_LCTRL (1<<0)
+#define KF1_LALT (1<<1)
+#define KF1_PAUSEACTIVE (1<<3)
+#define KF1_SCROLL (1<<4)
+#define KF1_NUM (1<<5)
+#define KF1_CAPS (1<<6)
+
+#define KF2_LAST_E1 (1<<0)
+#define KF2_LAST_E0 (1<<1)
+#define KF2_RCTRL (1<<2)
+#define KF2_RALT (1<<3)
+#define KF2_101KBD (1<<4)
+
+void
+kbd_init(void)
+{
+ dprintf(3, "init keyboard\n");
+ u16 x = offsetof(struct bios_data_area_s, kbd_buf);
+ SET_BDA(kbd_flag2, KF2_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));
+}
+
+static u8
+enqueue_key(u8 scan_code, u8 ascii_code)
+{
+ 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, *(u8*)(temp_tail+0), ascii_code);
+ SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+1), scan_code);
+ 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();
+ }
+
+ u8 ascii_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+0));
+ u8 scan_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+1));
+ if ((ascii_code == 0xF0 && scan_code != 0)
+ || (ascii_code == 0xE0 && !extended))
+ ascii_code = 0;
+ regs->ax = (scan_code << 8) | ascii_code;
+
+ 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->ch, regs->cl);
+}
+
+// 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->al = GET_BDA(kbd_flag0);
+ regs->ah = ((GET_BDA(kbd_flag1) & ~(KF2_RCTRL|KF2_RALT))
+ | (GET_BDA(kbd_flag2) & (KF2_RCTRL|KF2_RALT)));
+ //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
+#define MNUM KF0_NUMACTIVE
+#define MCAP KF0_CAPSACTIVE
+
+static struct scaninfo {
+ u16 normal;
+ u16 shift;
+ u16 control;
+ u16 alt;
+ u8 lock_flags;
+} scan_to_scanascii[] VAR16 = {
+ { none, none, none, none, none },
+ { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
+ { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
+ { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
+ { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
+ { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
+ { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
+ { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
+ { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
+ { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
+ { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
+ { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
+ { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
+ { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
+ { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
+ { 0x0f09, 0x0f00, none, none, none }, /* tab */
+ { 0x1071, 0x1051, 0x1011, 0x1000, MCAP }, /* Q */
+ { 0x1177, 0x1157, 0x1117, 0x1100, MCAP }, /* W */
+ { 0x1265, 0x1245, 0x1205, 0x1200, MCAP }, /* E */
+ { 0x1372, 0x1352, 0x1312, 0x1300, MCAP }, /* R */
+ { 0x1474, 0x1454, 0x1414, 0x1400, MCAP }, /* T */
+ { 0x1579, 0x1559, 0x1519, 0x1500, MCAP }, /* Y */
+ { 0x1675, 0x1655, 0x1615, 0x1600, MCAP }, /* U */
+ { 0x1769, 0x1749, 0x1709, 0x1700, MCAP }, /* I */
+ { 0x186f, 0x184f, 0x180f, 0x1800, MCAP }, /* O */
+ { 0x1970, 0x1950, 0x1910, 0x1900, MCAP }, /* P */
+ { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
+ { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
+ { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
+ { none, none, none, none, none }, /* L Ctrl */
+ { 0x1e61, 0x1e41, 0x1e01, 0x1e00, MCAP }, /* A */
+ { 0x1f73, 0x1f53, 0x1f13, 0x1f00, MCAP }, /* S */
+ { 0x2064, 0x2044, 0x2004, 0x2000, MCAP }, /* D */
+ { 0x2166, 0x2146, 0x2106, 0x2100, MCAP }, /* F */
+ { 0x2267, 0x2247, 0x2207, 0x2200, MCAP }, /* G */
+ { 0x2368, 0x2348, 0x2308, 0x2300, MCAP }, /* H */
+ { 0x246a, 0x244a, 0x240a, 0x2400, MCAP }, /* J */
+ { 0x256b, 0x254b, 0x250b, 0x2500, MCAP }, /* K */
+ { 0x266c, 0x264c, 0x260c, 0x2600, MCAP }, /* L */
+ { 0x273b, 0x273a, none, none, none }, /* ;: */
+ { 0x2827, 0x2822, none, none, none }, /* '" */
+ { 0x2960, 0x297e, none, none, none }, /* `~ */
+ { none, none, none, none, none }, /* L shift */
+ { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
+ { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, MCAP }, /* Z */
+ { 0x2d78, 0x2d58, 0x2d18, 0x2d00, MCAP }, /* X */
+ { 0x2e63, 0x2e43, 0x2e03, 0x2e00, MCAP }, /* C */
+ { 0x2f76, 0x2f56, 0x2f16, 0x2f00, MCAP }, /* V */
+ { 0x3062, 0x3042, 0x3002, 0x3000, MCAP }, /* B */
+ { 0x316e, 0x314e, 0x310e, 0x3100, MCAP }, /* N */
+ { 0x326d, 0x324d, 0x320d, 0x3200, MCAP }, /* M */
+ { 0x332c, 0x333c, none, none, none }, /* ,< */
+ { 0x342e, 0x343e, none, none, none }, /* .> */
+ { 0x352f, 0x353f, none, none, none }, /* /? */
+ { none, none, none, none, none }, /* R Shift */
+ { 0x372a, 0x372a, none, none, none }, /* * */
+ { none, none, none, none, none }, /* L Alt */
+ { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
+ { none, none, none, none, none }, /* caps lock */
+ { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
+ { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
+ { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
+ { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
+ { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
+ { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
+ { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
+ { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
+ { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
+ { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
+ { none, none, none, none, none }, /* Num Lock */
+ { none, none, none, none, none }, /* Scroll Lock */
+ { 0x4700, 0x4737, 0x7700, none, MNUM }, /* 7 Home */
+ { 0x4800, 0x4838, none, none, MNUM }, /* 8 UP */
+ { 0x4900, 0x4939, 0x8400, none, MNUM }, /* 9 PgUp */
+ { 0x4a2d, 0x4a2d, none, none, none }, /* - */
+ { 0x4b00, 0x4b34, 0x7300, none, MNUM }, /* 4 Left */
+ { 0x4c00, 0x4c35, none, none, MNUM }, /* 5 */
+ { 0x4d00, 0x4d36, 0x7400, none, MNUM }, /* 6 Right */
+ { 0x4e2b, 0x4e2b, none, none, none }, /* + */
+ { 0x4f00, 0x4f31, 0x7500, none, MNUM }, /* 1 End */
+ { 0x5000, 0x5032, none, none, MNUM }, /* 2 Down */
+ { 0x5100, 0x5133, 0x7600, none, MNUM }, /* 3 PgDn */
+ { 0x5200, 0x5230, none, none, MNUM }, /* 0 Ins */
+ { 0x5300, 0x532e, none, none, MNUM }, /* Del */
+ { none, none, none, none, none },
+ { none, none, none, none, none },
+ { 0x565c, 0x567c, none, none, none }, /* \| */
+ { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
+ { 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */
+};
+
+// Handle a ps2 style scancode read from the keyboard.
+static void
+__process_key(u8 scancode)
+{
+ u8 flags0 = GET_BDA(kbd_flag0);
+ u8 flags1 = GET_BDA(kbd_flag1);
+ u8 flags2 = GET_BDA(kbd_flag2);
+
+ if (flags2 & KF2_LAST_E1) {
+ // Part of "pause" key (sequence is e1 1d 45 e1 9d c5)
+ if ((scancode & ~0x80) == 0x1d)
+ // Second key of sequence
+ return;
+ // Third key of sequence - clear flag.
+ flags2 &= ~KF2_LAST_E1;
+ SET_BDA(kbd_flag2, flags2);
+
+ if (scancode == 0xc5) {
+ // Final key in sequence.
+
+ // XXX - do actual pause.
+ }
+ return;
+ }
+
+ // XXX - PrtScr should cause int 0x05
+ // XXX - Ctrl+Break should cause int 0x1B
+ // XXX - SysReq should cause int 0x15/0x85
+
+ switch (scancode) {
+ case 0x00:
+ dprintf(1, "KBD: int09 handler: AL=0\n");
+ return;
+
+ case 0x3a: /* Caps Lock press */
+ flags0 ^= KF0_CAPSACTIVE;
+ flags1 |= KF1_CAPS;
+ break;
+ case 0xba: /* Caps Lock release */
+ flags1 &= ~KF1_CAPS;
+ break;
+
+ case 0x2a: /* L Shift press */
+ flags0 |= KF0_LSHIFT;
+ break;
+ case 0xaa: /* L Shift release */
+ flags0 &= ~KF0_LSHIFT;
+ break;
+
+ case 0x36: /* R Shift press */
+ flags0 |= KF0_RSHIFT;
+ break;
+ case 0xb6: /* R Shift release */
+ flags0 &= ~KF0_RSHIFT;
+ break;
+
+ case 0x1d: /* Ctrl press */
+ flags0 |= KF0_CTRLACTIVE;
+ if (flags2 & KF2_LAST_E0)
+ flags2 |= KF2_RCTRL;
+ else
+ flags1 |= KF1_LCTRL;
+ break;
+ case 0x9d: /* Ctrl release */
+ flags0 &= ~KF0_CTRLACTIVE;
+ if (flags2 & KF2_LAST_E0)
+ flags2 &= ~KF2_RCTRL;
+ else
+ flags1 &= ~KF1_LCTRL;
+ break;
+
+ case 0x38: /* Alt press */
+ flags0 |= KF0_ALTACTIVE;
+ if (flags2 & KF2_LAST_E0)
+ flags2 |= KF2_RALT;
+ else
+ flags1 |= KF1_LALT;
+ break;
+ case 0xb8: /* Alt release */
+ flags0 &= ~KF0_ALTACTIVE;
+ if (flags2 & KF2_LAST_E0)
+ flags2 &= ~KF2_RALT;
+ else
+ flags1 &= ~KF1_LALT;
+ break;
+
+ case 0x45: /* Num Lock press */
+ flags1 |= KF1_NUM;
+ flags0 ^= KF0_NUMACTIVE;
+ break;
+ case 0xc5: /* Num Lock release */
+ flags1 &= ~KF1_NUM;
+ break;
+
+ case 0x46: /* Scroll Lock press */
+ flags1 |= KF1_SCROLL;
+ flags0 ^= KF0_SCROLLACTIVE;
+ break;
+ case 0xc6: /* Scroll Lock release */
+ flags1 &= ~KF1_SCROLL;
+ break;
+
+ case 0xe0:
+ // Extended key
+ flags2 |= KF2_LAST_E0;
+ SET_BDA(kbd_flag2, flags2);
+ return;
+ case 0xe1:
+ // Start of pause key sequence
+ flags2 |= KF2_LAST_E1;
+ break;
+
+ default:
+ if (scancode & 0x80)
+ // toss key releases
+ break;
+ if (scancode == 0x53
+ && ((flags0 & (KF0_CTRLACTIVE|KF0_ALTACTIVE))
+ == (KF0_CTRLACTIVE|KF0_ALTACTIVE))) {
+ // Ctrl+alt+del - reset machine.
+ SET_BDA(soft_reset_flag, 0x1234);
+ reset();
+ }
+ if (scancode >= ARRAY_SIZE(scan_to_scanascii)) {
+ dprintf(1, "KBD: int09h_handler(): unknown scancode read: 0x%02x!\n"
+ , scancode);
+ return;
+ }
+ u8 asciicode;
+ struct scaninfo *info = &scan_to_scanascii[scancode];
+ if (flags0 & KF0_ALTACTIVE) {
+ asciicode = GET_GLOBAL(info->alt);
+ scancode = GET_GLOBAL(info->alt) >> 8;
+ } else if (flags0 & KF0_CTRLACTIVE) {
+ asciicode = GET_GLOBAL(info->control);
+ scancode = GET_GLOBAL(info->control) >> 8;
+ } else if (flags2 & KF2_LAST_E0
+ && scancode >= 0x47 && scancode <= 0x53) {
+ /* extended keys handling */
+ asciicode = 0xe0;
+ scancode = GET_GLOBAL(info->normal) >> 8;
+ } else if (flags0 & (KF0_RSHIFT|KF0_LSHIFT)) {
+ /* check if lock state should be ignored because a SHIFT
+ * key is pressed */
+
+ if (flags0 & GET_GLOBAL(info->lock_flags)) {
+ asciicode = GET_GLOBAL(info->normal);
+ scancode = GET_GLOBAL(info->normal) >> 8;
+ } else {
+ asciicode = GET_GLOBAL(info->shift);
+ scancode = GET_GLOBAL(info->shift) >> 8;
+ }
+ } else {
+ /* check if lock is on */
+ if (flags0 & GET_GLOBAL(info->lock_flags)) {
+ asciicode = GET_GLOBAL(info->shift);
+ scancode = GET_GLOBAL(info->shift) >> 8;
+ } else {
+ asciicode = GET_GLOBAL(info->normal);
+ scancode = GET_GLOBAL(info->normal) >> 8;
+ }
+ }
+ if (scancode==0 && asciicode==0)
+ dprintf(1, "KBD: scancode & asciicode are zero?\n");
+ enqueue_key(scancode, asciicode);
+ break;
+ }
+ flags2 &= ~KF2_LAST_E0;
+
+ SET_BDA(kbd_flag0, flags0);
+ SET_BDA(kbd_flag1, flags1);
+ SET_BDA(kbd_flag2, flags2);
+}
+
+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/src/list.h b/roms/seabios/src/list.h
new file mode 100644
index 00000000..de656b9d
--- /dev/null
+++ b/roms/seabios/src/list.h
@@ -0,0 +1,81 @@
+#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);
+}
+
+#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/src/malloc.c b/roms/seabios/src/malloc.c
new file mode 100644
index 00000000..c4cb1714
--- /dev/null
+++ b/roms/seabios/src/malloc.c
@@ -0,0 +1,541 @@
+// 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 "list.h" // hlist_node
+#include "malloc.h" // _malloc
+#include "memmap.h" // struct e820entry
+#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;
+ void *data, *dataend, *allocend;
+};
+
+// 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 void *
+allocSpace(struct zone_s *zone, u32 size, u32 align, struct allocinfo_s *fill)
+{
+ struct allocinfo_s *info;
+ hlist_for_each_entry(info, &zone->head, node) {
+ void *dataend = info->dataend;
+ void *allocend = info->allocend;
+ void *newallocend = (void*)ALIGN_DOWN((u32)allocend - size, align);
+ if (newallocend >= dataend && newallocend <= allocend) {
+ // Found space - now reserve it.
+ if (!fill)
+ fill = newallocend;
+ fill->data = newallocend;
+ fill->dataend = newallocend + size;
+ fill->allocend = allocend;
+
+ info->allocend = newallocend;
+ hlist_add_before(&fill->node, &info->node);
+ return newallocend;
+ }
+ }
+ return NULL;
+}
+
+// Release space allocated with allocSpace()
+static void
+freeSpace(struct allocinfo_s *info)
+{
+ struct allocinfo_s *next = container_of_or_null(
+ info->node.next, struct allocinfo_s, node);
+ if (next && next->allocend == info->data)
+ next->allocend = info->allocend;
+ hlist_del(&info->node);
+}
+
+// Add new memory to a zone
+static void
+addSpace(struct zone_s *zone, void *start, void *end)
+{
+ // Find position to add space
+ struct allocinfo_s *info;
+ struct hlist_node **pprev;
+ hlist_for_each_entry_pprev(info, pprev, &zone->head, node) {
+ if (info->data < start)
+ break;
+ }
+
+ // Add space using temporary allocation info.
+ struct allocdetail_s tempdetail;
+ tempdetail.datainfo.data = tempdetail.datainfo.dataend = start;
+ tempdetail.datainfo.allocend = end;
+ hlist_add(&tempdetail.datainfo.node, pprev);
+
+ // Allocate final allocation info.
+ struct allocdetail_s *detail = allocSpace(
+ &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL);
+ if (!detail) {
+ detail = allocSpace(&ZoneTmpLow, sizeof(*detail)
+ , MALLOC_MIN_ALIGN, NULL);
+ if (!detail) {
+ hlist_del(&tempdetail.datainfo.node);
+ warn_noalloc();
+ return;
+ }
+ }
+
+ // Replace temp alloc space with final alloc space
+ pprev = tempdetail.datainfo.node.pprev;
+ hlist_del(&tempdetail.datainfo.node);
+ memcpy(&detail->datainfo, &tempdetail.datainfo, sizeof(detail->datainfo));
+ detail->handle = MALLOC_DEFAULT_HANDLE;
+ hlist_add(&detail->datainfo.node, pprev);
+}
+
+// Search all zones for an allocation obtained from allocSpace()
+static struct allocinfo_s *
+findAlloc(void *data)
+{
+ int i;
+ for (i=0; i<ARRAY_SIZE(Zones); i++) {
+ struct allocinfo_s *info;
+ hlist_for_each_entry(info, &Zones[i]->head, node) {
+ if (info->data == data)
+ return info;
+ }
+ }
+ return NULL;
+}
+
+// Return the last sentinal node of a zone
+static struct allocinfo_s *
+findLast(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 void *
+zonelow_expand(u32 size, u32 align, struct allocinfo_s *fill)
+{
+ // Make sure to not move ebda while an optionrom is running.
+ if (unlikely(wait_preempt())) {
+ void *data = allocSpace(&ZoneLow, size, align, fill);
+ if (data)
+ return data;
+ }
+
+ struct allocinfo_s *info = findLast(&ZoneLow);
+ if (!info)
+ return NULL;
+ u32 oldpos = (u32)info->allocend;
+ u32 newpos = ALIGN_DOWN(oldpos - size, align);
+ u32 bottom = (u32)info->dataend;
+ if (newpos >= bottom && newpos <= oldpos)
+ // Space already present.
+ return allocSpace(&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 NULL;
+
+ // Move ebda
+ int ret = relocate_ebda(newebda, ebda_pos, ebda_size);
+ if (ret)
+ return NULL;
+
+ // Update zone
+ if (ebda_end == bottom) {
+ info->data = (void*)newbottom;
+ info->dataend = (void*)newbottom;
+ } else
+ addSpace(&ZoneLow, (void*)newbottom, (void*)ebda_end);
+
+ return allocSpace(&ZoneLow, size, align, fill);
+}
+
+
+/****************************************************************
+ * tracked memory allocations
+ ****************************************************************/
+
+// Allocate memory from the given zone and track it as a PMM allocation
+void * __malloc
+_malloc(struct zone_s *zone, u32 size, u32 align)
+{
+ ASSERT32FLAT();
+ if (!size)
+ return NULL;
+
+ // Find and reserve space for bookkeeping.
+ struct allocdetail_s *detail = allocSpace(
+ &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL);
+ if (!detail) {
+ detail = allocSpace(&ZoneTmpLow, sizeof(*detail)
+ , MALLOC_MIN_ALIGN, NULL);
+ if (!detail)
+ return NULL;
+ }
+ detail->handle = MALLOC_DEFAULT_HANDLE;
+
+ // Find and reserve space for main allocation
+ void *data = allocSpace(zone, size, align, &detail->datainfo);
+ if (!CONFIG_MALLOC_UPPERMEMORY && !data && zone == &ZoneLow)
+ data = zonelow_expand(size, align, &detail->datainfo);
+ if (!data) {
+ freeSpace(&detail->detailinfo);
+ return NULL;
+ }
+
+ dprintf(8, "_malloc zone=%p size=%d align=%x ret=%p (detail=%p)\n"
+ , zone, size, align, data, detail);
+
+ return data;
+}
+
+// Free a data block allocated with _malloc
+int
+_free(void *data)
+{
+ ASSERT32FLAT();
+ struct allocinfo_s *info = findAlloc(data);
+ if (!info || data == (void*)info || data == info->dataend)
+ return -1;
+ struct allocdetail_s *detail = container_of(
+ info, struct allocdetail_s, datainfo);
+ dprintf(8, "_free %p (detail=%p)\n", data, detail);
+ freeSpace(info);
+ freeSpace(&detail->detailinfo);
+ return 0;
+}
+
+// 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->allocend - info->dataend;
+ 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(void *data, u32 handle)
+{
+ ASSERT32FLAT();
+ struct allocinfo_s *info = findAlloc(data);
+ if (!info || data == (void*)info || data == info->dataend)
+ return;
+ struct allocdetail_s *detail = container_of(
+ info, struct allocdetail_s, datainfo);
+ detail->handle = handle;
+}
+
+// Find the data block allocated with _malloc with a given handle.
+void *
+malloc_findhandle(u32 handle)
+{
+ int i;
+ for (i=0; i<ARRAY_SIZE(Zones); i++) {
+ struct allocinfo_s *info;
+ hlist_for_each_entry(info, &Zones[i]->head, node) {
+ if (info->data != (void*)info)
+ continue;
+ struct allocdetail_s *detail = container_of(
+ info, struct allocdetail_s, detailinfo);
+ if (detail->handle == handle)
+ return detail->datainfo.data;
+ }
+ }
+ return NULL;
+}
+
+
+/****************************************************************
+ * 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((u32)RomBase->allocend - OPROM_HEADER_RESERVE
+ , OPTION_ROM_ALIGN);
+ extern u8 final_readonly_start[];
+ return (u32)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 < (u32)zonelow_base)
+ newend = (u32)zonelow_base;
+ RomBase->data = RomBase->dataend = (void*)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
+ add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE);
+
+ // Mark known areas as reserved.
+ add_e820(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;
+ }
+ }
+ addSpace(&ZoneTmpHigh, (void*)s, (void*)e);
+ }
+
+ // Populate regions
+ addSpace(&ZoneTmpLow, (void*)BUILD_STACK_ADDR, (void*)BUILD_EBDA_MINIMUM);
+ if (highram) {
+ addSpace(&ZoneHigh, (void*)highram
+ , (void*)highram + BUILD_MAX_HIGHTABLE);
+ add_e820(highram, BUILD_MAX_HIGHTABLE, E820_RESERVED);
+ }
+}
+
+void
+csm_malloc_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm, u32 hi_pmm_size)
+{
+ ASSERT32FLAT();
+
+ if (hi_pmm_size > BUILD_MAX_HIGHTABLE) {
+ void *hi_pmm_end = (void *)hi_pmm + hi_pmm_size;
+ addSpace(&ZoneTmpHigh, (void *)hi_pmm, hi_pmm_end - BUILD_MAX_HIGHTABLE);
+ addSpace(&ZoneHigh, hi_pmm_end - BUILD_MAX_HIGHTABLE, hi_pmm_end);
+ } else {
+ addSpace(&ZoneTmpHigh, (void *)hi_pmm, (void *)hi_pmm + hi_pmm_size);
+ }
+ addSpace(&ZoneTmpLow, (void *)low_pmm, (void *)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
+ extern u8 varlow_start[], varlow_end[], final_varlow_start[];
+ memmove(final_varlow_start, varlow_start, varlow_end - varlow_start);
+ if (CONFIG_MALLOC_UPPERMEMORY) {
+ addSpace(&ZoneLow, zonelow_base + OPROM_HEADER_RESERVE
+ , final_varlow_start);
+ RomBase = findLast(&ZoneLow);
+ } else {
+ addSpace(&ZoneLow, (void*)ALIGN_DOWN((u32)final_varlow_start, 1024)
+ , final_varlow_start);
+ }
+
+ // Add space available in f-segment to ZoneFSeg
+ extern u8 zonefseg_start[], zonefseg_end[];
+ memset(zonefseg_start, 0, zonefseg_end - zonefseg_start);
+ addSpace(&ZoneFSeg, zonefseg_start, zonefseg_end);
+
+ 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;
+ add_e820(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED);
+
+ // Clear unused f-seg ram.
+ struct allocinfo_s *info = findLast(&ZoneFSeg);
+ memset(info->dataend, 0, info->allocend - info->dataend);
+ dprintf(1, "Space available for UMB: %x-%x, %x-%x\n"
+ , RomEnd, base, (u32)info->dataend, (u32)info->allocend);
+
+ // Give back unused high ram.
+ info = findLast(&ZoneHigh);
+ if (info) {
+ u32 giveback = ALIGN_DOWN(info->allocend - info->dataend, PAGE_SIZE);
+ add_e820((u32)info->dataend, giveback, E820_RAM);
+ dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback);
+ }
+
+ calcRamSize();
+}
diff --git a/roms/seabios/src/malloc.h b/roms/seabios/src/malloc.h
new file mode 100644
index 00000000..2bcb5bf6
--- /dev/null
+++ b/roms/seabios/src/malloc.h
@@ -0,0 +1,71 @@
+#ifndef __MALLOC_H
+#define __MALLOC_H
+
+#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 csm_malloc_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);
+void *_malloc(struct zone_s *zone, u32 size, u32 align);
+int _free(void *data);
+u32 malloc_getspace(struct zone_s *zone);
+void malloc_sethandle(void *data, u32 handle);
+void *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);
+}
+static inline void free(void *data) {
+ _free(data);
+}
+
+#endif // malloc.h
diff --git a/roms/seabios/src/memmap.c b/roms/seabios/src/memmap.c
new file mode 100644
index 00000000..e03f8d0b
--- /dev/null
+++ b/roms/seabios/src/memmap.c
@@ -0,0 +1,144 @@
+// 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 "memmap.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";
+ case E820_HOLE: return "HOLE";
+ 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));
+ }
+}
+
+// Add a new entry to the list. This scans for overlaps and keeps the
+// list sorted.
+void
+add_e820(u64 start, u64 size, u32 type)
+{
+ dprintf(8, "Add to e820 map: %08x %08x %d\n", (u32)start, (u32)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();
+}
+
+// Report on final memory locations.
+void
+memmap_prepboot(void)
+{
+ dump_map();
+}
diff --git a/roms/seabios/src/memmap.h b/roms/seabios/src/memmap.h
new file mode 100644
index 00000000..7bda56e2
--- /dev/null
+++ b/roms/seabios/src/memmap.h
@@ -0,0 +1,29 @@
+#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
+#define E820_HOLE ((u32)-1) // Useful for removing entries
+
+struct e820entry {
+ u64 start;
+ u64 size;
+ u32 type;
+};
+
+void add_e820(u64 start, u64 size, u32 type);
+void memmap_prepboot(void);
+
+// A typical OS page size
+#define PAGE_SIZE 4096
+
+// e820 map storage
+extern struct e820entry e820_list[];
+extern int e820_count;
+
+#endif // e820map.h
diff --git a/roms/seabios/src/misc.c b/roms/seabios/src/misc.c
new file mode 100644
index 00000000..8caaf31d
--- /dev/null
+++ b/roms/seabios/src/misc.c
@@ -0,0 +1,203 @@
+// 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);
+}
+
+// INT 10h Video Support Service Entry Point
+void VISIBLE16
+handle_10(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_10);
+ // dont do anything, since the VGA BIOS handles int10h requests
+}
+
+// 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/src/mouse.c b/roms/seabios/src/mouse.c
new file mode 100644
index 00000000..6d1f5b77
--- /dev/null
+++ b/roms/seabios/src/mouse.c
@@ -0,0 +1,343 @@
+// 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()) {
+ extern void _cfunc16_invoke_mouse_handler(void);
+ stack_hop_back(0, 0, _cfunc16_invoke_mouse_handler);
+ 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/src/optionroms.c b/roms/seabios/src/optionroms.c
new file mode 100644
index 00000000..93d9d2fe
--- /dev/null
+++ b/roms/seabios/src/optionroms.c
@@ -0,0 +1,475 @@
+// 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 "hw/pci.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
+
+
+/****************************************************************
+ * 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);
+}
+
+static int EnforceChecksum;
+
+// 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);
+
+ 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;
+}
+
+// Check if an option rom is at a hardcoded location or in CBFS.
+static struct rom_header *
+lookup_hardcode(struct pci_device *pci)
+{
+ char fname[17];
+ snprintf(fname, sizeof(fname), "pci%04x,%04x.rom"
+ , pci->vendor, pci->device);
+ struct romfile_s *file = romfile_find(fname);
+ if (file)
+ return deploy_romfile(file);
+ return NULL;
+}
+
+// Run all roms in a given CBFS directory.
+static void
+run_file_roms(const char *prefix, int isvga, u64 *sources)
+{
+ 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)
+{
+ u16 bdf = pci->bdf;
+ dprintf(6, "Attempting to map option rom on dev %02x:%02x.%x\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf));
+
+ if ((pci->header_type & 0x7f) != PCI_HEADER_TYPE_NORMAL) {
+ dprintf(6, "Skipping non-normal pci device (type=%x)\n"
+ , pci->header_type);
+ return NULL;
+ }
+
+ 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=%02x:%02x.%x)\n"
+ , rom, pci->vendor, pci->device
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf));
+ 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;
+}
+
+// Attempt to map and initialize the option rom on a given PCI device.
+static int
+init_pcirom(struct pci_device *pci, int isvga, u64 *sources)
+{
+ u16 bdf = pci->bdf;
+ dprintf(4, "Attempting to init PCI bdf %02x:%02x.%x (vd %04x:%04x)\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf)
+ , pci->vendor, pci->device);
+ struct rom_header *rom = lookup_hardcode(pci);
+ if (! rom)
+ rom = map_pcirom(pci);
+ if (! rom)
+ // No ROM present.
+ return -1;
+ setRomSource(sources, rom, RS_PCIROM | (u32)pci);
+ return init_optionrom(rom, bdf, isvga);
+}
+
+
+/****************************************************************
+ * 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();
+
+ if (CONFIG_OPTIONROMS_DEPLOYED) {
+ // Option roms are already deployed on the system.
+ u32 pos = post_vga;
+ while (pos < rom_get_max()) {
+ int ret = init_optionrom((void*)pos, 0, 0);
+ if (ret)
+ pos += OPTION_ROM_ALIGN;
+ else
+ pos = rom_get_last();
+ }
+ } else {
+ // Find and deploy PCI roms.
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->class == PCI_CLASS_DISPLAY_VGA || 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
+ ****************************************************************/
+
+static int S3ResumeVga;
+int ScreenAndDebug;
+struct rom_header *VgaROM;
+
+// Call into vga code to turn on console.
+void
+vgarom_setup(void)
+{
+ 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);
+ ScreenAndDebug = romfile_loadint("etc/screen-and-debug", 1);
+
+ if (CONFIG_OPTIONROMS_DEPLOYED) {
+ // Option roms are already deployed on the system.
+ init_optionrom((void*)BUILD_ROM_START, 0, 1);
+ } else {
+ // 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);
+ break;
+ }
+
+ // 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)
+ // No VGA rom found
+ return;
+
+ VgaROM = (void*)BUILD_ROM_START;
+ enable_vga_console();
+}
+
+void
+s3_resume_vga(void)
+{
+ if (!S3ResumeVga)
+ return;
+ if (!VgaROM || ! is_valid_rom(VgaROM))
+ return;
+ callrom(VgaROM, 0);
+}
diff --git a/roms/seabios/src/output.c b/roms/seabios/src/output.c
new file mode 100644
index 00000000..45397b3f
--- /dev/null
+++ b/roms/seabios/src/output.c
@@ -0,0 +1,564 @@
+// 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/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
+
+struct putcinfo {
+ void (*func)(struct putcinfo *info, char c);
+};
+
+
+/****************************************************************
+ * Debug output
+ ****************************************************************/
+
+void
+debug_banner(void)
+{
+ dprintf(1, "SeaBIOS (version %s)\n", VERSION);
+}
+
+// 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);
+ 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)
+{
+ 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);
+}
+
+// Handle a character from a printf request.
+static void
+screen_putc(struct putcinfo *action, char c)
+{
+ if (ScreenAndDebug)
+ debug_putc(&debuginfo, c);
+ if (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
+putuint(struct putcinfo *action, u32 val)
+{
+ char buf[12];
+ 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)
+{
+ if (val <= 9)
+ val = '0' + val;
+ 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)
+{
+ switch (width) {
+ default: putsinglehex(action, (val >> 28) & 0xf);
+ case 7: putsinglehex(action, (val >> 24) & 0xf);
+ case 6: putsinglehex(action, (val >> 20) & 0xf);
+ case 5: putsinglehex(action, (val >> 16) & 0xf);
+ case 4: putsinglehex(action, (val >> 12) & 0xf);
+ case 3: putsinglehex(action, (val >> 8) & 0xf);
+ case 2: putsinglehex(action, (val >> 4) & 0xf);
+ case 1: putsinglehex(action, (val >> 0) & 0xf);
+ }
+}
+
+// Output an integer in hexadecimal with a minimum width.
+static void
+putprettyhex(struct putcinfo *action, u32 val, int width, char padchar)
+{
+ u32 tmp = val;
+ int count = 1;
+ while (tmp >>= 4)
+ count++;
+ width -= count;
+ while (width-- > 0)
+ putc(action, padchar);
+ puthex(action, val, count);
+}
+
+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;
+ 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;
+ const char *sarg;
+ switch (c) {
+ case '%':
+ putc(action, '%');
+ break;
+ case 'd':
+ val = va_arg(args, s32);
+ if (is64)
+ va_arg(args, s32);
+ if (val < 0) {
+ putc(action, '-');
+ val = -val;
+ }
+ putuint(action, val);
+ break;
+ case 'u':
+ val = va_arg(args, s32);
+ if (is64)
+ va_arg(args, s32);
+ putuint(action, val);
+ break;
+ case 'p':
+ val = va_arg(args, s32);
+ putc(action, '0');
+ putc(action, 'x');
+ puthex(action, val, 8);
+ break;
+ case 'x':
+ val = va_arg(args, s32);
+ if (is64) {
+ u32 upper = va_arg(args, s32);
+ if (upper) {
+ putprettyhex(action, upper, field_width - 8, padchar);
+ puthex(action, val, 8);
+ break;
+ }
+ }
+ putprettyhex(action, val, field_width, padchar);
+ 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);
+ 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);
+ putc(&debuginfo, ':');
+ } else {
+ putc(&debuginfo, ' ');
+ }
+ puthex(&debuginfo, *(u32*)d, 8);
+ 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/src/output.h b/roms/seabios/src/output.h
new file mode 100644
index 00000000..14288cf5
--- /dev/null
+++ b/roms/seabios/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/src/pcibios.c b/roms/seabios/src/pcibios.c
new file mode 100644
index 00000000..7e5d972d
--- /dev/null
+++ b/roms/seabios/src/pcibios.c
@@ -0,0 +1,240 @@
+// 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/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/src/pmm.c b/roms/seabios/src/pmm.c
new file mode 100644
index 00000000..304faab2
--- /dev/null
+++ b/roms/seabios/src/pmm.c
@@ -0,0 +1,163 @@
+// 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 "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;
+ }
+ void *data;
+ switch (flags & 3) {
+ default:
+ case 0:
+ return 0;
+ case 1:
+ data = _malloc(lowzone, size, align);
+ break;
+ case 2:
+ data = _malloc(highzone, size, align);
+ break;
+ case 3: {
+ data = _malloc(lowzone, size, align);
+ if (!data)
+ data = _malloc(highzone, size, align);
+ }
+ }
+ if (data && handle != MALLOC_DEFAULT_HANDLE)
+ malloc_sethandle(data, handle);
+ return (u32)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 (u32)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 = _free((void*)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/src/pnpbios.c b/roms/seabios/src/pnpbios.c
new file mode 100644
index 00000000..95ce21f8
--- /dev/null
+++ b/roms/seabios/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/src/post.c b/roms/seabios/src/post.c
new file mode 100644
index 00000000..9ea5620c
--- /dev/null
+++ b/roms/seabios/src/post.c
@@ -0,0 +1,336 @@
+// 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 "bregs.h" // struct bregs
+#include "config.h" // CONFIG_*
+#include "fw/paravirt.h" // qemu_cfg_preinit
+#include "fw/xen.h" // xen_preinit
+#include "hw/ahci.h" // ahci_setup
+#include "hw/ata.h" // ata_setup
+#include "hw/esp-scsi.h" // esp_scsi_setup
+#include "hw/lsi-scsi.h" // lsi_scsi_setup
+#include "hw/megasas.h" // megasas_setup
+#include "hw/pvscsi.h" // pvscsi_setup
+#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 "hw/virtio-blk.h" // virtio_blk_setup
+#include "hw/virtio-scsi.h" // virtio_scsi_setup
+#include "malloc.h" // malloc_init
+#include "memmap.h" // add_e820
+#include "output.h" // dprintf
+#include "string.h" // memset
+#include "util.h" // kbd_init
+
+
+/****************************************************************
+ * BIOS initialization and hardware setup
+ ****************************************************************/
+
+static void
+ivt_init(void)
+{
+ dprintf(3, "init ivt\n");
+
+ // Setup reset-vector entry point (controls legacy reboots).
+ HaveRunPost = 1;
+ rtc_write(CMOS_RESET_CODE, 0);
+
+ // 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(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 = MAKE_FLATPTR(SEG_BDA, 0);
+ memset(bda, 0, sizeof(*bda));
+
+ int esize = EBDA_SIZE_START;
+ u16 ebda_seg = EBDA_SEGMENT_START;
+ extern u8 final_varlow_start[];
+ if (!CONFIG_MALLOC_UPPERMEMORY)
+ ebda_seg = FLATPTR_TO_SEG(ALIGN_DOWN((u32)final_varlow_start, 1024)
+ - EBDA_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;
+
+ add_e820((u32)ebda, BUILD_LOWRAM_END-(u32)ebda, E820_RESERVED);
+
+ // Init extra stack
+ StackPos = (void*)(&ExtraStack[BUILD_EXTRA_STACK_SIZE] - 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();
+
+ // Setup ivt/bda/ebda
+ ivt_init();
+ bda_init();
+
+ // Other interfaces
+ thread_init();
+ boot_init();
+ bios32_init();
+ pmm_init();
+ pnp_init();
+ kbd_init();
+ mouse_init();
+}
+
+// Initialize hardware devices
+void
+device_hardware_setup(void)
+{
+ usb_setup();
+ ps2port_setup();
+ lpt_setup();
+ serial_setup();
+
+ floppy_setup();
+ ata_setup();
+ ahci_setup();
+ sdcard_setup();
+ cbfs_payload_setup();
+ ramdisk_setup();
+ virtio_blk_setup();
+ virtio_scsi_setup();
+ lsi_scsi_setup();
+ esp_scsi_setup();
+ megasas_setup();
+ pvscsi_setup();
+}
+
+static void
+platform_hardware_setup(void)
+{
+ // Enable CPU caching
+ setcr0(getcr0() & ~(CR0_CD|CR0_NW));
+
+ // Make sure legacy DMA isn't running.
+ dma_setup();
+
+ // Init base pc hardware.
+ pic_setup();
+ mathcp_setup();
+ timer_setup();
+ clock_setup();
+
+ // Platform specific setup
+ qemu_platform_setup();
+ coreboot_platform_setup();
+}
+
+void
+prepareboot(void)
+{
+ // Run BCVs
+ bcv_prepboot();
+
+ // Finalize data structures before boot
+ cdrom_prepboot();
+ pmm_prepboot();
+ malloc_prepboot();
+ memmap_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();
+
+ // 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);
+ // Symbols populated by the build.
+ extern u8 code32flat_start[];
+ extern u8 _reloc_min_align;
+ extern u32 _reloc_abs_start[], _reloc_abs_end[];
+ extern u32 _reloc_rel_start[], _reloc_rel_end[];
+ extern u32 _reloc_init_start[], _reloc_init_end[];
+ extern u8 code32init_start[], code32init_end[];
+
+ // Allocate space for init code.
+ u32 initsize = code32init_end - code32init_start;
+ u32 codealign = (u32)&_reloc_min_align;
+ void *codedest = memalign_tmp(codealign, initsize);
+ if (!codedest)
+ panic("No space for init relocation.\n");
+
+ // Copy code and update relocs (init absolute, init relative, and runtime)
+ dprintf(1, "Relocating init from %p to %p (size %d)\n"
+ , code32init_start, codedest, initsize);
+ s32 delta = codedest - (void*)code32init_start;
+ memcpy(codedest, code32init_start, initsize);
+ updateRelocs(codedest, _reloc_abs_start, _reloc_abs_end, delta);
+ updateRelocs(codedest, _reloc_rel_start, _reloc_rel_end, -delta);
+ updateRelocs(code32flat_start, _reloc_init_start, _reloc_init_end, delta);
+ if (f >= (void*)code32init_start && f < (void*)code32init_end)
+ func = f + delta;
+
+ // Call function in relocated code.
+ barrier();
+ func(arg);
+}
+
+// Setup for code relocation and then relocate.
+void VISIBLE32INIT
+dopost(void)
+{
+ // 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/src/resume.c b/roms/seabios/src/resume.c
new file mode 100644
index 00000000..19031747
--- /dev/null
+++ b/roms/seabios/src/resume.c
@@ -0,0 +1,158 @@
+// 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
+
+// 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();
+
+ pci_resume();
+
+ s3_resume_vga();
+
+ 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);
+}
+
+u8 HaveAttemptedReboot VARLOW;
+
+// Attempt to invoke a hard-reboot.
+static void
+tryReboot(void)
+{
+ if (HaveAttemptedReboot) {
+ // Hard reboot has failed - try to shutdown machine.
+ dprintf(1, "Unable to hard-reboot machine - attempting shutdown.\n");
+ apm_shutdown();
+ }
+ HaveAttemptedReboot = 1;
+
+ dprintf(1, "Attempting a hard reboot\n");
+
+ // Setup for reset on qemu.
+ qemu_prep_reset();
+
+ // 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/src/romfile.c b/roms/seabios/src/romfile.c
new file mode 100644
index 00000000..42261a62
--- /dev/null
+++ b/roms/seabios/src/romfile.c
@@ -0,0 +1,100 @@
+// 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 "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;
+ return val;
+}
diff --git a/roms/seabios/src/romfile.h b/roms/seabios/src/romfile.h
new file mode 100644
index 00000000..c6d62a1d
--- /dev/null
+++ b/roms/seabios/src/romfile.h
@@ -0,0 +1,19 @@
+#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);
+
+#endif // romfile.h
diff --git a/roms/seabios/src/romlayout.S b/roms/seabios/src/romlayout.S
new file mode 100644
index 00000000..93b6874e
--- /dev/null
+++ b/roms/seabios/src/romlayout.S
@@ -0,0 +1,659 @@
+// 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
+transition32_nmi_off:
+ // transition32 when NMI and A20 are already initialized
+ movl %eax, %ecx
+ jmp 1f
+transition32:
+ movl %eax, %ecx
+
+ // Disable irqs (and clear direction flag)
+ cli
+ cld
+
+ // Disable nmi
+ 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
+
+ // Set segment descriptors
+1: lidtw %cs:pmode_IDT_info
+ lgdtw %cs:rombios32_gdt_48
+
+ // Enable protected mode
+ movl %cr0, %eax
+ orl $CR0_PE, %eax
+ movl %eax, %cr0
+
+ // start 32bit protected mode code
+ ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 2f)
+
+ .code32
+ // init data segments
+2: movl $SEG32_MODE32_DS, %eax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %fs
+ movw %ax, %gs
+
+ movl %ecx, %eax
+ 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:
+ movl %eax, %ecx
+
+ // restore data segment limits to 0xffff
+ movl $SEG32_MODE16_DS, %eax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %fs
+ movw %ax, %gs
+
+#if CONFIG_DISABLE_A20
+ // disable a20
+ inb $PORT_A20, %al
+ andb $~A20_ENABLE_BIT, %al
+ outb %al, $PORT_A20
+#endif
+
+ // Jump to 16bit mode
+ ljmpw $SEG32_MODE16_CS, $1f
+
+transition16big:
+ movl %eax, %ecx
+
+ movl $SEG32_MODE16BIG_DS, %eax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %fs
+ movw %ax, %gs
+
+ ljmpw $SEG32_MODE16BIG_CS, $1f
+
+ .code16
+1:
+ // Disable protected mode
+ movl %cr0, %eax
+ andl $~CR0_PE, %eax
+ movl %eax, %cr0
+
+ // far jump to flush CPU queue after transition to real mode
+ ljmpw $SEG_BIOS, $2f
+
+2:
+ // restore IDT to normal real-mode defaults
+ lidtw %cs:rmode_IDT_info
+
+ // Clear segment registers
+ xorw %ax, %ax
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %es
+ movw %ax, %ds
+ movw %ax, %ss // Assume stack is in segment 0
+
+ movl %ecx, %eax
+ 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 10
+ IRQ_TRAMPOLINE 13
+ IRQ_TRAMPOLINE 15
+ IRQ_TRAMPOLINE 16
+ IRQ_TRAMPOLINE 18
+ IRQ_TRAMPOLINE 19
+ 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
+ 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
+
+
+/****************************************************************
+ * 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
+ IRQ_ENTRY 02
+
+ 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
+ IRQ_ENTRY_ARG 10
+
+ // 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/src/serial.c b/roms/seabios/src/serial.c
new file mode 100644
index 00000000..88349c8a
--- /dev/null
+++ b/roms/seabios/src/serial.c
@@ -0,0 +1,317 @@
+// 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(u16 port, u8 timeout, u8 count)
+{
+ if (CONFIG_DEBUG_SERIAL && port == CONFIG_DEBUG_SERIAL_PORT
+ && !romfile_loadint("etc/advertise-serial-debug-port", 1))
+ 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/src/stacks.c b/roms/seabios/src/stacks.c
new file mode 100644
index 00000000..1dbdfe9b
--- /dev/null
+++ b/roms/seabios/src/stacks.c
@@ -0,0 +1,827 @@
+// Code for manipulating stack locations.
+//
+// Copyright (C) 2009-2014 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 "util.h" // useRTC
+
+#define MAIN_STACK_MAX (1024*1024)
+
+
+/****************************************************************
+ * 16bit / 32bit calling
+ ****************************************************************/
+
+struct {
+ u8 method;
+ u8 cmosindex;
+ u8 a20;
+ u16 ss, fs, gs;
+ struct descloc_s gdt;
+} Call32Data VARLOW;
+
+#define C32_SLOPPY 1
+#define C32_SMM 2
+
+int HaveSmmCall32 VARFSEG;
+
+// Backup state in preparation for call32_smm()
+static void
+call32_smm_prep(void)
+{
+ // Backup cmos index register and disable nmi
+ u8 cmosindex = inb(PORT_CMOS_INDEX);
+ outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX);
+ inb(PORT_CMOS_DATA);
+ SET_LOW(Call32Data.cmosindex, cmosindex);
+
+ // Backup ss
+ SET_LOW(Call32Data.ss, GET_SEG(SS));
+
+ SET_LOW(Call32Data.method, C32_SMM);
+}
+
+// Restore state backed up during call32_smm()
+static void
+call32_smm_post(void)
+{
+ SET_LOW(Call32Data.method, 0);
+ SET_LOW(Call32Data.ss, 0);
+
+ // Restore cmos index register
+ outb(GET_LOW(Call32Data.cmosindex), PORT_CMOS_INDEX);
+ inb(PORT_CMOS_DATA);
+}
+
+#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_smm_prep();
+ 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_smm_post();
+
+ dprintf(9, "call32_smm done %p %x\n", func, eax);
+ return eax;
+}
+
+// 16bit handler code called from call16_smm()
+u32 VISIBLE16
+call16_smm_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx))
+{
+ if (!CONFIG_CALL32_SMM)
+ return eax;
+ call32_smm_post();
+ u32 ret = func(eax, edx);
+ call32_smm_prep();
+ return ret;
+}
+
+static u32
+call16_smm(u32 eax, u32 edx, void *func)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_CALL32_SMM)
+ return eax;
+ func -= BUILD_BIOS_ADDR;
+ dprintf(9, "call16_smm %p %x %x\n", func, eax, edx);
+ u32 stackoffset = Call32Data.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_smm_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;
+}
+
+// Backup state in preparation for call32_sloppy()
+static void
+call32_sloppy_prep(void)
+{
+ // Backup cmos index register and disable nmi
+ u8 cmosindex = inb(PORT_CMOS_INDEX);
+ outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX);
+ inb(PORT_CMOS_DATA);
+ SET_LOW(Call32Data.cmosindex, cmosindex);
+
+ // Enable a20 and backup it's previous state
+ SET_LOW(Call32Data.a20, set_a20(1));
+
+ // Backup ss/fs/gs and gdt
+ SET_LOW(Call32Data.ss, GET_SEG(SS));
+ SET_LOW(Call32Data.fs, GET_SEG(FS));
+ SET_LOW(Call32Data.gs, GET_SEG(GS));
+ struct descloc_s gdt;
+ sgdt(&gdt);
+ SET_LOW(Call32Data.gdt.length, gdt.length);
+ SET_LOW(Call32Data.gdt.addr, gdt.addr);
+
+ SET_LOW(Call32Data.method, C32_SLOPPY);
+}
+
+// Restore state backed up during call32_sloppy()
+static void
+call32_sloppy_post(void)
+{
+ SET_LOW(Call32Data.method, 0);
+ SET_LOW(Call32Data.ss, 0);
+
+ // Restore gdt and fs/gs
+ struct descloc_s gdt;
+ gdt.length = GET_LOW(Call32Data.gdt.length);
+ gdt.addr = GET_LOW(Call32Data.gdt.addr);
+ lgdt(&gdt);
+ SET_SEG(FS, GET_LOW(Call32Data.fs));
+ SET_SEG(GS, GET_LOW(Call32Data.gs));
+
+ // Restore a20
+ set_a20(GET_LOW(Call32Data.a20));
+
+ // Restore cmos index register
+ outb(GET_LOW(Call32Data.cmosindex), PORT_CMOS_INDEX);
+ inb(PORT_CMOS_DATA);
+}
+
+// Call a C function in 32bit mode. This clobbers the 16bit segment
+// selector registers.
+static u32
+call32_sloppy(void *func, u32 eax)
+{
+ ASSERT16();
+ call32_sloppy_prep();
+ 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\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_sloppy_post();
+ return eax;
+}
+
+// 16bit handler code called from call16_sloppy()
+u32 VISIBLE16
+call16_sloppy_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx))
+{
+ call32_sloppy_post();
+ u32 ret = func(eax, edx);
+ call32_sloppy_prep();
+ return ret;
+}
+
+// Jump back to 16bit mode while in 32bit mode from call32_sloppy()
+static u32
+call16_sloppy(u32 eax, u32 edx, void *func)
+{
+ ASSERT32FLAT();
+ if (getesp() > MAIN_STACK_MAX)
+ panic("call16_sloppy with invalid stack\n");
+ func -= BUILD_BIOS_ADDR;
+ u32 stackseg = Call32Data.ss;
+ asm volatile(
+ // Transition to 16bit mode
+ " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n"
+ " jmp transition16big\n"
+ // Setup ss/esp and call func
+ ASM32_SWITCH16
+ "1:movl %3, %%ecx\n"
+ " shll $4, %3\n"
+ " movw %%cx, %%ss\n"
+ " subl %3, %%esp\n"
+ " movw %%cx, %%ds\n"
+ " movl %2, %%edx\n"
+ " movl %1, %%ecx\n"
+ " calll _cfunc16_call16_sloppy_helper\n"
+ // Return to 32bit and restore esp
+ " movl $2f, %%edx\n"
+ " jmp transition32\n"
+ ASM32_BACK32
+ "2:addl %3, %%esp\n"
+ : "+a" (eax)
+ : "r" (func), "r" (edx), "r" (stackseg)
+ : "edx", "ecx", "cc", "memory");
+ return eax;
+}
+
+// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function.
+u32 VISIBLE16
+call32(void *func, u32 eax, u32 errret)
+{
+ ASSERT16();
+ if (CONFIG_CALL32_SMM && GET_GLOBAL(HaveSmmCall32))
+ return call32_smm(func, eax);
+ u32 cr0 = getcr0();
+ if (cr0 & CR0_PE)
+ // Called in 16bit protected mode?!
+ return errret;
+ return call32_sloppy(func, eax);
+}
+
+// Call a 16bit SeaBIOS function from a 32bit SeaBIOS function.
+static u32
+call16(u32 eax, u32 edx, void *func)
+{
+ ASSERT32FLAT();
+ if (getesp() > BUILD_STACK_ADDR)
+ panic("call16 with invalid stack\n");
+ func -= BUILD_BIOS_ADDR;
+ asm volatile(
+ // Transition to 16bit mode
+ " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n"
+ " jmp transition16\n"
+ // Call func
+ ASM32_SWITCH16
+ "1:movl %2, %%edx\n"
+ " calll *%1\n"
+ // Return to 32bit
+ " movl $2f, %%edx\n"
+ " jmp transition32\n"
+ ASM32_BACK32
+ "2:\n"
+ : "+a" (eax)
+ : "r" (func), "r" (edx)
+ : "edx", "ecx", "cc", "memory");
+ return eax;
+}
+
+// Call a 16bit SeaBIOS function in "big real" mode.
+static u32
+call16big(u32 eax, u32 edx, void *func)
+{
+ ASSERT32FLAT();
+ if (getesp() > BUILD_STACK_ADDR)
+ panic("call16big with invalid stack\n");
+ func -= BUILD_BIOS_ADDR;
+ asm volatile(
+ // Transition to 16bit mode
+ " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n"
+ " jmp transition16big\n"
+ // Call func
+ ASM32_SWITCH16
+ "1:movl %2, %%edx\n"
+ " calll *%1\n"
+ // Return to 32bit
+ " movl $2f, %%edx\n"
+ " jmp transition32\n"
+ ASM32_BACK32
+ "2:\n"
+ : "+a" (eax)
+ : "r" (func), "r" (edx)
+ : "edx", "ecx", "cc", "memory");
+ return eax;
+}
+
+// Call a 16bit SeaBIOS function, restoring the mode from last call32().
+static u32
+call16_back(u32 eax, u32 edx, void *func)
+{
+ ASSERT32FLAT();
+ if (CONFIG_CALL32_SMM && Call32Data.method == C32_SMM)
+ return call16_smm(eax, edx, func);
+ if (Call32Data.method == C32_SLOPPY)
+ return call16_sloppy(eax, edx, func);
+ if (in_post())
+ return call16big(eax, edx, func);
+ return call16(eax, edx, func);
+}
+
+
+/****************************************************************
+ * Extra 16bit stack
+ ****************************************************************/
+
+// 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_back(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()) {
+ extern void _cfunc16__farcall16(void);
+ stack_hop_back((u32)callregs, callregseg, _cfunc16__farcall16);
+ return;
+ }
+ ASSERT16();
+ asm volatile(
+ "calll __farcall16\n"
+ : "+a" (callregs), "+m" (*callregs), "+d" (callregseg)
+ :
+ : "ebx", "ecx", "esi", "edi", "cc", "memory");
+}
+
+void
+farcall16(struct bregs *callregs)
+{
+ extern void _cfunc16__farcall16(void);
+ call16((u32)callregs, 0, _cfunc16__farcall16);
+}
+
+void
+farcall16big(struct bregs *callregs)
+{
+ extern void _cfunc16__farcall16(void);
+ call16big((u32)callregs, 0, _cfunc16__farcall16);
+}
+
+// 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 - Call32Data.ss * 16, Call32Data.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_back(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 int ThreadControl;
+
+// Initialize the support for internal threads.
+void
+thread_init(void)
+{
+ 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 && 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");
+}
+
+// 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();
+ 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"(cur)
+ : "m"(*(u8*)__end_thread), "m"(MainThread)
+ : "esi", "edi", "cc", "memory");
+ return;
+
+fail:
+ func(data);
+}
+
+
+/****************************************************************
+ * Thread helpers
+ ****************************************************************/
+
+// Low-level irq enable.
+void VISIBLE16
+check_irqs(void)
+{
+ if (need_hop_back()) {
+ extern void _cfunc16_check_irqs(void);
+ stack_hop_back(0, 0, _cfunc16_check_irqs);
+ return;
+ }
+ 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();
+ if (cur == &MainThread)
+ // Permit irqs to fire
+ check_irqs();
+
+ // Switch to the next thread
+ switch_next(cur);
+}
+
+void VISIBLE16
+wait_irq(void)
+{
+ if (need_hop_back()) {
+ extern void _cfunc16_wait_irq(void);
+ stack_hop_back(0, 0, _cfunc16_wait_irq);
+ return;
+ }
+ asm volatile("sti ; hlt ; cli ; cld": : :"memory");
+}
+
+// Wait for next irq to occur.
+void
+yield_toirq(void)
+{
+ if (!MODESEGMENT && have_threads()) {
+ // Threads still active - 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)
+{
+ extern void _cfunc32flat_yield_preempt(void);
+ if (CONFIG_THREADS && GET_GLOBAL(CanPreempt) && have_threads())
+ call32(_cfunc32flat_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};
+ extern void _cfunc32flat_call32_params_helper(void);
+ return call32(_cfunc32flat_call32_params_helper
+ , (u32)MAKE_FLATPTR(GET_SEG(SS), &params), errret);
+}
diff --git a/roms/seabios/src/stacks.h b/roms/seabios/src/stacks.h
new file mode 100644
index 00000000..82c4c3c8
--- /dev/null
+++ b/roms/seabios/src/stacks.h
@@ -0,0 +1,53 @@
+// Misc function and variable declarations.
+#ifndef __STACKS_H
+#define __STACKS_H
+
+#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);
+extern u8 ExtraStack[], *StackPos;
+u32 stack_hop(u32 eax, u32 edx, void *func);
+u32 stack_hop_back(u32 eax, u32 edx, void *func);
+int on_extra_stack(void);
+struct bregs;
+void farcall16(struct bregs *callregs);
+void farcall16big(struct bregs *callregs);
+void __call16_int(struct bregs *callregs, u16 offset);
+#define call16_int(nr, callregs) do { \
+ extern void irq_trampoline_ ##nr (); \
+ __call16_int((callregs), (u32)&irq_trampoline_ ##nr ); \
+ } while (0)
+void reset(void);
+extern struct thread_info MainThread;
+struct thread_info *getCurThread(void);
+void yield(void);
+void yield_toirq(void);
+void thread_init(void);
+int threads_during_optionroms(void);
+void run_thread(void (*func)(void*), void *data);
+void wait_threads(void);
+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);
+
+// 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/src/std/LegacyBios.h b/roms/seabios/src/std/LegacyBios.h
new file mode 100644
index 00000000..5170c378
--- /dev/null
+++ b/roms/seabios/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/src/std/acpi.h b/roms/seabios/src/std/acpi.h
new file mode 100644
index 00000000..e0d9516b
--- /dev/null
+++ b/roms/seabios/src/std/acpi.h
@@ -0,0 +1,297 @@
+#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 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;
+
+#endif // acpi.h
diff --git a/roms/seabios/src/std/bda.h b/roms/seabios/src/std/bda.h
new file mode 100644
index 00000000..c321266e
--- /dev/null
+++ b/roms/seabios/src/std/bda.h
@@ -0,0 +1,154 @@
+// BIOS Data Area (and similar) definitions
+#ifndef __BDA_H
+#define __BDA_H
+
+#include "disk.h" // struct fdpt_s
+#include "types.h" // u8
+
+
+/****************************************************************
+ * Interupt 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;
+ u8 kbd_flag0;
+ u8 kbd_flag1;
+ 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_flag2;
+ 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)
+
+// 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/src/std/disk.h b/roms/seabios/src/std/disk.h
new file mode 100644
index 00000000..63971089
--- /dev/null
+++ b/roms/seabios/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/src/std/mptable.h b/roms/seabios/src/std/mptable.h
new file mode 100644
index 00000000..fa6a2294
--- /dev/null
+++ b/roms/seabios/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/src/std/optionrom.h b/roms/seabios/src/std/optionrom.h
new file mode 100644
index 00000000..94ca4ae1
--- /dev/null
+++ b/roms/seabios/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/src/std/pirtable.h b/roms/seabios/src/std/pirtable.h
new file mode 100644
index 00000000..9de3a438
--- /dev/null
+++ b/roms/seabios/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/src/std/pmm.h b/roms/seabios/src/std/pmm.h
new file mode 100644
index 00000000..80027f38
--- /dev/null
+++ b/roms/seabios/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/src/std/pnpbios.h b/roms/seabios/src/std/pnpbios.h
new file mode 100644
index 00000000..0871e3ab
--- /dev/null
+++ b/roms/seabios/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/src/std/smbios.h b/roms/seabios/src/std/smbios.h
new file mode 100644
index 00000000..05137167
--- /dev/null
+++ b/roms/seabios/src/std/smbios.h
@@ -0,0 +1,165 @@
+#ifndef __SMBIOS_H
+#define __SMBIOS_H
+
+#include "types.h" // u32
+
+/* SMBIOS entry point -- must be written to a 16-bit aligned address
+ between 0xf0000 and 0xfffff.
+ */
+struct smbios_entry_point {
+ char anchor_string[4];
+ 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/src/std/vbe.h b/roms/seabios/src/std/vbe.h
new file mode 100644
index 00000000..94b4ad86
--- /dev/null
+++ b/roms/seabios/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/src/std/vga.h b/roms/seabios/src/std/vga.h
new file mode 100644
index 00000000..de9ec750
--- /dev/null
+++ b/roms/seabios/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/src/string.c b/roms/seabios/src/string.c
new file mode 100644
index 00000000..2e4e4374
--- /dev/null
+++ b/roms/seabios/src/string.c
@@ -0,0 +1,251 @@
+// 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)
+{
+ SET_SEG(ES, d_seg);
+ asm volatile(
+ "rep stosb %%es:(%%di)"
+ : "+c"(len), "+D"(d_far)
+ : "a"(c), "m" (__segment_ES)
+ : "cc", "memory");
+}
+
+inline void
+memset16_far(u16 d_seg, void *d_far, u16 c, size_t len)
+{
+ len /= 2;
+ SET_SEG(ES, d_seg);
+ asm volatile(
+ "rep stosw %%es:(%%di)"
+ : "+c"(len), "+D"(d_far)
+ : "a"(c), "m" (__segment_ES)
+ : "cc", "memory");
+}
+
+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)
+{
+ 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");
+}
+
+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 *
+#undef memcpy
+memcpy(void *d1, const void *s1, size_t len)
+#if MODESEGMENT == 0
+#define memcpy __builtin_memcpy
+#endif
+{
+ 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;
+}
+
+// Copy to/from memory mapped IO. IO mem is very slow, so yield
+// periodically.
+void
+iomemcpy(void *d, const void *s, u32 len)
+{
+ 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);
+}
+
+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 occurance 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/src/string.h b/roms/seabios/src/string.h
new file mode 100644
index 00000000..a557d6a4
--- /dev/null
+++ b/roms/seabios/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);
+inline void memset_far(u16 d_seg, void *d_far, u8 c, size_t len);
+inline void memset16_far(u16 d_seg, void *d_far, u16 c, size_t len);
+void *memset(void *s, int c, size_t n);
+void memset_fl(void *ptr, u8 val, size_t size);
+inline void memcpy_far(u16 d_seg, void *d_far
+ , u16 s_seg, const void *s_far, size_t len);
+void memcpy_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/src/system.c b/roms/seabios/src/system.c
new file mode 100644
index 00000000..60a6fce5
--- /dev/null
+++ b/roms/seabios/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 "hw/pic.h" // pic_reset
+#include "malloc.h" // LegacyRamSize
+#include "memmap.h" // E820_RAM
+#include "output.h" // debug_enter
+#include "string.h" // memcpy_far
+#include "util.h" // handle_1553
+#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/src/types.h b/roms/seabios/src/types.h
new file mode 100644
index 00000000..097372cd
--- /dev/null
+++ b/roms/seabios/src/types.h
@@ -0,0 +1,156 @@
+// 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;
+};
+
+// Definition for common 16bit segment/offset pointers.
+struct segoff_s {
+ union {
+ struct {
+ u16 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 accessable 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/src/util.h b/roms/seabios/src/util.h
new file mode 100644
index 00000000..09bb8a9f
--- /dev/null
+++ b/roms/seabios/src/util.h
@@ -0,0 +1,237 @@
+// 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_size(struct bmp_decdata *bmp, int *width, int *height);
+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);
+struct pci_device;
+int bootprio_find_pci_device(struct pci_device *pci);
+int bootprio_find_scsi_device(struct pci_device *pci, 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);
+
+// bootsplash.c
+void enable_vga_console(void);
+void enable_bootsplash(void);
+void disable_bootsplash(void);
+
+// cdrom.c
+extern u8 CDRom_locks[];
+extern struct eltorito_s CDEmu;
+extern struct drive_s *cdemu_drive_gf;
+struct disk_op_s;
+int process_cdemu_op(struct disk_op_s *op);
+void cdrom_prepboot(void);
+int cdrom_boot(struct drive_s *drive_g);
+
+// clock.c
+void clock_setup(void);
+void handle_1583(struct bregs *regs);
+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);
+u32 find_resume_vector(void);
+void acpi_reboot(void);
+void find_acpi_features(void);
+extern struct smbios_entry_point *SMBiosAddr;
+void copy_smbios(void *pos);
+void display_uuid(void);
+void copy_table(void *pos);
+void smbios_setup(void);
+
+// 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/pciinit.c
+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_prep_reset(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);
+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 process_floppy_op(struct disk_op_s *op);
+void floppy_tick(void);
+
+// hw/ramdisk.c
+void ramdisk_setup(void);
+int process_ramdisk_op(struct disk_op_s *op);
+
+// hw/sdcard.c
+int process_sdcard_op(struct disk_op_s *op);
+void sdcard_setup(void);
+
+// hw/timer.c
+void timer_setup(void);
+void pmtimer_setup(u16 ioport);
+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);
+
+// misc.c
+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);
+
+// resume.c
+extern int HaveRunPost;
+
+// serial.c
+void serial_setup(void);
+void lpt_setup(void);
+
+// vgahooks.c
+void handle_155f(struct bregs *regs);
+void handle_157f(struct bregs *regs);
+void vgahook_setup(struct pci_device *pci);
+
+
+// version (auto generated file out/version.c)
+extern const char VERSION[];
+
+#endif // util.h
diff --git a/roms/seabios/src/vgahooks.c b/roms/seabios/src/vgahooks.c
new file mode 100644
index 00000000..6a4acfea
--- /dev/null
+++ b/roms/seabios/src/vgahooks.c
@@ -0,0 +1,354 @@
+// 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_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/dont 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/src/x86.c b/roms/seabios/src/x86.c
new file mode 100644
index 00000000..0fdf86f9
--- /dev/null
+++ b/roms/seabios/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/src/x86.h b/roms/seabios/src/x86.h
new file mode 100644
index 00000000..7798b1c1
--- /dev/null
+++ b/roms/seabios/src/x86.h
@@ -0,0 +1,247 @@
+// 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
+
+#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)
+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 getcr0(void) {
+ u32 cr0;
+ asm("movl %%cr0, %0" : "=r"(cr0));
+ return cr0;
+}
+static inline void setcr0(u32 cr0) {
+ asm("movl %0, %%cr0" : : "r"(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 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");
+}
+
+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 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);
+ outb((val & ~A20_ENABLE_BIT) | (cond ? A20_ENABLE_BIT : 0), PORT_A20);
+ return (val & A20_ENABLE_BIT) != 0;
+}
+
+// x86.c
+void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx);
+
+#endif // !__ASSEMBLY__
+
+#endif // x86.h
diff --git a/roms/seabios/vgasrc/Kconfig b/roms/seabios/vgasrc/Kconfig
new file mode 100644
index 00000000..91d590ae
--- /dev/null
+++ b/roms/seabios/vgasrc/Kconfig
@@ -0,0 +1,162 @@
+# Kconfig SeaBIOS VGA BIOS configuration
+
+menu "VGA ROM"
+ choice
+ prompt "VGA Hardware Type"
+ default NO_VGABIOS
+
+ config NO_VGABIOS
+ bool "None"
+ help
+ Do not build a VGA BIOS.
+
+ config VGA_STANDARD_VGA
+ depends on QEMU
+ bool "QEMU/Bochs Original IBM 256K VGA"
+ select VGA_STDVGA_PORTS
+ help
+ Build basic VGA BIOS support (pre Super-VGA) for use
+ on emulators.
+
+ config VGA_CIRRUS
+ depends on QEMU
+ bool "QEMU/Bochs Cirrus SVGA"
+ select VGA_STDVGA_PORTS
+ help
+ Build support for Cirrus VGA emulation found on QEMU
+ and Bochs emulators. This is for emulators; it is not
+ intended for use on real Cirrus hardware.
+
+ config VGA_BOCHS
+ depends on QEMU
+ bool "QEMU/Bochs VBE SVGA"
+ select VGA_STDVGA_PORTS
+ help
+ Build support for Bochs DISPI interface (a custom VBE
+ protocol) found on QEMU and Bochs emulators.
+
+ config VGA_GEODEGX2
+ bool "GeodeGX2"
+ select VGA_STDVGA_PORTS
+ help
+ Build support for Geode GX2 vga.
+
+ config VGA_GEODELX
+ bool "GeodeLX"
+ select VGA_STDVGA_PORTS
+ help
+ Build support for Geode LX vga.
+
+ config VGA_COREBOOT
+ depends on COREBOOT
+ bool "coreboot linear framebuffer"
+ select VGA_EMULATE_TEXT
+ help
+ Build support for a vgabios wrapper around video
+ devices initialized using coreboot native vga init.
+
+ endchoice
+
+ choice
+ depends on VGA_GEODEGX2 || VGA_GEODELX
+ prompt "Output Mode"
+ default VGA_OUTPUT_CRT
+
+ config VGA_OUTPUT_CRT
+ bool "CRT"
+ help
+ Use CRT for output.
+
+ config VGA_OUTPUT_PANEL
+ bool "Flat Panel"
+ help
+ Use flat panel for output.
+
+ config VGA_OUTPUT_CRT_PANEL
+ bool "CRT and Flat Panel"
+ help
+ Use CRT and flat panel for output.
+ endchoice
+
+ config BUILD_VGABIOS
+ bool
+ default !NO_VGABIOS
+
+ config VGA_STDVGA_PORTS
+ bool
+ config VGA_EMULATE_TEXT
+ bool
+ help
+ Support emulating text mode features when only a
+ framebuffer is available.
+
+ config VGA_FIXUP_ASM
+ depends on BUILD_VGABIOS
+ bool "Fixup assembler to work with broken emulators"
+ default y
+ help
+ This option will cause the build to attempt to avoid
+ certain x86 machine instructions that are known to confuse
+ some emulators. In particular, it works around
+ deficiencies in the Windows vgabios emulator and the
+ x86emu vgabios emulator (frequently used in Xorg).
+
+ config VGA_ALLOCATE_EXTRA_STACK
+ depends on BUILD_VGABIOS
+ bool "Allocate an internal stack for 16bit interrupt entry point"
+ default y
+ help
+ Attempt to allocate (via BIOS PMM call) an internal stack
+ for the legacy 16bit 0x10 interrupt entry point. This
+ reduces the amount of space on the caller's stack that
+ SeaVGABIOS uses.
+
+ config VGA_EXTRA_STACK_SIZE
+ int
+ default 512
+
+ config VGA_VBE
+ depends on BUILD_VGABIOS
+ bool "Video BIOS Extensions (VBE)"
+ default y
+ help
+ Support VBE.
+
+ config VGA_PCI
+ depends on BUILD_VGABIOS && !VGA_COREBOOT
+ bool "PCI ROM Headers"
+ default y
+ help
+ Build PCI ROM headers so the vga rom can be extracted from
+ a PCI device.
+
+ config OVERRIDE_PCI_ID
+ depends on VGA_PCI
+ bool "Override PCI Vendor and Device IDs"
+ help
+ Specify specific values for the PCI Vendor and Device IDs.
+
+ config VGA_VID
+ depends on VGA_PCI
+ hex
+ prompt "PCI Vendor ID" if OVERRIDE_PCI_ID
+ default 0x1013 if VGA_CIRRUS
+ default 0x1234 if VGA_BOCHS
+ default 0x100b if VGA_GEODEGX2
+ default 0x1022 if VGA_GEODELX
+ default 0x0000
+ help
+ Vendor ID for the PCI ROM
+
+ config VGA_DID
+ depends on VGA_PCI
+ hex
+ prompt "PCI Vendor ID" if OVERRIDE_PCI_ID
+ default 0x00b8 if VGA_CIRRUS
+ default 0x1111 if VGA_BOCHS
+ default 0x0030 if VGA_GEODEGX2
+ default 0x2081 if VGA_GEODELX
+ default 0x0000
+ help
+ Device ID for the PCI ROM
+endmenu
diff --git a/roms/seabios/vgasrc/bochsvga.c b/roms/seabios/vgasrc/bochsvga.c
new file mode 100644
index 00000000..aa82fc5a
--- /dev/null
+++ b/roms/seabios/vgasrc/bochsvga.c
@@ -0,0 +1,446 @@
+// Bochs VGA interface to extended "VBE" modes
+//
+// Copyright (C) 2012 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2011 Julian Pidancet <julian.pidancet@citrix.com>
+// Copyright (C) 2002 Jeroen Janssen
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "bochsvga.h" // bochsvga_set_mode
+#include "config.h" // CONFIG_*
+#include "hw/pci.h" // pci_config_readl
+#include "hw/pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "output.h" // dprintf
+#include "std/vbe.h" // VBE_CAPABILITY_8BIT_DAC
+#include "stdvga.h" // VGAREG_SEQU_ADDRESS
+#include "vgabios.h" // struct vbe_modeinfo
+#include "x86.h" // outw
+
+
+/****************************************************************
+ * Mode tables
+ ****************************************************************/
+
+static struct bochsvga_mode
+{
+ u16 mode;
+ struct vgamode_s info;
+} bochsvga_modes[] VAR16 = {
+ /* standard modes */
+ { 0x100, { MM_PACKED, 640, 400, 8, 8, 16, SEG_GRAPH } },
+ { 0x101, { MM_PACKED, 640, 480, 8, 8, 16, SEG_GRAPH } },
+ { 0x102, { MM_PLANAR, 800, 600, 4, 8, 16, SEG_GRAPH } },
+ { 0x103, { MM_PACKED, 800, 600, 8, 8, 16, SEG_GRAPH } },
+ { 0x104, { MM_PLANAR, 1024, 768, 4, 8, 16, SEG_GRAPH } },
+ { 0x105, { MM_PACKED, 1024, 768, 8, 8, 16, SEG_GRAPH } },
+ { 0x106, { MM_PLANAR, 1280, 1024, 4, 8, 16, SEG_GRAPH } },
+ { 0x107, { MM_PACKED, 1280, 1024, 8, 8, 16, SEG_GRAPH } },
+ { 0x10D, { MM_DIRECT, 320, 200, 15, 8, 16, SEG_GRAPH } },
+ { 0x10E, { MM_DIRECT, 320, 200, 16, 8, 16, SEG_GRAPH } },
+ { 0x10F, { MM_DIRECT, 320, 200, 24, 8, 16, SEG_GRAPH } },
+ { 0x110, { MM_DIRECT, 640, 480, 15, 8, 16, SEG_GRAPH } },
+ { 0x111, { MM_DIRECT, 640, 480, 16, 8, 16, SEG_GRAPH } },
+ { 0x112, { MM_DIRECT, 640, 480, 24, 8, 16, SEG_GRAPH } },
+ { 0x113, { MM_DIRECT, 800, 600, 15, 8, 16, SEG_GRAPH } },
+ { 0x114, { MM_DIRECT, 800, 600, 16, 8, 16, SEG_GRAPH } },
+ { 0x115, { MM_DIRECT, 800, 600, 24, 8, 16, SEG_GRAPH } },
+ { 0x116, { MM_DIRECT, 1024, 768, 15, 8, 16, SEG_GRAPH } },
+ { 0x117, { MM_DIRECT, 1024, 768, 16, 8, 16, SEG_GRAPH } },
+ { 0x118, { MM_DIRECT, 1024, 768, 24, 8, 16, SEG_GRAPH } },
+ { 0x119, { MM_DIRECT, 1280, 1024, 15, 8, 16, SEG_GRAPH } },
+ { 0x11A, { MM_DIRECT, 1280, 1024, 16, 8, 16, SEG_GRAPH } },
+ { 0x11B, { MM_DIRECT, 1280, 1024, 24, 8, 16, SEG_GRAPH } },
+ { 0x11C, { MM_PACKED, 1600, 1200, 8, 8, 16, SEG_GRAPH } },
+ { 0x11D, { MM_DIRECT, 1600, 1200, 15, 8, 16, SEG_GRAPH } },
+ { 0x11E, { MM_DIRECT, 1600, 1200, 16, 8, 16, SEG_GRAPH } },
+ { 0x11F, { MM_DIRECT, 1600, 1200, 24, 8, 16, SEG_GRAPH } },
+ /* BOCHS modes */
+ { 0x140, { MM_DIRECT, 320, 200, 32, 8, 16, SEG_GRAPH } },
+ { 0x141, { MM_DIRECT, 640, 400, 32, 8, 16, SEG_GRAPH } },
+ { 0x142, { MM_DIRECT, 640, 480, 32, 8, 16, SEG_GRAPH } },
+ { 0x143, { MM_DIRECT, 800, 600, 32, 8, 16, SEG_GRAPH } },
+ { 0x144, { MM_DIRECT, 1024, 768, 32, 8, 16, SEG_GRAPH } },
+ { 0x145, { MM_DIRECT, 1280, 1024, 32, 8, 16, SEG_GRAPH } },
+ { 0x146, { MM_PACKED, 320, 200, 8, 8, 16, SEG_GRAPH } },
+ { 0x147, { MM_DIRECT, 1600, 1200, 32, 8, 16, SEG_GRAPH } },
+ { 0x148, { MM_PACKED, 1152, 864, 8, 8, 16, SEG_GRAPH } },
+ { 0x149, { MM_DIRECT, 1152, 864, 15, 8, 16, SEG_GRAPH } },
+ { 0x14a, { MM_DIRECT, 1152, 864, 16, 8, 16, SEG_GRAPH } },
+ { 0x14b, { MM_DIRECT, 1152, 864, 24, 8, 16, SEG_GRAPH } },
+ { 0x14c, { MM_DIRECT, 1152, 864, 32, 8, 16, SEG_GRAPH } },
+ { 0x175, { MM_DIRECT, 1280, 768, 16, 8, 16, SEG_GRAPH } },
+ { 0x176, { MM_DIRECT, 1280, 768, 24, 8, 16, SEG_GRAPH } },
+ { 0x177, { MM_DIRECT, 1280, 768, 32, 8, 16, SEG_GRAPH } },
+ { 0x178, { MM_DIRECT, 1280, 800, 16, 8, 16, SEG_GRAPH } },
+ { 0x179, { MM_DIRECT, 1280, 800, 24, 8, 16, SEG_GRAPH } },
+ { 0x17a, { MM_DIRECT, 1280, 800, 32, 8, 16, SEG_GRAPH } },
+ { 0x17b, { MM_DIRECT, 1280, 960, 16, 8, 16, SEG_GRAPH } },
+ { 0x17c, { MM_DIRECT, 1280, 960, 24, 8, 16, SEG_GRAPH } },
+ { 0x17d, { MM_DIRECT, 1280, 960, 32, 8, 16, SEG_GRAPH } },
+ { 0x17e, { MM_DIRECT, 1440, 900, 16, 8, 16, SEG_GRAPH } },
+ { 0x17f, { MM_DIRECT, 1440, 900, 24, 8, 16, SEG_GRAPH } },
+ { 0x180, { MM_DIRECT, 1440, 900, 32, 8, 16, SEG_GRAPH } },
+ { 0x181, { MM_DIRECT, 1400, 1050, 16, 8, 16, SEG_GRAPH } },
+ { 0x182, { MM_DIRECT, 1400, 1050, 24, 8, 16, SEG_GRAPH } },
+ { 0x183, { MM_DIRECT, 1400, 1050, 32, 8, 16, SEG_GRAPH } },
+ { 0x184, { MM_DIRECT, 1680, 1050, 16, 8, 16, SEG_GRAPH } },
+ { 0x185, { MM_DIRECT, 1680, 1050, 24, 8, 16, SEG_GRAPH } },
+ { 0x186, { MM_DIRECT, 1680, 1050, 32, 8, 16, SEG_GRAPH } },
+ { 0x187, { MM_DIRECT, 1920, 1200, 16, 8, 16, SEG_GRAPH } },
+ { 0x188, { MM_DIRECT, 1920, 1200, 24, 8, 16, SEG_GRAPH } },
+ { 0x189, { MM_DIRECT, 1920, 1200, 32, 8, 16, SEG_GRAPH } },
+ { 0x18a, { MM_DIRECT, 2560, 1600, 16, 8, 16, SEG_GRAPH } },
+ { 0x18b, { MM_DIRECT, 2560, 1600, 24, 8, 16, SEG_GRAPH } },
+ { 0x18c, { MM_DIRECT, 2560, 1600, 32, 8, 16, SEG_GRAPH } },
+ { 0x18d, { MM_DIRECT, 1280, 720, 16, 8, 16, SEG_GRAPH } },
+ { 0x18e, { MM_DIRECT, 1280, 720, 24, 8, 16, SEG_GRAPH } },
+ { 0x18f, { MM_DIRECT, 1280, 720, 32, 8, 16, SEG_GRAPH } },
+ { 0x190, { MM_DIRECT, 1920, 1080, 16, 8, 16, SEG_GRAPH } },
+ { 0x191, { MM_DIRECT, 1920, 1080, 24, 8, 16, SEG_GRAPH } },
+ { 0x192, { MM_DIRECT, 1920, 1080, 32, 8, 16, SEG_GRAPH } },
+};
+
+static int dispi_found VAR16 = 0;
+
+static int is_bochsvga_mode(struct vgamode_s *vmode_g)
+{
+ return (vmode_g >= &bochsvga_modes[0].info
+ && vmode_g <= &bochsvga_modes[ARRAY_SIZE(bochsvga_modes)-1].info);
+}
+
+struct vgamode_s *bochsvga_find_mode(int mode)
+{
+ struct bochsvga_mode *m = bochsvga_modes;
+ if (GET_GLOBAL(dispi_found))
+ for (; m < &bochsvga_modes[ARRAY_SIZE(bochsvga_modes)]; m++)
+ if (GET_GLOBAL(m->mode) == mode)
+ return &m->info;
+ return stdvga_find_mode(mode);
+}
+
+void
+bochsvga_list_modes(u16 seg, u16 *dest, u16 *last)
+{
+ struct bochsvga_mode *m = bochsvga_modes;
+ if (GET_GLOBAL(dispi_found)) {
+ for (; m < &bochsvga_modes[ARRAY_SIZE(bochsvga_modes)] && dest<last; m++) {
+ u16 mode = GET_GLOBAL(m->mode);
+ if (mode == 0xffff)
+ continue;
+ SET_FARVAR(seg, *dest, mode);
+ dest++;
+ }
+ }
+ stdvga_list_modes(seg, dest, last);
+}
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+static inline u16 dispi_read(u16 reg)
+{
+ outw(reg, VBE_DISPI_IOPORT_INDEX);
+ return inw(VBE_DISPI_IOPORT_DATA);
+}
+static inline void dispi_write(u16 reg, u16 val)
+{
+ outw(reg, VBE_DISPI_IOPORT_INDEX);
+ outw(val, VBE_DISPI_IOPORT_DATA);
+}
+
+static u8
+bochsvga_dispi_enabled(void)
+{
+ if (!GET_GLOBAL(dispi_found))
+ return 0;
+ u16 en = dispi_read(VBE_DISPI_INDEX_ENABLE);
+ if (!(en & VBE_DISPI_ENABLED))
+ return 0;
+ return 1;
+}
+
+int
+bochsvga_get_window(struct vgamode_s *vmode_g, int window)
+{
+ if (!bochsvga_dispi_enabled())
+ return stdvga_get_window(vmode_g, window);
+ if (window != 0)
+ return -1;
+ return dispi_read(VBE_DISPI_INDEX_BANK);
+}
+
+int
+bochsvga_set_window(struct vgamode_s *vmode_g, int window, int val)
+{
+ if (!bochsvga_dispi_enabled())
+ return stdvga_set_window(vmode_g, window, val);
+ if (window != 0)
+ return -1;
+ dispi_write(VBE_DISPI_INDEX_BANK, val);
+ if (dispi_read(VBE_DISPI_INDEX_BANK) != val)
+ return -1;
+ return 0;
+}
+
+int
+bochsvga_get_linelength(struct vgamode_s *vmode_g)
+{
+ if (!bochsvga_dispi_enabled())
+ return stdvga_get_linelength(vmode_g);
+ return dispi_read(VBE_DISPI_INDEX_VIRT_WIDTH) * vga_bpp(vmode_g) / 8;
+}
+
+int
+bochsvga_set_linelength(struct vgamode_s *vmode_g, int val)
+{
+ stdvga_set_linelength(vmode_g, val);
+ if (bochsvga_dispi_enabled()) {
+ int pixels = (val * 8) / vga_bpp(vmode_g);
+ dispi_write(VBE_DISPI_INDEX_VIRT_WIDTH, pixels);
+ }
+ return 0;
+}
+
+int
+bochsvga_get_displaystart(struct vgamode_s *vmode_g)
+{
+ if (!bochsvga_dispi_enabled())
+ return stdvga_get_displaystart(vmode_g);
+ int bpp = vga_bpp(vmode_g);
+ int linelength = dispi_read(VBE_DISPI_INDEX_VIRT_WIDTH) * bpp / 8;
+ int x = dispi_read(VBE_DISPI_INDEX_X_OFFSET);
+ int y = dispi_read(VBE_DISPI_INDEX_Y_OFFSET);
+ return x * bpp / 8 + linelength * y;
+}
+
+int
+bochsvga_set_displaystart(struct vgamode_s *vmode_g, int val)
+{
+ stdvga_set_displaystart(vmode_g, val);
+ if (bochsvga_dispi_enabled()) {
+ int bpp = vga_bpp(vmode_g);
+ int linelength = dispi_read(VBE_DISPI_INDEX_VIRT_WIDTH) * bpp / 8;
+ if (!linelength)
+ return 0;
+ dispi_write(VBE_DISPI_INDEX_X_OFFSET, (val % linelength) * 8 / bpp);
+ dispi_write(VBE_DISPI_INDEX_Y_OFFSET, val / linelength);
+ }
+ return 0;
+}
+
+int
+bochsvga_get_dacformat(struct vgamode_s *vmode_g)
+{
+ if (!bochsvga_dispi_enabled())
+ return stdvga_get_dacformat(vmode_g);
+ u16 en = dispi_read(VBE_DISPI_INDEX_ENABLE);
+ return (en & VBE_DISPI_8BIT_DAC) ? 8 : 6;
+}
+
+int
+bochsvga_set_dacformat(struct vgamode_s *vmode_g, int val)
+{
+ if (!bochsvga_dispi_enabled())
+ return stdvga_set_dacformat(vmode_g, val);
+ u16 en = dispi_read(VBE_DISPI_INDEX_ENABLE);
+ if (val == 6)
+ en &= ~VBE_DISPI_8BIT_DAC;
+ else if (val == 8)
+ en |= VBE_DISPI_8BIT_DAC;
+ else
+ return -1;
+ dispi_write(VBE_DISPI_INDEX_ENABLE, en);
+ return 0;
+}
+
+static int
+bochsvga_save_state(u16 seg, u16 *info)
+{
+ u16 en = dispi_read(VBE_DISPI_INDEX_ENABLE);
+ SET_FARVAR(seg, *info, en);
+ info++;
+ if (!(en & VBE_DISPI_ENABLED))
+ return 0;
+ int i;
+ for (i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++)
+ if (i != VBE_DISPI_INDEX_ENABLE) {
+ u16 v = dispi_read(i);
+ SET_FARVAR(seg, *info, v);
+ info++;
+ }
+ return 0;
+}
+
+static int
+bochsvga_restore_state(u16 seg, u16 *info)
+{
+ u16 en = GET_FARVAR(seg, *info);
+ info++;
+ if (!(en & VBE_DISPI_ENABLED)) {
+ dispi_write(VBE_DISPI_INDEX_ENABLE, en);
+ return 0;
+ }
+ int i;
+ for (i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++)
+ if (i == VBE_DISPI_INDEX_ENABLE) {
+ dispi_write(i, en);
+ } else {
+ dispi_write(i, GET_FARVAR(seg, *info));
+ info++;
+ }
+ return 0;
+}
+
+int
+bochsvga_save_restore(int cmd, u16 seg, void *data)
+{
+ int ret = stdvga_save_restore(cmd, seg, data);
+ if (ret < 0 || !(cmd & SR_REGISTERS) || !GET_GLOBAL(dispi_found))
+ return ret;
+
+ u16 *info = (data + ret);
+ if (cmd & SR_SAVE)
+ bochsvga_save_state(seg, info);
+ if (cmd & SR_RESTORE)
+ bochsvga_restore_state(seg, info);
+ return ret + (VBE_DISPI_INDEX_Y_OFFSET-VBE_DISPI_INDEX_XRES+1)*sizeof(u16);
+}
+
+
+/****************************************************************
+ * Mode setting
+ ****************************************************************/
+
+int
+bochsvga_set_mode(struct vgamode_s *vmode_g, int flags)
+{
+ if (GET_GLOBAL(dispi_found))
+ dispi_write(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
+ if (! is_bochsvga_mode(vmode_g))
+ return stdvga_set_mode(vmode_g, flags);
+ if (!GET_GLOBAL(dispi_found))
+ return -1;
+
+ u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
+ if (memmodel == MM_PLANAR)
+ stdvga_set_mode(stdvga_find_mode(0x6a), 0);
+ if (memmodel == MM_PACKED && !(flags & MF_NOPALETTE))
+ stdvga_set_packed_palette();
+
+ dispi_write(VBE_DISPI_INDEX_BPP, GET_GLOBAL(vmode_g->depth));
+ u16 width = GET_GLOBAL(vmode_g->width);
+ u16 height = GET_GLOBAL(vmode_g->height);
+ dispi_write(VBE_DISPI_INDEX_XRES, width);
+ dispi_write(VBE_DISPI_INDEX_YRES, height);
+ dispi_write(VBE_DISPI_INDEX_BANK, 0);
+ u16 bf = ((flags & MF_NOCLEARMEM ? VBE_DISPI_NOCLEARMEM : 0)
+ | (flags & MF_LINEARFB ? VBE_DISPI_LFB_ENABLED : 0));
+ dispi_write(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | bf);
+
+ /* VGA compat setup */
+ u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
+ stdvga_crtc_write(crtc_addr, 0x11, 0x00);
+ stdvga_crtc_write(crtc_addr, 0x01, width / 8 - 1);
+ stdvga_set_linelength(vmode_g, width);
+ stdvga_crtc_write(crtc_addr, 0x12, height - 1);
+ u8 v = 0;
+ if ((height - 1) & 0x0100)
+ v |= 0x02;
+ if ((height - 1) & 0x0200)
+ v |= 0x40;
+ stdvga_crtc_mask(crtc_addr, 0x07, 0x42, v);
+
+ stdvga_crtc_write(crtc_addr, 0x09, 0x00);
+ stdvga_crtc_mask(crtc_addr, 0x17, 0x00, 0x03);
+ stdvga_attr_mask(0x10, 0x00, 0x01);
+ stdvga_grdc_write(0x06, 0x05);
+ stdvga_sequ_write(0x02, 0x0f);
+ if (memmodel != MM_PLANAR) {
+ stdvga_crtc_mask(crtc_addr, 0x14, 0x00, 0x40);
+ stdvga_attr_mask(0x10, 0x00, 0x40);
+ stdvga_sequ_mask(0x04, 0x00, 0x08);
+ stdvga_grdc_mask(0x05, 0x20, 0x40);
+ }
+ stdvga_attrindex_write(0x20);
+
+ return 0;
+}
+
+
+/****************************************************************
+ * Init
+ ****************************************************************/
+
+int
+bochsvga_setup(void)
+{
+ int ret = stdvga_setup();
+ if (ret)
+ return ret;
+
+ /* Sanity checks */
+ dispi_write(VBE_DISPI_INDEX_ID, VBE_DISPI_ID0);
+ if (dispi_read(VBE_DISPI_INDEX_ID) != VBE_DISPI_ID0) {
+ dprintf(1, "No VBE DISPI interface detected, falling back to stdvga\n");
+ return 0;
+ }
+
+ dispi_write(VBE_DISPI_INDEX_ID, VBE_DISPI_ID5);
+ SET_VGA(dispi_found, 1);
+
+ if (GET_GLOBAL(HaveRunInit))
+ return 0;
+
+ u32 lfb_addr = VBE_DISPI_LFB_PHYSICAL_ADDRESS;
+ int bdf = GET_GLOBAL(VgaBDF);
+ if (CONFIG_VGA_PCI && bdf >= 0) {
+ u16 vendor = pci_config_readw(bdf, PCI_VENDOR_ID);
+ int barid;
+ switch (vendor) {
+ case 0x15ad: /* qemu vmware vga */
+ barid = 1;
+ break;
+ default: /* stdvga, qxl, virtio */
+ barid = 0;
+ break;
+ }
+ u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_0 + barid * 4);
+ lfb_addr = bar & PCI_BASE_ADDRESS_MEM_MASK;
+ dprintf(1, "VBE DISPI: bdf %02x:%02x.%x, bar %d\n", pci_bdf_to_bus(bdf)
+ , pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf), barid);
+ }
+
+ SET_VGA(VBE_framebuffer, lfb_addr);
+ u32 totalmem = dispi_read(VBE_DISPI_INDEX_VIDEO_MEMORY_64K) * 64 * 1024;
+ SET_VGA(VBE_total_memory, totalmem);
+ SET_VGA(VBE_win_granularity, 64);
+ SET_VGA(VBE_capabilities, VBE_CAPABILITY_8BIT_DAC);
+
+ dprintf(1, "VBE DISPI: lfb_addr=%x, size %d MB\n",
+ lfb_addr, totalmem >> 20);
+
+ // Validate modes
+ u16 en = dispi_read(VBE_DISPI_INDEX_ENABLE);
+ dispi_write(VBE_DISPI_INDEX_ENABLE, en | VBE_DISPI_GETCAPS);
+ u16 max_xres = dispi_read(VBE_DISPI_INDEX_XRES);
+ u16 max_bpp = dispi_read(VBE_DISPI_INDEX_BPP);
+ dispi_write(VBE_DISPI_INDEX_ENABLE, en);
+ struct bochsvga_mode *m = bochsvga_modes;
+ for (; m < &bochsvga_modes[ARRAY_SIZE(bochsvga_modes)]; m++) {
+ u16 width = GET_GLOBAL(m->info.width);
+ u16 height = GET_GLOBAL(m->info.height);
+ u8 depth = GET_GLOBAL(m->info.depth);
+ u32 mem = (height * DIV_ROUND_UP(width * vga_bpp(&m->info), 8)
+ * stdvga_vram_ratio(&m->info));
+
+ if (width > max_xres || depth > max_bpp || mem > totalmem) {
+ dprintf(1, "Removing mode %x\n", GET_GLOBAL(m->mode));
+ SET_VGA(m->mode, 0xffff);
+ }
+ }
+
+ return 0;
+}
diff --git a/roms/seabios/vgasrc/bochsvga.h b/roms/seabios/vgasrc/bochsvga.h
new file mode 100644
index 00000000..ae5f75db
--- /dev/null
+++ b/roms/seabios/vgasrc/bochsvga.h
@@ -0,0 +1,57 @@
+#ifndef __BOCHSVGA_H
+#define __BOCHSVGA_H
+
+#include "types.h" // u8
+
+#define VBE_DISPI_BANK_ADDRESS 0xA0000
+#define VBE_DISPI_BANK_SIZE_KB 64
+
+#define VBE_DISPI_MAX_XRES 2560
+#define VBE_DISPI_MAX_YRES 1600
+
+#define VBE_DISPI_IOPORT_INDEX 0x01CE
+#define VBE_DISPI_IOPORT_DATA 0x01CF
+
+#define VBE_DISPI_INDEX_ID 0x0
+#define VBE_DISPI_INDEX_XRES 0x1
+#define VBE_DISPI_INDEX_YRES 0x2
+#define VBE_DISPI_INDEX_BPP 0x3
+#define VBE_DISPI_INDEX_ENABLE 0x4
+#define VBE_DISPI_INDEX_BANK 0x5
+#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
+#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
+#define VBE_DISPI_INDEX_X_OFFSET 0x8
+#define VBE_DISPI_INDEX_Y_OFFSET 0x9
+#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa
+
+#define VBE_DISPI_ID0 0xB0C0
+#define VBE_DISPI_ID1 0xB0C1
+#define VBE_DISPI_ID2 0xB0C2
+#define VBE_DISPI_ID3 0xB0C3
+#define VBE_DISPI_ID4 0xB0C4
+#define VBE_DISPI_ID5 0xB0C5
+
+#define VBE_DISPI_DISABLED 0x00
+#define VBE_DISPI_ENABLED 0x01
+#define VBE_DISPI_GETCAPS 0x02
+#define VBE_DISPI_8BIT_DAC 0x20
+#define VBE_DISPI_LFB_ENABLED 0x40
+#define VBE_DISPI_NOCLEARMEM 0x80
+
+#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
+
+struct vgamode_s *bochsvga_find_mode(int mode);
+void bochsvga_list_modes(u16 seg, u16 *dest, u16 *last);
+int bochsvga_get_window(struct vgamode_s *vmode_g, int window);
+int bochsvga_set_window(struct vgamode_s *vmode_g, int window, int val);
+int bochsvga_get_linelength(struct vgamode_s *vmode_g);
+int bochsvga_set_linelength(struct vgamode_s *vmode_g, int val);
+int bochsvga_get_displaystart(struct vgamode_s *vmode_g);
+int bochsvga_set_displaystart(struct vgamode_s *vmode_g, int val);
+int bochsvga_get_dacformat(struct vgamode_s *vmode_g);
+int bochsvga_set_dacformat(struct vgamode_s *vmode_g, int val);
+int bochsvga_save_restore(int cmd, u16 seg, void *data);
+int bochsvga_set_mode(struct vgamode_s *vmode_g, int flags);
+int bochsvga_setup(void);
+
+#endif // bochsvga.h
diff --git a/roms/seabios/vgasrc/cbvga.c b/roms/seabios/vgasrc/cbvga.c
new file mode 100644
index 00000000..1cfb9d37
--- /dev/null
+++ b/roms/seabios/vgasrc/cbvga.c
@@ -0,0 +1,193 @@
+// Simple framebuffer vgabios for use with coreboot native vga init.
+//
+// Copyright (C) 2014 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 "cbvga.h" // cbvga_setup
+#include "output.h" // dprintf
+#include "stdvga.h" // SEG_CTEXT
+#include "string.h" // memset16_far
+#include "util.h" // find_cb_table
+#include "vgabios.h" // VGAREG_*
+
+static int CBmode VAR16;
+static struct vgamode_s CBmodeinfo VAR16;
+static struct vgamode_s CBemulinfo VAR16;
+static u32 CBlinelength VAR16;
+
+struct vgamode_s *cbvga_find_mode(int mode)
+{
+ if (mode == GET_GLOBAL(CBmode))
+ return &CBmodeinfo;
+ if (mode == 0x03)
+ return &CBemulinfo;
+ return NULL;
+}
+
+void
+cbvga_list_modes(u16 seg, u16 *dest, u16 *last)
+{
+ if (dest<last) {
+ SET_FARVAR(seg, *dest, GET_GLOBAL(CBmode));
+ dest++;
+ }
+ SET_FARVAR(seg, *dest, 0xffff);
+}
+
+int
+cbvga_get_window(struct vgamode_s *vmode_g, int window)
+{
+ return -1;
+}
+
+int
+cbvga_set_window(struct vgamode_s *vmode_g, int window, int val)
+{
+ return -1;
+}
+
+int
+cbvga_get_linelength(struct vgamode_s *vmode_g)
+{
+ return GET_GLOBAL(CBlinelength);
+}
+
+int
+cbvga_set_linelength(struct vgamode_s *vmode_g, int val)
+{
+ return -1;
+}
+
+int
+cbvga_get_displaystart(struct vgamode_s *vmode_g)
+{
+ return 0;
+}
+
+int
+cbvga_set_displaystart(struct vgamode_s *vmode_g, int val)
+{
+ return -1;
+}
+
+int
+cbvga_get_dacformat(struct vgamode_s *vmode_g)
+{
+ return -1;
+}
+
+int
+cbvga_set_dacformat(struct vgamode_s *vmode_g, int val)
+{
+ return -1;
+}
+
+int
+cbvga_save_restore(int cmd, u16 seg, void *data)
+{
+ if (cmd & (SR_HARDWARE|SR_DAC|SR_REGISTERS))
+ return -1;
+ return bda_save_restore(cmd, seg, data);
+}
+
+int
+cbvga_set_mode(struct vgamode_s *vmode_g, int flags)
+{
+ u8 emul = vmode_g == &CBemulinfo || GET_GLOBAL(CBmode) == 0x03;
+ MASK_BDA_EXT(flags, BF_EMULATE_TEXT, emul ? BF_EMULATE_TEXT : 0);
+ if (!(flags & MF_NOCLEARMEM)) {
+ if (GET_GLOBAL(CBmodeinfo.memmodel) == MM_TEXT) {
+ memset16_far(SEG_CTEXT, (void*)0, 0x0720, 80*25*2);
+ return 0;
+ }
+ struct gfx_op op;
+ init_gfx_op(&op, vmode_g);
+ op.x = op.y = 0;
+ op.xlen = GET_GLOBAL(CBmodeinfo.width);
+ op.ylen = GET_GLOBAL(CBmodeinfo.height);
+ op.op = GO_MEMSET;
+ handle_gfx_op(&op);
+ }
+ return 0;
+}
+
+#define CB_TAG_FRAMEBUFFER 0x0012
+struct cb_framebuffer {
+ u32 tag;
+ u32 size;
+
+ u64 physical_address;
+ u32 x_resolution;
+ u32 y_resolution;
+ u32 bytes_per_line;
+ u8 bits_per_pixel;
+ u8 red_mask_pos;
+ u8 red_mask_size;
+ u8 green_mask_pos;
+ u8 green_mask_size;
+ u8 blue_mask_pos;
+ u8 blue_mask_size;
+ u8 reserved_mask_pos;
+ u8 reserved_mask_size;
+};
+
+int
+cbvga_setup(void)
+{
+ dprintf(1, "coreboot vga init\n");
+
+ if (GET_GLOBAL(HaveRunInit))
+ return 0;
+
+ struct cb_header *cbh = find_cb_table();
+ if (!cbh) {
+ dprintf(1, "Unable to find coreboot table\n");
+ return -1;
+ }
+ struct cb_framebuffer *cbfb = find_cb_subtable(cbh, CB_TAG_FRAMEBUFFER);
+ if (!cbfb) {
+ // Assume there is an EGA text framebuffer.
+ dprintf(1, "Did not find coreboot framebuffer - assuming EGA text\n");
+ SET_VGA(CBmode, 0x03);
+ SET_VGA(CBlinelength, 80*2);
+ SET_VGA(CBmodeinfo.memmodel, MM_TEXT);
+ SET_VGA(CBmodeinfo.width, 80);
+ SET_VGA(CBmodeinfo.height, 25);
+ SET_VGA(CBmodeinfo.depth, 4);
+ SET_VGA(CBmodeinfo.cwidth, 9);
+ SET_VGA(CBmodeinfo.cheight, 16);
+ SET_VGA(CBmodeinfo.sstart, SEG_CTEXT);
+ return 0;
+ }
+
+ u64 addr = GET_FARVAR(0, cbfb->physical_address);
+ u8 bpp = GET_FARVAR(0, cbfb->bits_per_pixel);
+ u32 xlines = GET_FARVAR(0, cbfb->x_resolution);
+ u32 ylines = GET_FARVAR(0, cbfb->y_resolution);
+ u32 linelength = GET_FARVAR(0, cbfb->bytes_per_line);
+ dprintf(1, "Found FB @ %llx %dx%d with %d bpp (%d stride)\n"
+ , addr, xlines, ylines, bpp, linelength);
+
+ if (!addr || addr > 0xffffffff
+ || (bpp != 15 && bpp != 16 && bpp != 24 && bpp != 32)) {
+ dprintf(1, "Unable to use FB\n");
+ return -1;
+ }
+
+ SET_VGA(CBmode, 0x140);
+ SET_VGA(VBE_framebuffer, addr);
+ SET_VGA(VBE_total_memory, linelength * ylines);
+ SET_VGA(CBlinelength, linelength);
+ SET_VGA(CBmodeinfo.memmodel, MM_DIRECT);
+ SET_VGA(CBmodeinfo.width, xlines);
+ SET_VGA(CBmodeinfo.height, ylines);
+ SET_VGA(CBmodeinfo.depth, bpp);
+ SET_VGA(CBmodeinfo.cwidth, 8);
+ SET_VGA(CBmodeinfo.cheight, 16);
+ memcpy_far(get_global_seg(), &CBemulinfo
+ , get_global_seg(), &CBmodeinfo, sizeof(CBemulinfo));
+
+ return 0;
+}
diff --git a/roms/seabios/vgasrc/cbvga.h b/roms/seabios/vgasrc/cbvga.h
new file mode 100644
index 00000000..fb892c85
--- /dev/null
+++ b/roms/seabios/vgasrc/cbvga.h
@@ -0,0 +1,20 @@
+#ifndef __CBVGA_H
+#define __CBVGA_H
+
+#include "types.h" // u16
+
+struct vgamode_s *cbvga_find_mode(int mode);
+void cbvga_list_modes(u16 seg, u16 *dest, u16 *last);
+int cbvga_get_window(struct vgamode_s *vmode_g, int window);
+int cbvga_set_window(struct vgamode_s *vmode_g, int window, int val);
+int cbvga_get_linelength(struct vgamode_s *vmode_g);
+int cbvga_set_linelength(struct vgamode_s *vmode_g, int val);
+int cbvga_get_displaystart(struct vgamode_s *vmode_g);
+int cbvga_set_displaystart(struct vgamode_s *vmode_g, int val);
+int cbvga_get_dacformat(struct vgamode_s *vmode_g);
+int cbvga_set_dacformat(struct vgamode_s *vmode_g, int val);
+int cbvga_save_restore(int cmd, u16 seg, void *data);
+int cbvga_set_mode(struct vgamode_s *vmode_g, int flags);
+int cbvga_setup(void);
+
+#endif // cbvga.h
diff --git a/roms/seabios/vgasrc/clext.c b/roms/seabios/vgasrc/clext.c
new file mode 100644
index 00000000..fc5b42f6
--- /dev/null
+++ b/roms/seabios/vgasrc/clext.c
@@ -0,0 +1,627 @@
+// QEMU Cirrus CLGD 54xx VGABIOS Extension.
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (c) 2004 Makoto Suzuki (suzu)
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "bregs.h" // struct bregs
+#include "clext.h" // clext_setup
+#include "hw/pci.h" // pci_config_readl
+#include "hw/pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "output.h" // dprintf
+#include "stdvga.h" // VGAREG_SEQU_ADDRESS
+#include "string.h" // memset16_far
+#include "vgabios.h" // VBE_VENDOR_STRING
+
+
+/****************************************************************
+ * Cirrus mode tables
+ ****************************************************************/
+
+/* VGA */
+static u16 cseq_vga[] VAR16 = {0x0007,0xffff};
+static u16 cgraph_vga[] VAR16 = {0x0009,0x000a,0x000b,0xffff};
+static u16 ccrtc_vga[] VAR16 = {0x001a,0x001b,0x001d,0xffff};
+
+/* extensions */
+static u16 cgraph_svgacolor[] VAR16 = {
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x4005,0x0506,0x0f07,0xff08,
+ 0x0009,0x000a,0x000b,
+ 0xffff
+};
+/* 640x480x8 */
+static u16 cseq_640x480x8[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+ 0x580b,0x580c,0x580d,0x580e,
+ 0x0412,0x0013,0x2017,
+ 0x331b,0x331c,0x331d,0x331e,
+ 0xffff
+};
+static u16 ccrtc_640x480x8[] VAR16 = {
+ 0x2c11,
+ 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+ 0x4009,0x000c,0x000d,
+ 0xea10,0xdf12,0x5013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+/* 640x480x16 */
+static u16 cseq_640x480x16[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+ 0x580b,0x580c,0x580d,0x580e,
+ 0x0412,0x0013,0x2017,
+ 0x331b,0x331c,0x331d,0x331e,
+ 0xffff
+};
+static u16 ccrtc_640x480x16[] VAR16 = {
+ 0x2c11,
+ 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+ 0x4009,0x000c,0x000d,
+ 0xea10,0xdf12,0xa013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+/* 640x480x24 */
+static u16 cseq_640x480x24[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+ 0x580b,0x580c,0x580d,0x580e,
+ 0x0412,0x0013,0x2017,
+ 0x331b,0x331c,0x331d,0x331e,
+ 0xffff
+};
+static u16 ccrtc_640x480x24[] VAR16 = {
+ 0x2c11,
+ 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+ 0x4009,0x000c,0x000d,
+ 0xea10,0xdf12,0xf013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+/* 800x600x8 */
+static u16 cseq_800x600x8[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+ 0x230b,0x230c,0x230d,0x230e,
+ 0x0412,0x0013,0x2017,
+ 0x141b,0x141c,0x141d,0x141e,
+ 0xffff
+};
+static u16 ccrtc_800x600x8[] VAR16 = {
+ 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+ 0x6009,0x000c,0x000d,
+ 0x7d10,0x5712,0x6413,0x4014,0x5715,0x9816,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+/* 800x600x16 */
+static u16 cseq_800x600x16[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+ 0x230b,0x230c,0x230d,0x230e,
+ 0x0412,0x0013,0x2017,
+ 0x141b,0x141c,0x141d,0x141e,
+ 0xffff
+};
+static u16 ccrtc_800x600x16[] VAR16 = {
+ 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+ 0x6009,0x000c,0x000d,
+ 0x7d10,0x5712,0xc813,0x4014,0x5715,0x9816,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+/* 800x600x24 */
+static u16 cseq_800x600x24[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+ 0x230b,0x230c,0x230d,0x230e,
+ 0x0412,0x0013,0x2017,
+ 0x141b,0x141c,0x141d,0x141e,
+ 0xffff
+};
+static u16 ccrtc_800x600x24[] VAR16 = {
+ 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+ 0x6009,0x000c,0x000d,
+ 0x7d10,0x5712,0x2c13,0x4014,0x5715,0x9816,0xc317,0xff18,
+ 0x001a,0x321b,0x001d,
+ 0xffff
+};
+/* 1024x768x8 */
+static u16 cseq_1024x768x8[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+ 0x760b,0x760c,0x760d,0x760e,
+ 0x0412,0x0013,0x2017,
+ 0x341b,0x341c,0x341d,0x341e,
+ 0xffff
+};
+static u16 ccrtc_1024x768x8[] VAR16 = {
+ 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+ 0x6009,0x000c,0x000d,
+ 0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+/* 1024x768x16 */
+static u16 cseq_1024x768x16[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+ 0x760b,0x760c,0x760d,0x760e,
+ 0x0412,0x0013,0x2017,
+ 0x341b,0x341c,0x341d,0x341e,
+ 0xffff
+};
+static u16 ccrtc_1024x768x16[] VAR16 = {
+ 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+ 0x6009,0x000c,0x000d,
+ 0x0310,0xff12,0x0013,0x4014,0xff15,0x2416,0xc317,0xff18,
+ 0x001a,0x321b,0x001d,
+ 0xffff
+};
+/* 1024x768x24 */
+static u16 cseq_1024x768x24[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+ 0x760b,0x760c,0x760d,0x760e,
+ 0x0412,0x0013,0x2017,
+ 0x341b,0x341c,0x341d,0x341e,
+ 0xffff
+};
+static u16 ccrtc_1024x768x24[] VAR16 = {
+ 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+ 0x6009,0x000c,0x000d,
+ 0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18,
+ 0x001a,0x321b,0x001d,
+ 0xffff
+};
+/* 1280x1024x8 */
+static u16 cseq_1280x1024x8[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+ 0x760b,0x760c,0x760d,0x760e,
+ 0x0412,0x0013,0x2017,
+ 0x341b,0x341c,0x341d,0x341e,
+ 0xffff
+};
+static u16 ccrtc_1280x1024x8[] VAR16 = {
+ 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+ 0x6009,0x000c,0x000d,
+ 0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+/* 1280x1024x16 */
+static u16 cseq_1280x1024x16[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+ 0x760b,0x760c,0x760d,0x760e,
+ 0x0412,0x0013,0x2017,
+ 0x341b,0x341c,0x341d,0x341e,
+ 0xffff
+};
+static u16 ccrtc_1280x1024x16[] VAR16 = {
+ 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+ 0x6009,0x000c,0x000d,
+ 0x0310,0xff12,0x4013,0x4014,0xff15,0x2416,0xc317,0xff18,
+ 0x001a,0x321b,0x001d,
+ 0xffff
+};
+
+/* 1600x1200x8 */
+static u16 cseq_1600x1200x8[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+ 0x760b,0x760c,0x760d,0x760e,
+ 0x0412,0x0013,0x2017,
+ 0x341b,0x341c,0x341d,0x341e,
+ 0xffff
+};
+static u16 ccrtc_1600x1200x8[] VAR16 = {
+ 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+ 0x6009,0x000c,0x000d,
+ 0x0310,0xff12,0xc813,0x4014,0xff15,0x2416,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+
+struct cirrus_mode_s {
+ u16 mode, vesamode;
+ struct vgamode_s info;
+
+ u16 hidden_dac; /* 0x3c6 */
+ u16 *seq; /* 0x3c4 */
+ u16 *graph; /* 0x3ce */
+ u16 *crtc; /* 0x3d4 */
+};
+
+static struct cirrus_mode_s cirrus_modes[] VAR16 = {
+ {0x5f,0x101,{MM_PACKED,640,480,8,8,16,SEG_GRAPH},0x00,
+ cseq_640x480x8,cgraph_svgacolor,ccrtc_640x480x8},
+ {0x64,0x111,{MM_DIRECT,640,480,16,8,16,SEG_GRAPH},0xe1,
+ cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16},
+ {0x66,0x110,{MM_DIRECT,640,480,15,8,16,SEG_GRAPH},0xf0,
+ cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16},
+ {0x71,0x112,{MM_DIRECT,640,480,24,8,16,SEG_GRAPH},0xe5,
+ cseq_640x480x24,cgraph_svgacolor,ccrtc_640x480x24},
+
+ {0x5c,0x103,{MM_PACKED,800,600,8,8,16,SEG_GRAPH},0x00,
+ cseq_800x600x8,cgraph_svgacolor,ccrtc_800x600x8},
+ {0x65,0x114,{MM_DIRECT,800,600,16,8,16,SEG_GRAPH},0xe1,
+ cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16},
+ {0x67,0x113,{MM_DIRECT,800,600,15,8,16,SEG_GRAPH},0xf0,
+ cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16},
+
+ {0x60,0x105,{MM_PACKED,1024,768,8,8,16,SEG_GRAPH},0x00,
+ cseq_1024x768x8,cgraph_svgacolor,ccrtc_1024x768x8},
+ {0x74,0x117,{MM_DIRECT,1024,768,16,8,16,SEG_GRAPH},0xe1,
+ cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16},
+ {0x68,0x116,{MM_DIRECT,1024,768,15,8,16,SEG_GRAPH},0xf0,
+ cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16},
+
+ {0x78,0x115,{MM_DIRECT,800,600,24,8,16,SEG_GRAPH},0xe5,
+ cseq_800x600x24,cgraph_svgacolor,ccrtc_800x600x24},
+ {0x79,0x118,{MM_DIRECT,1024,768,24,8,16,SEG_GRAPH},0xe5,
+ cseq_1024x768x24,cgraph_svgacolor,ccrtc_1024x768x24},
+
+ {0x6d,0x107,{MM_PACKED,1280,1024,8,8,16,SEG_GRAPH},0x00,
+ cseq_1280x1024x8,cgraph_svgacolor,ccrtc_1280x1024x8},
+ {0x69,0x119,{MM_DIRECT,1280,1024,15,8,16,SEG_GRAPH},0xf0,
+ cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16},
+ {0x75,0x11a,{MM_DIRECT,1280,1024,16,8,16,SEG_GRAPH},0xe1,
+ cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16},
+
+ {0x7b,0xffff,{MM_PACKED,1600,1200,8,8,16,SEG_GRAPH},0x00,
+ cseq_1600x1200x8,cgraph_svgacolor,ccrtc_1600x1200x8},
+};
+
+static struct cirrus_mode_s mode_switchback VAR16 =
+ {0xfe,0xffff,{0xff},0,cseq_vga,cgraph_vga,ccrtc_vga};
+
+int
+is_cirrus_mode(struct vgamode_s *vmode_g)
+{
+ return (vmode_g >= &cirrus_modes[0].info
+ && vmode_g <= &cirrus_modes[ARRAY_SIZE(cirrus_modes)-1].info);
+}
+
+struct vgamode_s *
+clext_find_mode(int mode)
+{
+ struct cirrus_mode_s *table_g = cirrus_modes;
+ while (table_g < &cirrus_modes[ARRAY_SIZE(cirrus_modes)]) {
+ if (GET_GLOBAL(table_g->mode) == mode
+ || GET_GLOBAL(table_g->vesamode) == mode)
+ return &table_g->info;
+ table_g++;
+ }
+ return stdvga_find_mode(mode);
+}
+
+void
+clext_list_modes(u16 seg, u16 *dest, u16 *last)
+{
+ int i;
+ for (i=0; i<ARRAY_SIZE(cirrus_modes) && dest<last; i++) {
+ u16 mode = GET_GLOBAL(cirrus_modes[i].vesamode);
+ if (mode == 0xffff)
+ continue;
+ SET_FARVAR(seg, *dest, mode);
+ dest++;
+ }
+ stdvga_list_modes(seg, dest, last);
+}
+
+
+/****************************************************************
+ * helper functions
+ ****************************************************************/
+
+int
+clext_get_window(struct vgamode_s *vmode_g, int window)
+{
+ return stdvga_grdc_read(window + 9);
+}
+
+int
+clext_set_window(struct vgamode_s *vmode_g, int window, int val)
+{
+ if (val >= 0x100)
+ return -1;
+ stdvga_grdc_write(window + 9, val);
+ return 0;
+}
+
+int
+clext_get_linelength(struct vgamode_s *vmode_g)
+{
+ u16 crtc_addr = stdvga_get_crtc();
+ u8 reg13 = stdvga_crtc_read(crtc_addr, 0x13);
+ u8 reg1b = stdvga_crtc_read(crtc_addr, 0x1b);
+ return (((reg1b & 0x10) << 4) + reg13) * 8 / stdvga_vram_ratio(vmode_g);
+}
+
+int
+clext_set_linelength(struct vgamode_s *vmode_g, int val)
+{
+ u16 crtc_addr = stdvga_get_crtc();
+ val = DIV_ROUND_UP(val * stdvga_vram_ratio(vmode_g), 8);
+ stdvga_crtc_write(crtc_addr, 0x13, val);
+ stdvga_crtc_mask(crtc_addr, 0x1b, 0x10, (val & 0x100) >> 4);
+ return 0;
+}
+
+int
+clext_get_displaystart(struct vgamode_s *vmode_g)
+{
+ u16 crtc_addr = stdvga_get_crtc();
+ u8 b2 = stdvga_crtc_read(crtc_addr, 0x0c);
+ u8 b1 = stdvga_crtc_read(crtc_addr, 0x0d);
+ u8 b3 = stdvga_crtc_read(crtc_addr, 0x1b);
+ u8 b4 = stdvga_crtc_read(crtc_addr, 0x1d);
+ int val = (b1 | (b2<<8) | ((b3 & 0x01) << 16) | ((b3 & 0x0c) << 15)
+ | ((b4 & 0x80) << 12));
+ return val * 4 / stdvga_vram_ratio(vmode_g);
+}
+
+int
+clext_set_displaystart(struct vgamode_s *vmode_g, int val)
+{
+ u16 crtc_addr = stdvga_get_crtc();
+ val = val * stdvga_vram_ratio(vmode_g) / 4;
+ stdvga_crtc_write(crtc_addr, 0x0d, val);
+ stdvga_crtc_write(crtc_addr, 0x0c, val >> 8);
+ stdvga_crtc_mask(crtc_addr, 0x1d, 0x80, (val & 0x0800) >> 4);
+ stdvga_crtc_mask(crtc_addr, 0x1b, 0x0d
+ , ((val & 0x0100) >> 8) | ((val & 0x0600) >> 7));
+ return 0;
+}
+
+int
+clext_save_restore(int cmd, u16 seg, void *data)
+{
+ if (cmd & SR_REGISTERS)
+ return -1;
+ return stdvga_save_restore(cmd, seg, data);
+}
+
+
+/****************************************************************
+ * Mode setting
+ ****************************************************************/
+
+static void
+cirrus_switch_mode_setregs(u16 *data, u16 port)
+{
+ for (;;) {
+ u16 val = GET_GLOBAL(*data);
+ if (val == 0xffff)
+ return;
+ outw(val, port);
+ data++;
+ }
+}
+
+static void
+cirrus_switch_mode(struct cirrus_mode_s *table)
+{
+ // Unlock cirrus special
+ stdvga_sequ_write(0x06, 0x12);
+ cirrus_switch_mode_setregs(GET_GLOBAL(table->seq), VGAREG_SEQU_ADDRESS);
+ cirrus_switch_mode_setregs(GET_GLOBAL(table->graph), VGAREG_GRDC_ADDRESS);
+ cirrus_switch_mode_setregs(GET_GLOBAL(table->crtc), stdvga_get_crtc());
+
+ stdvga_pelmask_write(0x00);
+ stdvga_pelmask_read();
+ stdvga_pelmask_read();
+ stdvga_pelmask_read();
+ stdvga_pelmask_read();
+ stdvga_pelmask_write(GET_GLOBAL(table->hidden_dac));
+ stdvga_pelmask_write(0xff);
+
+ u8 memmodel = GET_GLOBAL(table->info.memmodel);
+ u8 on = 0;
+ if (memmodel == MM_PLANAR)
+ on = 0x41;
+ else if (memmodel != MM_TEXT)
+ on = 0x01;
+ stdvga_attr_mask(0x10, 0x01, on);
+ stdvga_attrindex_write(0x20);
+}
+
+static void
+cirrus_enable_16k_granularity(void)
+{
+ stdvga_grdc_mask(0x0b, 0x00, 0x20);
+}
+
+static void
+cirrus_clear_vram(u16 fill)
+{
+ cirrus_enable_16k_granularity();
+ int count = GET_GLOBAL(VBE_total_memory) / (16 * 1024);
+ int i;
+ for (i=0; i<count; i++) {
+ stdvga_grdc_write(0x09, i);
+ memset16_far(SEG_GRAPH, 0, fill, 16 * 1024);
+ }
+ stdvga_grdc_write(0x09, 0x00);
+}
+
+int
+clext_set_mode(struct vgamode_s *vmode_g, int flags)
+{
+ if (!is_cirrus_mode(vmode_g)) {
+ cirrus_switch_mode(&mode_switchback);
+ dprintf(1, "cirrus mode switch regular\n");
+ return stdvga_set_mode(vmode_g, flags);
+ }
+ struct cirrus_mode_s *table_g = container_of(
+ vmode_g, struct cirrus_mode_s, info);
+ cirrus_switch_mode(table_g);
+ if (GET_GLOBAL(vmode_g->memmodel) == MM_PACKED && !(flags & MF_NOPALETTE))
+ stdvga_set_packed_palette();
+ if (!(flags & MF_LINEARFB))
+ cirrus_enable_16k_granularity();
+ if (!(flags & MF_NOCLEARMEM))
+ // fill with 0xff to keep win 2K happy
+ cirrus_clear_vram(flags & MF_LEGACY ? 0xffff : 0x0000);
+ return 0;
+}
+
+
+/****************************************************************
+ * extbios
+ ****************************************************************/
+
+static void
+clext_101280(struct bregs *regs)
+{
+ u8 v = stdvga_crtc_read(stdvga_get_crtc(), 0x27);
+ if (v == 0xa0)
+ // 5430
+ regs->ax = 0x0032;
+ else if (v == 0xb8)
+ // 5446
+ regs->ax = 0x0039;
+ else
+ regs->ax = 0x00ff;
+ regs->bx = 0x00;
+ return;
+}
+
+static void
+clext_101281(struct bregs *regs)
+{
+ // XXX
+ regs->ax = 0x0100;
+}
+
+static void
+clext_101282(struct bregs *regs)
+{
+ regs->al = stdvga_crtc_read(stdvga_get_crtc(), 0x27) & 0x03;
+ regs->ah = 0xAF;
+}
+
+static void
+clext_101285(struct bregs *regs)
+{
+ regs->al = GET_GLOBAL(VBE_total_memory) / (64*1024);
+}
+
+static void
+clext_10129a(struct bregs *regs)
+{
+ regs->ax = 0x4060;
+ regs->cx = 0x1132;
+}
+
+extern void a0h_callback(void);
+ASM16(
+ // fatal: not implemented yet
+ "a0h_callback:"
+ "cli\n"
+ "hlt\n"
+ "lretw");
+
+static void
+clext_1012a0(struct bregs *regs)
+{
+ struct vgamode_s *table_g = clext_find_mode(regs->al & 0x7f);
+ regs->ah = (table_g ? 1 : 0);
+ regs->bx = (u32)a0h_callback;
+ regs->ds = regs->si = regs->es = regs->di = 0xffff;
+}
+
+static void
+clext_1012a1(struct bregs *regs)
+{
+ regs->bx = 0x0e00; // IBM 8512/8513, color
+}
+
+static void
+clext_1012a2(struct bregs *regs)
+{
+ regs->al = 0x07; // HSync 31.5 - 64.0 kHz
+}
+
+static void
+clext_1012ae(struct bregs *regs)
+{
+ regs->al = 0x01; // High Refresh 75Hz
+}
+
+static void
+clext_1012XX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+void
+clext_1012(struct bregs *regs)
+{
+ switch (regs->bl) {
+ case 0x80: clext_101280(regs); break;
+ case 0x81: clext_101281(regs); break;
+ case 0x82: clext_101282(regs); break;
+ case 0x85: clext_101285(regs); break;
+ case 0x9a: clext_10129a(regs); break;
+ case 0xa0: clext_1012a0(regs); break;
+ case 0xa1: clext_1012a1(regs); break;
+ case 0xa2: clext_1012a2(regs); break;
+ case 0xae: clext_1012ae(regs); break;
+ default: clext_1012XX(regs); break;
+ }
+}
+
+
+/****************************************************************
+ * init
+ ****************************************************************/
+
+static int
+cirrus_check(void)
+{
+ stdvga_sequ_write(0x06, 0x92);
+ return stdvga_sequ_read(0x06) == 0x12;
+}
+
+static u8
+cirrus_get_memsize(void)
+{
+ // get DRAM band width
+ u8 v = stdvga_sequ_read(0x0f);
+ u8 x = (v >> 3) & 0x03;
+ if (x == 0x03 && v & 0x80)
+ // 4MB
+ return 0x40;
+ return 0x04 << x;
+}
+
+int
+clext_setup(void)
+{
+ int ret = stdvga_setup();
+ if (ret)
+ return ret;
+
+ dprintf(1, "cirrus init\n");
+ if (! cirrus_check())
+ return -1;
+ dprintf(1, "cirrus init 2\n");
+
+ // memory setup
+ stdvga_sequ_write(0x0a, stdvga_sequ_read(0x0f) & 0x18);
+ // set vga mode
+ stdvga_sequ_write(0x07, 0x00);
+ // reset bitblt
+ stdvga_grdc_write(0x31, 0x04);
+ stdvga_grdc_write(0x31, 0x00);
+
+ if (GET_GLOBAL(HaveRunInit))
+ return 0;
+
+ u32 lfb_addr = 0;
+ int bdf = GET_GLOBAL(VgaBDF);
+ if (CONFIG_VGA_PCI && bdf >= 0)
+ lfb_addr = (pci_config_readl(bdf, PCI_BASE_ADDRESS_0)
+ & PCI_BASE_ADDRESS_MEM_MASK);
+ SET_VGA(VBE_framebuffer, lfb_addr);
+ u16 totalmem = cirrus_get_memsize();
+ SET_VGA(VBE_total_memory, totalmem * 64 * 1024);
+ SET_VGA(VBE_win_granularity, 16);
+
+ return 0;
+}
diff --git a/roms/seabios/vgasrc/clext.h b/roms/seabios/vgasrc/clext.h
new file mode 100644
index 00000000..cf47a5bf
--- /dev/null
+++ b/roms/seabios/vgasrc/clext.h
@@ -0,0 +1,20 @@
+#ifndef __CLEXT_H
+#define __CLEXT_H
+
+#include "types.h" // u16
+
+struct vgamode_s *clext_find_mode(int mode);
+void clext_list_modes(u16 seg, u16 *dest, u16 *last);
+int clext_get_window(struct vgamode_s *vmode_g, int window);
+int clext_set_window(struct vgamode_s *vmode_g, int window, int val);
+int clext_get_linelength(struct vgamode_s *vmode_g);
+int clext_set_linelength(struct vgamode_s *vmode_g, int val);
+int clext_get_displaystart(struct vgamode_s *vmode_g);
+int clext_set_displaystart(struct vgamode_s *vmode_g, int val);
+int clext_save_restore(int cmd, u16 seg, void *data);
+int clext_set_mode(struct vgamode_s *vmode_g, int flags);
+struct bregs;
+void clext_1012(struct bregs *regs);
+int clext_setup(void);
+
+#endif // clext.h
diff --git a/roms/seabios/vgasrc/geodevga.c b/roms/seabios/vgasrc/geodevga.c
new file mode 100644
index 00000000..f8f61c3a
--- /dev/null
+++ b/roms/seabios/vgasrc/geodevga.c
@@ -0,0 +1,433 @@
+// Geode GX2/LX VGA functions
+//
+// Copyright (C) 2009 Chris Kindt
+//
+// Written for Google Summer of Code 2009 for the coreboot project
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_BDA
+#include "farptr.h" // SET_FARVAR
+#include "geodevga.h" // geodevga_setup
+#include "hw/pci.h" // pci_config_readl
+#include "hw/pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "output.h" // dprintf
+#include "stdvga.h" // stdvga_crtc_write
+#include "vgabios.h" // VGAREG_*
+
+
+/****************************************************************
+* MSR and High Mem access through VSA Virtual Register
+****************************************************************/
+
+static u64 geode_msr_read(u32 msrAddr)
+{
+ union u64_u32_u val;
+ asm __volatile__ (
+ "movw $0x0AC1C, %%dx \n"
+ "movl $0xFC530007, %%eax \n"
+ "outl %%eax, %%dx \n"
+ "addb $2, %%dl \n"
+ "inw %%dx, %%ax \n"
+ : "=a" (val.lo), "=d"(val.hi)
+ : "c"(msrAddr)
+ : "cc"
+ );
+
+ dprintf(4, "%s(0x%08x) = 0x%08x-0x%08x\n"
+ , __func__, msrAddr, val.hi, val.lo);
+ return val.val;
+}
+
+static void geode_msr_mask(u32 msrAddr, u64 off, u64 on)
+{
+ union u64_u32_u uand, uor;
+ uand.val = ~off;
+ uor.val = on;
+
+ dprintf(4, "%s(0x%08x, 0x%016llx, 0x%016llx)\n"
+ , __func__, msrAddr, off, on);
+
+ asm __volatile__ (
+ "push %%eax \n"
+ "movw $0x0AC1C, %%dx \n"
+ "movl $0xFC530007, %%eax \n"
+ "outl %%eax, %%dx \n"
+ "addb $2, %%dl \n"
+ "pop %%eax \n"
+ "outw %%ax, %%dx \n"
+ :
+ : "c"(msrAddr), "S" (uand.hi), "D" (uand.lo), "b" (uor.hi), "a" (uor.lo)
+ : "%edx","cc"
+ );
+}
+
+static u32 geode_mem_read(u32 addr)
+{
+ u32 val;
+ asm __volatile__ (
+ "movw $0x0AC1C, %%dx \n"
+ "movl $0xFC530001, %%eax \n"
+ "outl %%eax, %%dx \n"
+ "addb $2, %%dl \n"
+ "inw %%dx, %%ax \n"
+ : "=a" (val)
+ : "b"(addr)
+ : "cc"
+ );
+
+ return val;
+}
+
+static void geode_mem_mask(u32 addr, u32 off, u32 or)
+{
+ asm __volatile__ (
+ "movw $0x0AC1C, %%dx \n"
+ "movl $0xFC530001, %%eax \n"
+ "outl %%eax, %%dx \n"
+ "addb $2, %%dl \n"
+ "outw %%ax, %%dx \n"
+ :
+ : "b"(addr), "S" (~off), "D" (or)
+ : "%eax","cc"
+ );
+}
+
+#define VP_FP_START 0x400
+
+static u32 GeodeFB VAR16;
+static u32 GeodeDC VAR16;
+static u32 GeodeVP VAR16;
+
+static u32 geode_dc_read(int reg)
+{
+ u32 val = geode_mem_read(GET_GLOBAL(GeodeDC) + reg);
+ dprintf(4, "%s(0x%08x) = 0x%08x\n"
+ , __func__, GET_GLOBAL(GeodeDC) + reg, val);
+ return val;
+}
+
+static void geode_dc_write(int reg, u32 val)
+{
+ dprintf(4, "%s(0x%08x, 0x%08x)\n"
+ , __func__, GET_GLOBAL(GeodeDC) + reg, val);
+ geode_mem_mask(GET_GLOBAL(GeodeDC) + reg, ~0, val);
+}
+
+static void geode_dc_mask(int reg, u32 off, u32 on)
+{
+ dprintf(4, "%s(0x%08x, 0x%08x, 0x%08x)\n"
+ , __func__, GET_GLOBAL(GeodeDC) + reg, off, on);
+ geode_mem_mask(GET_GLOBAL(GeodeDC) + reg, off, on);
+}
+
+static u32 geode_vp_read(int reg)
+{
+ u32 val = geode_mem_read(GET_GLOBAL(GeodeVP) + reg);
+ dprintf(4, "%s(0x%08x) = 0x%08x\n"
+ , __func__, GET_GLOBAL(GeodeVP) + reg, val);
+ return val;
+}
+
+static void geode_vp_write(int reg, u32 val)
+{
+ dprintf(4, "%s(0x%08x, 0x%08x)\n"
+ , __func__, GET_GLOBAL(GeodeVP) + reg, val);
+ geode_mem_mask(GET_GLOBAL(GeodeVP) + reg, ~0, val);
+}
+
+static void geode_vp_mask(int reg, u32 off, u32 on)
+{
+ dprintf(4, "%s(0x%08x, 0x%08x, 0x%08x)\n"
+ , __func__, GET_GLOBAL(GeodeVP) + reg, off, on);
+ geode_mem_mask(GET_GLOBAL(GeodeVP) + reg, off, on);
+}
+
+static u32 geode_fp_read(int reg)
+{
+ u32 val = geode_mem_read(GET_GLOBAL(GeodeVP) + VP_FP_START + reg);
+ dprintf(4, "%s(0x%08x) = 0x%08x\n"
+ , __func__, GET_GLOBAL(GeodeVP) + VP_FP_START + reg, val);
+ return val;
+}
+
+static void geode_fp_write(int reg, u32 val)
+{
+ dprintf(4, "%s(0x%08x, 0x%08x)\n"
+ , __func__, GET_GLOBAL(GeodeVP) + VP_FP_START + reg, val);
+ geode_mem_mask(GET_GLOBAL(GeodeVP) + VP_FP_START + reg, ~0, val);
+}
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+static int legacyio_check(void)
+{
+ int ret=0;
+ u64 val;
+
+ if (CONFIG_VGA_GEODEGX2)
+ val = geode_msr_read(GLIU0_P2D_BM_4);
+ else
+ val = geode_msr_read(MSR_GLIU0_BASE4);
+ if ((val & 0xffffffff) != 0x0A0fffe0)
+ ret|=1;
+
+ val = geode_msr_read(GLIU0_IOD_BM_0);
+ if ((val & 0xffffffff) != 0x3c0ffff0)
+ ret|=2;
+
+ val = geode_msr_read(GLIU0_IOD_BM_1);
+ if ((val & 0xffffffff) != 0x3d0ffff0)
+ ret|=4;
+
+ return ret;
+}
+
+static u32 framebuffer_size(void)
+{
+ /* We use the P2D_R0 msr to read out the number of pages.
+ * One page has a size of 4k
+ *
+ * Bit Name Description
+ * 39:20 PMAX Physical Memory Address Max
+ * 19:0 PMIX Physical Memory Address Min
+ *
+ */
+ u64 msr = geode_msr_read(GLIU0_P2D_RO);
+
+ u32 pmax = (msr >> 20) & 0x000fffff;
+ u32 pmin = msr & 0x000fffff;
+
+ u32 val = pmax - pmin;
+ val += 1;
+
+ /* The page size is 4k */
+ return (val << 12);
+}
+
+/****************************************************************
+* Init Functions
+****************************************************************/
+
+static void geodevga_set_output_mode(void)
+{
+ u64 msr_addr;
+ u64 msr;
+
+ /* set output to crt and RGB/YUV */
+ if (CONFIG_VGA_GEODEGX2)
+ msr_addr = VP_MSR_CONFIG_GX2;
+ else
+ msr_addr = VP_MSR_CONFIG_LX;
+
+ /* set output mode (RGB/YUV) */
+ msr = geode_msr_read(msr_addr);
+ msr &= ~VP_MSR_CONFIG_FMT; // mask out FMT (bits 5:3)
+
+ if (CONFIG_VGA_OUTPUT_PANEL || CONFIG_VGA_OUTPUT_CRT_PANEL) {
+ msr |= VP_MSR_CONFIG_FMT_FP; // flat panel
+
+ if (CONFIG_VGA_OUTPUT_CRT_PANEL) {
+ msr |= VP_MSR_CONFIG_FPC; // simultaneous Flat Panel and CRT
+ dprintf(1, "output: simultaneous Flat Panel and CRT\n");
+ } else {
+ msr &= ~VP_MSR_CONFIG_FPC; // no simultaneous Flat Panel and CRT
+ dprintf(1, "ouput: flat panel\n");
+ }
+ } else {
+ msr |= VP_MSR_CONFIG_FMT_CRT; // CRT only
+ dprintf(1, "output: CRT\n");
+ }
+ geode_msr_mask(msr_addr, ~msr, msr);
+}
+
+/* Set up the dc (display controller) portion of the geodelx
+* The dc provides hardware support for VGA graphics.
+*/
+static void dc_setup(void)
+{
+ dprintf(2, "DC_SETUP\n");
+
+ geode_dc_write(DC_UNLOCK, DC_LOCK_UNLOCK);
+
+ /* zero memory config */
+ geode_dc_write(DC_FB_ST_OFFSET, 0x0);
+ geode_dc_write(DC_CB_ST_OFFSET, 0x0);
+ geode_dc_write(DC_CURS_ST_OFFSET, 0x0);
+
+ geode_dc_mask(DC_DISPLAY_CFG, ~DC_CFG_MSK, DC_DISPLAY_CFG_GDEN|DC_DISPLAY_CFG_TRUP);
+ geode_dc_write(DC_GENERAL_CFG, DC_GENERAL_CFG_VGAE);
+
+ geode_dc_write(DC_UNLOCK, DC_LOCK_LOCK);
+}
+
+/* Setup the vp (video processor) portion of the geodelx
+* Under VGA modes the vp was handled by softvg from inside VSA2.
+* Without a softvg module, access is only available through a pci bar.
+* The High Mem Access virtual register is used to configure the
+* pci mmio bar from 16bit friendly io space.
+*/
+static void vp_setup(void)
+{
+ dprintf(2,"VP_SETUP\n");
+
+ geodevga_set_output_mode();
+
+ /* Set mmio registers
+ * there may be some timing issues here, the reads seem
+ * to slow things down enough work reliably
+ */
+
+ u32 reg = geode_vp_read(VP_MISC);
+ dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
+ geode_vp_write(VP_MISC, VP_DCFG_BYP_BOTH);
+ reg = geode_vp_read(VP_MISC);
+ dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
+
+ reg = geode_vp_read(VP_DCFG);
+ dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
+ geode_vp_mask(VP_DCFG, 0, VP_DCFG_CRT_EN|VP_DCFG_HSYNC_EN|VP_DCFG_VSYNC_EN|VP_DCFG_DAC_BL_EN|VP_DCFG_CRT_SKEW);
+ reg = geode_vp_read(VP_DCFG);
+ dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
+
+ /* setup flat panel */
+ if (CONFIG_VGA_OUTPUT_PANEL || CONFIG_VGA_OUTPUT_CRT_PANEL) {
+ u64 msr;
+
+ dprintf(1, "Setting up flat panel\n");
+ /* write timing register */
+ geode_fp_write(FP_PT1, 0x0);
+ geode_fp_write(FP_PT2, FP_PT2_SCRC);
+
+ /* set pad select for TFT/LVDS */
+ msr = VP_MSR_PADSEL_TFT_SEL_HIGH;
+ msr = msr << 32;
+ msr |= VP_MSR_PADSEL_TFT_SEL_LOW;
+ geode_msr_mask(VP_MSR_PADSEL, ~msr, msr);
+
+ /* turn the panel on (if it isn't already) */
+ reg = geode_fp_read(FP_PM);
+ reg |= FP_PM_P;
+ geode_fp_write(FP_PM, reg);
+ }
+}
+
+static u8 geode_crtc_01[] VAR16 = {
+ 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
+ 0xff };
+static u8 geode_crtc_03[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
+ 0xff };
+static u8 geode_crtc_04[] VAR16 = {
+ 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
+ 0xff };
+static u8 geode_crtc_05[] VAR16 = {
+ 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
+ 0xff };
+static u8 geode_crtc_06[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
+ 0xff };
+static u8 geode_crtc_07[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
+ 0xff };
+static u8 geode_crtc_0d[] VAR16 = {
+ 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
+ 0xff };
+static u8 geode_crtc_0e[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
+ 0xff };
+static u8 geode_crtc_0f[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
+ 0xff };
+static u8 geode_crtc_11[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
+ 0xff };
+static u8 geode_crtc_13[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
+ 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
+ 0xff };
+
+int geodevga_setup(void)
+{
+ int ret = stdvga_setup();
+ if (ret)
+ return ret;
+
+ dprintf(1,"GEODEVGA_SETUP\n");
+
+ if ((ret=legacyio_check())) {
+ dprintf(1,"GEODEVGA_SETUP legacyio_check=0x%x\n",ret);
+ }
+
+ // Updated timings from geode datasheets, table 6-53 in particular
+ static u8 *new_crtc[] VAR16 = {
+ geode_crtc_01, geode_crtc_01, geode_crtc_03, geode_crtc_03,
+ geode_crtc_04, geode_crtc_05, geode_crtc_06, geode_crtc_07,
+ 0, 0, 0, 0, 0,
+ geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f,
+ geode_crtc_11, geode_crtc_11, geode_crtc_13 };
+ int i;
+ for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
+ u8 *crtc = GET_GLOBAL(new_crtc[i]);
+ if (crtc)
+ stdvga_override_crtc(i, crtc);
+ }
+
+ if (GET_GLOBAL(VgaBDF) < 0)
+ // Device should be at 00:01.1
+ SET_VGA(VgaBDF, pci_to_bdf(0, 1, 1));
+
+ // setup geode struct which is used for register access
+ SET_VGA(GeodeFB, pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_0));
+ SET_VGA(GeodeDC, pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_2));
+ SET_VGA(GeodeVP, pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_3));
+
+ dprintf(1, "fb addr: 0x%08x\n", GET_GLOBAL(GeodeFB));
+ dprintf(1, "dc addr: 0x%08x\n", GET_GLOBAL(GeodeDC));
+ dprintf(1, "vp addr: 0x%08x\n", GET_GLOBAL(GeodeVP));
+
+ /* setup framebuffer */
+ geode_dc_write(DC_UNLOCK, DC_LOCK_UNLOCK);
+
+ /* read fb-bar from pci, then point dc to the fb base */
+ u32 fb = GET_GLOBAL(GeodeFB);
+ if (geode_dc_read(DC_GLIU0_MEM_OFFSET) != fb)
+ geode_dc_write(DC_GLIU0_MEM_OFFSET, fb);
+
+ geode_dc_write(DC_UNLOCK, DC_LOCK_LOCK);
+
+ u32 fb_size = framebuffer_size(); // in byte
+ dprintf(1, "%d KB of video memory at 0x%08x\n", fb_size / 1024, fb);
+
+ /* update VBE variables */
+ SET_VGA(VBE_framebuffer, fb);
+ SET_VGA(VBE_total_memory, fb_size / 1024 / 64); // number of 64K blocks
+
+ vp_setup();
+ dc_setup();
+
+ return 0;
+}
diff --git a/roms/seabios/vgasrc/geodevga.h b/roms/seabios/vgasrc/geodevga.h
new file mode 100644
index 00000000..61d78084
--- /dev/null
+++ b/roms/seabios/vgasrc/geodevga.h
@@ -0,0 +1,89 @@
+// Geode GX2/LX VGA functions
+//
+// Copyright (C) 2009 Chris Kindt
+//
+// Writen for Google Summer of Code 2009 for the coreboot project
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#ifndef GEODEVGA_H
+#define GEODEVGA_H
+
+#define VRC_INDEX 0xAC1C // Index register
+#define VRC_DATA 0xAC1E // Data register
+#define VR_UNLOCK 0xFC53 // Virtual register unlock code
+
+// Graphics-specific registers:
+#define OEM_BAR0 0x50
+#define OEM_BAR1 0x54
+#define OEM_BAR2 0x58
+#define OEM_BAR3 0x5C
+
+#define DC_LOCK_LOCK 0x00000000
+#define DC_LOCK_UNLOCK 0x00004758
+
+/* LX MSRs */
+#define MSR_GLIU0 (1 << 28)
+#define MSR_GLIU0_BASE4 (MSR_GLIU0 + 0x23) /* LX */
+#define GLIU0_P2D_BM_4 (MSR_GLIU0 + 0x24) /* GX2 */
+#define GLIU0_P2D_RO (MSR_GLIU0 + 0x29)
+#define GLIU0_IOD_BM_0 (MSR_GLIU0 + 0xE0)
+#define GLIU0_IOD_BM_1 (MSR_GLIU0 + 0xE1)
+#define DC_SPARE 0x80000011
+#define VP_MSR_CONFIG_GX2 0xc0002001 /* GX2 */
+#define VP_MSR_CONFIG_LX 0x48002001 /* LX */
+#define VP_MSR_PADSEL 0x48002011
+
+#define VP_MSR_PADSEL_TFT_SEL_LOW 0xDFFFFFFF
+#define VP_MSR_PADSEL_TFT_SEL_HIGH 0x0000003F
+
+/* VP_MSR_CONFIG bits */
+#define VP_MSR_CONFIG_FMT_CRT (0)
+#define VP_MSR_CONFIG_FMT_FP (1 << 3)
+#define VP_MSR_CONFIG_FPC (1 << 15)
+#define VP_MSR_CONFIG_FMT ((1 << 3) | (1 << 4) | (1 << 5))
+
+
+/* DC REG OFFSET */
+#define DC_UNLOCK 0x0
+#define DC_GENERAL_CFG 0x4
+#define DC_DISPLAY_CFG 0x8
+#define DC_FB_ST_OFFSET 0x10
+#define DC_CB_ST_OFFSET 0x14
+#define DC_CURS_ST_OFFSET 0x18
+#define DC_GLIU0_MEM_OFFSET 0x84
+
+/* VP REG OFFSET */
+#define VP_VCFG 0x0
+#define VP_DCFG 0x8
+#define VP_MISC 0x50
+
+/* FP REG OFFSET */
+#define FP_PT1 0x00
+#define FP_PT2 0x08
+#define FP_PM 0x10
+
+
+/* DC bits */
+#define DC_GENERAL_CFG_VGAE (1 << 7)
+#define DC_DISPLAY_CFG_GDEN (1 << 3)
+#define DC_DISPLAY_CFG_TRUP (1 << 6)
+
+/* VP bits */
+#define VP_DCFG_CRT_EN (1 << 0)
+#define VP_DCFG_HSYNC_EN (1 << 1)
+#define VP_DCFG_VSYNC_EN (1 << 2)
+#define VP_DCFG_DAC_BL_EN (1 << 3)
+#define VP_DCFG_CRT_SKEW (1 << 16)
+#define VP_DCFG_BYP_BOTH (1 << 0)
+
+/* FP bits */
+#define FP_PM_P (1 << 24) /* panel power ctl */
+#define FP_PT2_SCRC (1 << 27) /* panel shift clock retrace activity ctl */
+
+/* Mask */
+#define DC_CFG_MSK 0xf000a6
+
+int geodevga_setup();
+
+#endif
diff --git a/roms/seabios/vgasrc/stdvga.c b/roms/seabios/vgasrc/stdvga.c
new file mode 100644
index 00000000..00a0fc57
--- /dev/null
+++ b/roms/seabios/vgasrc/stdvga.c
@@ -0,0 +1,479 @@
+// Standard VGA driver code
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "farptr.h" // SET_FARVAR
+#include "stdvga.h" // stdvga_setup
+#include "string.h" // memset_far
+#include "vgabios.h" // struct vgamode_s
+#include "x86.h" // outb
+
+
+/****************************************************************
+ * Attribute control
+ ****************************************************************/
+
+void
+stdvga_set_border_color(u8 color)
+{
+ u8 v1 = color & 0x0f;
+ if (v1 & 0x08)
+ v1 += 0x08;
+ stdvga_attr_write(0x00, v1);
+
+ int i;
+ for (i = 1; i < 4; i++)
+ stdvga_attr_mask(i, 0x10, color & 0x10);
+}
+
+void
+stdvga_set_overscan_border_color(u8 color)
+{
+ stdvga_attr_write(0x11, color);
+}
+
+u8
+stdvga_get_overscan_border_color(void)
+{
+ return stdvga_attr_read(0x11);
+}
+
+void
+stdvga_set_palette(u8 palid)
+{
+ int i;
+ for (i = 1; i < 4; i++)
+ stdvga_attr_mask(i, 0x01, palid & 0x01);
+}
+
+void
+stdvga_set_all_palette_reg(u16 seg, u8 *data_far)
+{
+ int i;
+ for (i = 0; i < 0x10; i++) {
+ stdvga_attr_write(i, GET_FARVAR(seg, *data_far));
+ data_far++;
+ }
+ stdvga_attr_write(0x11, GET_FARVAR(seg, *data_far));
+}
+
+void
+stdvga_get_all_palette_reg(u16 seg, u8 *data_far)
+{
+ int i;
+ for (i = 0; i < 0x10; i++) {
+ SET_FARVAR(seg, *data_far, stdvga_attr_read(i));
+ data_far++;
+ }
+ SET_FARVAR(seg, *data_far, stdvga_attr_read(0x11));
+}
+
+void
+stdvga_toggle_intensity(u8 flag)
+{
+ stdvga_attr_mask(0x10, 0x08, (flag & 0x01) << 3);
+}
+
+void
+stdvga_select_video_dac_color_page(u8 flag, u8 data)
+{
+ if (!(flag & 0x01)) {
+ // select paging mode
+ stdvga_attr_mask(0x10, 0x80, data << 7);
+ return;
+ }
+ // select page
+ u8 val = stdvga_attr_read(0x10);
+ if (!(val & 0x80))
+ data <<= 2;
+ data &= 0x0f;
+ stdvga_attr_write(0x14, data);
+}
+
+void
+stdvga_read_video_dac_state(u8 *pmode, u8 *curpage)
+{
+ u8 val1 = stdvga_attr_read(0x10) >> 7;
+ u8 val2 = stdvga_attr_read(0x14) & 0x0f;
+ if (!(val1 & 0x01))
+ val2 >>= 2;
+ *pmode = val1;
+ *curpage = val2;
+}
+
+
+/****************************************************************
+ * DAC control
+ ****************************************************************/
+
+void
+stdvga_perform_gray_scale_summing(u16 start, u16 count)
+{
+ stdvga_attrindex_write(0x00);
+ int i;
+ for (i = start; i < start+count; i++) {
+ u8 rgb[3];
+ stdvga_dac_read(GET_SEG(SS), rgb, i, 1);
+
+ // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
+ u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8;
+ if (intensity > 0x3f)
+ intensity = 0x3f;
+ rgb[0] = rgb[1] = rgb[2] = intensity;
+
+ stdvga_dac_write(GET_SEG(SS), rgb, i, 1);
+ }
+ stdvga_attrindex_write(0x20);
+}
+
+
+/****************************************************************
+ * Memory control
+ ****************************************************************/
+
+void
+stdvga_set_text_block_specifier(u8 spec)
+{
+ stdvga_sequ_write(0x03, spec);
+}
+
+// Enable reads and writes to the given "plane" when in planar4 mode.
+void
+stdvga_planar4_plane(int plane)
+{
+ if (plane < 0) {
+ // Return to default mode (read plane0, write all planes)
+ stdvga_sequ_write(0x02, 0x0f);
+ stdvga_grdc_write(0x04, 0);
+ } else {
+ stdvga_sequ_write(0x02, 1<<plane);
+ stdvga_grdc_write(0x04, plane);
+ }
+}
+
+
+/****************************************************************
+ * Font loading
+ ****************************************************************/
+
+static void
+get_font_access(void)
+{
+ stdvga_sequ_write(0x00, 0x01);
+ stdvga_sequ_write(0x02, 0x04);
+ stdvga_sequ_write(0x04, 0x07);
+ stdvga_sequ_write(0x00, 0x03);
+ stdvga_grdc_write(0x04, 0x02);
+ stdvga_grdc_write(0x05, 0x00);
+ stdvga_grdc_write(0x06, 0x04);
+}
+
+static void
+release_font_access(void)
+{
+ stdvga_sequ_write(0x00, 0x01);
+ stdvga_sequ_write(0x02, 0x03);
+ stdvga_sequ_write(0x04, 0x03);
+ stdvga_sequ_write(0x00, 0x03);
+ u16 v = (stdvga_misc_read() & 0x01) ? 0x0e : 0x0a;
+ stdvga_grdc_write(0x06, v);
+ stdvga_grdc_write(0x04, 0x00);
+ stdvga_grdc_write(0x05, 0x10);
+}
+
+void
+stdvga_load_font(u16 seg, void *src_far, u16 count
+ , u16 start, u8 destflags, u8 fontsize)
+{
+ get_font_access();
+ u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
+ void *dest_far = (void*)(blockaddr + start*32);
+ u16 i;
+ for (i = 0; i < count; i++)
+ memcpy_far(SEG_GRAPH, dest_far + i*32
+ , seg, src_far + i*fontsize, fontsize);
+ release_font_access();
+}
+
+
+/****************************************************************
+ * CRTC registers
+ ****************************************************************/
+
+u16
+stdvga_get_crtc(void)
+{
+ if (stdvga_misc_read() & 1)
+ return VGAREG_VGA_CRTC_ADDRESS;
+ return VGAREG_MDA_CRTC_ADDRESS;
+}
+
+// Ratio between system visible framebuffer ram and the actual videoram used.
+int
+stdvga_vram_ratio(struct vgamode_s *vmode_g)
+{
+ switch (GET_GLOBAL(vmode_g->memmodel)) {
+ case MM_TEXT:
+ return 2;
+ case MM_CGA:
+ return 4 / GET_GLOBAL(vmode_g->depth);
+ case MM_PLANAR:
+ return 4;
+ default:
+ return 1;
+ }
+}
+
+void
+stdvga_set_cursor_shape(u16 cursor_type)
+{
+ u16 crtc_addr = stdvga_get_crtc();
+ stdvga_crtc_write(crtc_addr, 0x0a, cursor_type >> 8);
+ stdvga_crtc_write(crtc_addr, 0x0b, cursor_type);
+}
+
+void
+stdvga_set_cursor_pos(int address)
+{
+ u16 crtc_addr = stdvga_get_crtc();
+ address /= 2; // Assume we're in text mode.
+ stdvga_crtc_write(crtc_addr, 0x0e, address >> 8);
+ stdvga_crtc_write(crtc_addr, 0x0f, address);
+}
+
+void
+stdvga_set_scan_lines(u8 lines)
+{
+ stdvga_crtc_mask(stdvga_get_crtc(), 0x09, 0x1f, lines - 1);
+}
+
+// Get vertical display end
+u16
+stdvga_get_vde(void)
+{
+ u16 crtc_addr = stdvga_get_crtc();
+ u16 vde = stdvga_crtc_read(crtc_addr, 0x12);
+ u8 ovl = stdvga_crtc_read(crtc_addr, 0x07);
+ vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
+ return vde;
+}
+
+int
+stdvga_get_window(struct vgamode_s *vmode_g, int window)
+{
+ return -1;
+}
+
+int
+stdvga_set_window(struct vgamode_s *vmode_g, int window, int val)
+{
+ return -1;
+}
+
+int
+stdvga_get_linelength(struct vgamode_s *vmode_g)
+{
+ u8 val = stdvga_crtc_read(stdvga_get_crtc(), 0x13);
+ return val * 8 / stdvga_vram_ratio(vmode_g);
+}
+
+int
+stdvga_set_linelength(struct vgamode_s *vmode_g, int val)
+{
+ val = DIV_ROUND_UP(val * stdvga_vram_ratio(vmode_g), 8);
+ stdvga_crtc_write(stdvga_get_crtc(), 0x13, val);
+ return 0;
+}
+
+int
+stdvga_get_displaystart(struct vgamode_s *vmode_g)
+{
+ u16 crtc_addr = stdvga_get_crtc();
+ int addr = (stdvga_crtc_read(crtc_addr, 0x0c) << 8
+ | stdvga_crtc_read(crtc_addr, 0x0d));
+ return addr * 4 / stdvga_vram_ratio(vmode_g);
+}
+
+int
+stdvga_set_displaystart(struct vgamode_s *vmode_g, int val)
+{
+ u16 crtc_addr = stdvga_get_crtc();
+ val = val * stdvga_vram_ratio(vmode_g) / 4;
+ stdvga_crtc_write(crtc_addr, 0x0c, val >> 8);
+ stdvga_crtc_write(crtc_addr, 0x0d, val);
+ return 0;
+}
+
+int
+stdvga_get_dacformat(struct vgamode_s *vmode_g)
+{
+ return -1;
+}
+
+int
+stdvga_set_dacformat(struct vgamode_s *vmode_g, int val)
+{
+ return -1;
+}
+
+
+/****************************************************************
+ * Save/Restore state
+ ****************************************************************/
+
+struct saveVideoHardware {
+ u8 sequ_index;
+ u8 crtc_index;
+ u8 grdc_index;
+ u8 actl_index;
+ u8 feature;
+ u8 sequ_regs[4];
+ u8 sequ0;
+ u8 crtc_regs[25];
+ u8 actl_regs[20];
+ u8 grdc_regs[9];
+ u16 crtc_addr;
+ u8 plane_latch[4];
+} PACKED;
+
+static void
+stdvga_save_hw_state(u16 seg, struct saveVideoHardware *info)
+{
+ u16 crtc_addr = stdvga_get_crtc();
+ SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
+ SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
+ SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
+ SET_FARVAR(seg, info->actl_index, stdvga_attrindex_read());
+ SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
+
+ int i;
+ for (i=0; i<4; i++)
+ SET_FARVAR(seg, info->sequ_regs[i], stdvga_sequ_read(i+1));
+ SET_FARVAR(seg, info->sequ0, stdvga_sequ_read(0));
+
+ for (i=0; i<25; i++)
+ SET_FARVAR(seg, info->crtc_regs[i], stdvga_crtc_read(crtc_addr, i));
+
+ for (i=0; i<20; i++)
+ SET_FARVAR(seg, info->actl_regs[i], stdvga_attr_read(i));
+
+ for (i=0; i<9; i++)
+ SET_FARVAR(seg, info->grdc_regs[i], stdvga_grdc_read(i));
+
+ SET_FARVAR(seg, info->crtc_addr, crtc_addr);
+
+ /* XXX: read plane latches */
+ for (i=0; i<4; i++)
+ SET_FARVAR(seg, info->plane_latch[i], 0);
+}
+
+static void
+stdvga_restore_hw_state(u16 seg, struct saveVideoHardware *info)
+{
+ int i;
+ for (i=0; i<4; i++)
+ stdvga_sequ_write(i+1, GET_FARVAR(seg, info->sequ_regs[i]));
+ stdvga_sequ_write(0x00, GET_FARVAR(seg, info->sequ0));
+
+ // Disable CRTC write protection
+ u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
+ stdvga_crtc_write(crtc_addr, 0x11, 0x00);
+ // Set CRTC regs
+ for (i=0; i<25; i++)
+ if (i != 0x11)
+ stdvga_crtc_write(crtc_addr, i, GET_FARVAR(seg, info->crtc_regs[i]));
+ // select crtc base address
+ stdvga_misc_mask(0x01, crtc_addr == VGAREG_VGA_CRTC_ADDRESS ? 0x01 : 0x00);
+
+ // enable write protection if needed
+ stdvga_crtc_write(crtc_addr, 0x11, GET_FARVAR(seg, info->crtc_regs[0x11]));
+
+ // Set Attribute Ctl
+ for (i=0; i<20; i++)
+ stdvga_attr_write(i, GET_FARVAR(seg, info->actl_regs[i]));
+ stdvga_attrindex_write(GET_FARVAR(seg, info->actl_index));
+
+ for (i=0; i<9; i++)
+ stdvga_grdc_write(i, GET_FARVAR(seg, info->grdc_regs[i]));
+
+ outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
+ outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
+ outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
+ outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
+}
+
+struct saveDACcolors {
+ u8 rwmode;
+ u8 peladdr;
+ u8 pelmask;
+ u8 dac[768];
+ u8 color_select;
+} PACKED;
+
+static void
+stdvga_save_dac_state(u16 seg, struct saveDACcolors *info)
+{
+ /* XXX: check this */
+ SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE));
+ SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS));
+ SET_FARVAR(seg, info->pelmask, stdvga_pelmask_read());
+ stdvga_dac_read(seg, info->dac, 0, 256);
+ SET_FARVAR(seg, info->color_select, 0);
+}
+
+static void
+stdvga_restore_dac_state(u16 seg, struct saveDACcolors *info)
+{
+ stdvga_pelmask_write(GET_FARVAR(seg, info->pelmask));
+ stdvga_dac_write(seg, info->dac, 0, 256);
+ outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
+}
+
+int
+stdvga_save_restore(int cmd, u16 seg, void *data)
+{
+ void *pos = data;
+ if (cmd & SR_HARDWARE) {
+ if (cmd & SR_SAVE)
+ stdvga_save_hw_state(seg, pos);
+ if (cmd & SR_RESTORE)
+ stdvga_restore_hw_state(seg, pos);
+ pos += sizeof(struct saveVideoHardware);
+ }
+ pos += bda_save_restore(cmd, seg, pos);
+ if (cmd & SR_DAC) {
+ if (cmd & SR_SAVE)
+ stdvga_save_dac_state(seg, pos);
+ if (cmd & SR_RESTORE)
+ stdvga_restore_dac_state(seg, pos);
+ pos += sizeof(struct saveDACcolors);
+ }
+ return pos - data;
+}
+
+
+/****************************************************************
+ * Misc
+ ****************************************************************/
+
+void
+stdvga_enable_video_addressing(u8 disable)
+{
+ u8 v = (disable & 1) ? 0x00 : 0x02;
+ stdvga_misc_mask(0x02, v);
+}
+
+int
+stdvga_setup(void)
+{
+ // switch to color mode and enable CPU access 480 lines
+ stdvga_misc_write(0xc3);
+ // more than 64k 3C4/04
+ stdvga_sequ_write(0x04, 0x02);
+
+ return 0;
+}
diff --git a/roms/seabios/vgasrc/stdvga.h b/roms/seabios/vgasrc/stdvga.h
new file mode 100644
index 00000000..39753b4d
--- /dev/null
+++ b/roms/seabios/vgasrc/stdvga.h
@@ -0,0 +1,111 @@
+#ifndef __STDVGA_H
+#define __STDVGA_H
+
+#include "types.h" // u8
+
+// VGA registers
+#define VGAREG_ACTL_ADDRESS 0x3c0
+#define VGAREG_ACTL_WRITE_DATA 0x3c0
+#define VGAREG_ACTL_READ_DATA 0x3c1
+
+#define VGAREG_INPUT_STATUS 0x3c2
+#define VGAREG_WRITE_MISC_OUTPUT 0x3c2
+#define VGAREG_VIDEO_ENABLE 0x3c3
+#define VGAREG_SEQU_ADDRESS 0x3c4
+#define VGAREG_SEQU_DATA 0x3c5
+
+#define VGAREG_PEL_MASK 0x3c6
+#define VGAREG_DAC_STATE 0x3c7
+#define VGAREG_DAC_READ_ADDRESS 0x3c7
+#define VGAREG_DAC_WRITE_ADDRESS 0x3c8
+#define VGAREG_DAC_DATA 0x3c9
+
+#define VGAREG_READ_FEATURE_CTL 0x3ca
+#define VGAREG_READ_MISC_OUTPUT 0x3cc
+
+#define VGAREG_GRDC_ADDRESS 0x3ce
+#define VGAREG_GRDC_DATA 0x3cf
+
+#define VGAREG_MDA_CRTC_ADDRESS 0x3b4
+#define VGAREG_MDA_CRTC_DATA 0x3b5
+#define VGAREG_VGA_CRTC_ADDRESS 0x3d4
+#define VGAREG_VGA_CRTC_DATA 0x3d5
+
+#define VGAREG_MDA_WRITE_FEATURE_CTL 0x3ba
+#define VGAREG_VGA_WRITE_FEATURE_CTL 0x3da
+#define VGAREG_ACTL_RESET 0x3da
+
+#define VGAREG_MDA_MODECTL 0x3b8
+#define VGAREG_CGA_MODECTL 0x3d8
+#define VGAREG_CGA_PALETTE 0x3d9
+
+/* Video memory */
+#define SEG_GRAPH 0xA000
+#define SEG_CTEXT 0xB800
+#define SEG_MTEXT 0xB000
+
+// stdvgamodes.c
+struct vgamode_s *stdvga_find_mode(int mode);
+void stdvga_list_modes(u16 seg, u16 *dest, u16 *last);
+void stdvga_build_video_param(void);
+void stdvga_override_crtc(int mode, u8 *crtc);
+int stdvga_set_mode(struct vgamode_s *vmode_g, int flags);
+void stdvga_set_packed_palette(void);
+
+// stdvgaio.c
+u8 stdvga_pelmask_read(void);
+void stdvga_pelmask_write(u8 val);
+u8 stdvga_misc_read(void);
+void stdvga_misc_write(u8 value);
+void stdvga_misc_mask(u8 off, u8 on);
+u8 stdvga_sequ_read(u8 index);
+void stdvga_sequ_write(u8 index, u8 value);
+void stdvga_sequ_mask(u8 index, u8 off, u8 on);
+u8 stdvga_grdc_read(u8 index);
+void stdvga_grdc_write(u8 index, u8 value);
+void stdvga_grdc_mask(u8 index, u8 off, u8 on);
+u8 stdvga_crtc_read(u16 crtc_addr, u8 index);
+void stdvga_crtc_write(u16 crtc_addr, u8 index, u8 value);
+void stdvga_crtc_mask(u16 crtc_addr, u8 index, u8 off, u8 on);
+u8 stdvga_attr_read(u8 index);
+void stdvga_attr_write(u8 index, u8 value);
+void stdvga_attr_mask(u8 index, u8 off, u8 on);
+u8 stdvga_attrindex_read(void);
+void stdvga_attrindex_write(u8 value);
+void stdvga_dac_read(u16 seg, u8 *data_far, u8 start, int count);
+void stdvga_dac_write(u16 seg, u8 *data_far, u8 start, int count);
+
+// stdvga.c
+void stdvga_set_border_color(u8 color);
+void stdvga_set_overscan_border_color(u8 color);
+u8 stdvga_get_overscan_border_color(void);
+void stdvga_set_palette(u8 palid);
+void stdvga_set_all_palette_reg(u16 seg, u8 *data_far);
+void stdvga_get_all_palette_reg(u16 seg, u8 *data_far);
+void stdvga_toggle_intensity(u8 flag);
+void stdvga_select_video_dac_color_page(u8 flag, u8 data);
+void stdvga_read_video_dac_state(u8 *pmode, u8 *curpage);
+void stdvga_perform_gray_scale_summing(u16 start, u16 count);
+void stdvga_set_text_block_specifier(u8 spec);
+void stdvga_planar4_plane(int plane);
+void stdvga_load_font(u16 seg, void *src_far, u16 count
+ , u16 start, u8 destflags, u8 fontsize);
+u16 stdvga_get_crtc(void);
+int stdvga_vram_ratio(struct vgamode_s *vmode_g);
+void stdvga_set_cursor_shape(u16 cursor_type);
+void stdvga_set_cursor_pos(int address);
+void stdvga_set_scan_lines(u8 lines);
+u16 stdvga_get_vde(void);
+int stdvga_get_window(struct vgamode_s *vmode_g, int window);
+int stdvga_set_window(struct vgamode_s *vmode_g, int window, int val);
+int stdvga_get_linelength(struct vgamode_s *vmode_g);
+int stdvga_set_linelength(struct vgamode_s *vmode_g, int val);
+int stdvga_get_displaystart(struct vgamode_s *vmode_g);
+int stdvga_set_displaystart(struct vgamode_s *vmode_g, int val);
+int stdvga_get_dacformat(struct vgamode_s *vmode_g);
+int stdvga_set_dacformat(struct vgamode_s *vmode_g, int val);
+int stdvga_save_restore(int cmd, u16 seg, void *data);
+void stdvga_enable_video_addressing(u8 disable);
+int stdvga_setup(void);
+
+#endif // stdvga.h
diff --git a/roms/seabios/vgasrc/stdvgaio.c b/roms/seabios/vgasrc/stdvgaio.c
new file mode 100644
index 00000000..d6138c22
--- /dev/null
+++ b/roms/seabios/vgasrc/stdvgaio.c
@@ -0,0 +1,185 @@
+// Standard VGA IO port access
+//
+// Copyright (C) 2012 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "farptr.h" // GET_FARVAR
+#include "stdvga.h" // stdvga_pelmask_read
+#include "x86.h" // inb
+
+u8
+stdvga_pelmask_read(void)
+{
+ return inb(VGAREG_PEL_MASK);
+}
+
+void
+stdvga_pelmask_write(u8 value)
+{
+ outb(value, VGAREG_PEL_MASK);
+}
+
+
+u8
+stdvga_misc_read(void)
+{
+ return inb(VGAREG_READ_MISC_OUTPUT);
+}
+
+void
+stdvga_misc_write(u8 value)
+{
+ outb(value, VGAREG_WRITE_MISC_OUTPUT);
+}
+
+void
+stdvga_misc_mask(u8 off, u8 on)
+{
+ stdvga_misc_write((stdvga_misc_read() & ~off) | on);
+}
+
+
+u8
+stdvga_sequ_read(u8 index)
+{
+ outb(index, VGAREG_SEQU_ADDRESS);
+ return inb(VGAREG_SEQU_DATA);
+}
+
+void
+stdvga_sequ_write(u8 index, u8 value)
+{
+ outw((value<<8) | index, VGAREG_SEQU_ADDRESS);
+}
+
+void
+stdvga_sequ_mask(u8 index, u8 off, u8 on)
+{
+ outb(index, VGAREG_SEQU_ADDRESS);
+ u8 v = inb(VGAREG_SEQU_DATA);
+ outb((v & ~off) | on, VGAREG_SEQU_DATA);
+}
+
+
+u8
+stdvga_grdc_read(u8 index)
+{
+ outb(index, VGAREG_GRDC_ADDRESS);
+ return inb(VGAREG_GRDC_DATA);
+}
+
+void
+stdvga_grdc_write(u8 index, u8 value)
+{
+ outw((value<<8) | index, VGAREG_GRDC_ADDRESS);
+}
+
+void
+stdvga_grdc_mask(u8 index, u8 off, u8 on)
+{
+ outb(index, VGAREG_GRDC_ADDRESS);
+ u8 v = inb(VGAREG_GRDC_DATA);
+ outb((v & ~off) | on, VGAREG_GRDC_DATA);
+}
+
+
+u8
+stdvga_crtc_read(u16 crtc_addr, u8 index)
+{
+ outb(index, crtc_addr);
+ return inb(crtc_addr + 1);
+}
+
+void
+stdvga_crtc_write(u16 crtc_addr, u8 index, u8 value)
+{
+ outw((value<<8) | index, crtc_addr);
+}
+
+void
+stdvga_crtc_mask(u16 crtc_addr, u8 index, u8 off, u8 on)
+{
+ outb(index, crtc_addr);
+ u8 v = inb(crtc_addr + 1);
+ outb((v & ~off) | on, crtc_addr + 1);
+}
+
+
+u8
+stdvga_attr_read(u8 index)
+{
+ inb(VGAREG_ACTL_RESET);
+ u8 orig = inb(VGAREG_ACTL_ADDRESS);
+ outb(index, VGAREG_ACTL_ADDRESS);
+ u8 v = inb(VGAREG_ACTL_READ_DATA);
+ inb(VGAREG_ACTL_RESET);
+ outb(orig, VGAREG_ACTL_ADDRESS);
+ return v;
+}
+
+void
+stdvga_attr_write(u8 index, u8 value)
+{
+ inb(VGAREG_ACTL_RESET);
+ u8 orig = inb(VGAREG_ACTL_ADDRESS);
+ outb(index, VGAREG_ACTL_ADDRESS);
+ outb(value, VGAREG_ACTL_WRITE_DATA);
+ outb(orig, VGAREG_ACTL_ADDRESS);
+}
+
+void
+stdvga_attr_mask(u8 index, u8 off, u8 on)
+{
+ inb(VGAREG_ACTL_RESET);
+ u8 orig = inb(VGAREG_ACTL_ADDRESS);
+ outb(index, VGAREG_ACTL_ADDRESS);
+ u8 v = inb(VGAREG_ACTL_READ_DATA);
+ outb((v & ~off) | on, VGAREG_ACTL_WRITE_DATA);
+ outb(orig, VGAREG_ACTL_ADDRESS);
+}
+
+u8
+stdvga_attrindex_read(void)
+{
+ inb(VGAREG_ACTL_RESET);
+ return inb(VGAREG_ACTL_ADDRESS);
+}
+
+void
+stdvga_attrindex_write(u8 value)
+{
+ inb(VGAREG_ACTL_RESET);
+ outb(value, VGAREG_ACTL_ADDRESS);
+}
+
+
+void
+stdvga_dac_read(u16 seg, u8 *data_far, u8 start, int count)
+{
+ outb(start, VGAREG_DAC_READ_ADDRESS);
+ while (count) {
+ SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
+ data_far++;
+ SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
+ data_far++;
+ SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
+ data_far++;
+ count--;
+ }
+}
+
+void
+stdvga_dac_write(u16 seg, u8 *data_far, u8 start, int count)
+{
+ outb(start, VGAREG_DAC_WRITE_ADDRESS);
+ while (count) {
+ outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
+ data_far++;
+ outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
+ data_far++;
+ outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
+ data_far++;
+ count--;
+ }
+}
diff --git a/roms/seabios/vgasrc/stdvgamodes.c b/roms/seabios/vgasrc/stdvgamodes.c
new file mode 100644
index 00000000..c553514f
--- /dev/null
+++ b/roms/seabios/vgasrc/stdvgamodes.c
@@ -0,0 +1,523 @@
+// Standard VGA mode information.
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "output.h" // warn_internalerror
+#include "stdvga.h" // stdvga_find_mode
+#include "string.h" // memcpy_far
+#include "vgabios.h" // video_param_table
+
+
+/****************************************************************
+ * Video mode register definitions
+ ****************************************************************/
+
+/* Mono */
+static u8 palette0[] VAR16 = {
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f,
+ 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f,
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f,
+ 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f
+};
+
+static u8 palette1[] VAR16 = {
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+ 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+ 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+ 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+ 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+ 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+ 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+ 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+ 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f
+};
+
+static u8 palette2[] VAR16 = {
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+ 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x2a,0x00, 0x2a,0x2a,0x2a,
+ 0x00,0x00,0x15, 0x00,0x00,0x3f, 0x00,0x2a,0x15, 0x00,0x2a,0x3f,
+ 0x2a,0x00,0x15, 0x2a,0x00,0x3f, 0x2a,0x2a,0x15, 0x2a,0x2a,0x3f,
+ 0x00,0x15,0x00, 0x00,0x15,0x2a, 0x00,0x3f,0x00, 0x00,0x3f,0x2a,
+ 0x2a,0x15,0x00, 0x2a,0x15,0x2a, 0x2a,0x3f,0x00, 0x2a,0x3f,0x2a,
+ 0x00,0x15,0x15, 0x00,0x15,0x3f, 0x00,0x3f,0x15, 0x00,0x3f,0x3f,
+ 0x2a,0x15,0x15, 0x2a,0x15,0x3f, 0x2a,0x3f,0x15, 0x2a,0x3f,0x3f,
+ 0x15,0x00,0x00, 0x15,0x00,0x2a, 0x15,0x2a,0x00, 0x15,0x2a,0x2a,
+ 0x3f,0x00,0x00, 0x3f,0x00,0x2a, 0x3f,0x2a,0x00, 0x3f,0x2a,0x2a,
+ 0x15,0x00,0x15, 0x15,0x00,0x3f, 0x15,0x2a,0x15, 0x15,0x2a,0x3f,
+ 0x3f,0x00,0x15, 0x3f,0x00,0x3f, 0x3f,0x2a,0x15, 0x3f,0x2a,0x3f,
+ 0x15,0x15,0x00, 0x15,0x15,0x2a, 0x15,0x3f,0x00, 0x15,0x3f,0x2a,
+ 0x3f,0x15,0x00, 0x3f,0x15,0x2a, 0x3f,0x3f,0x00, 0x3f,0x3f,0x2a,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+ 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f
+};
+
+static u8 palette3[] VAR16 = {
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+ 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+ 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+ 0x00,0x00,0x00, 0x05,0x05,0x05, 0x08,0x08,0x08, 0x0b,0x0b,0x0b,
+ 0x0e,0x0e,0x0e, 0x11,0x11,0x11, 0x14,0x14,0x14, 0x18,0x18,0x18,
+ 0x1c,0x1c,0x1c, 0x20,0x20,0x20, 0x24,0x24,0x24, 0x28,0x28,0x28,
+ 0x2d,0x2d,0x2d, 0x32,0x32,0x32, 0x38,0x38,0x38, 0x3f,0x3f,0x3f,
+ 0x00,0x00,0x3f, 0x10,0x00,0x3f, 0x1f,0x00,0x3f, 0x2f,0x00,0x3f,
+ 0x3f,0x00,0x3f, 0x3f,0x00,0x2f, 0x3f,0x00,0x1f, 0x3f,0x00,0x10,
+ 0x3f,0x00,0x00, 0x3f,0x10,0x00, 0x3f,0x1f,0x00, 0x3f,0x2f,0x00,
+ 0x3f,0x3f,0x00, 0x2f,0x3f,0x00, 0x1f,0x3f,0x00, 0x10,0x3f,0x00,
+ 0x00,0x3f,0x00, 0x00,0x3f,0x10, 0x00,0x3f,0x1f, 0x00,0x3f,0x2f,
+ 0x00,0x3f,0x3f, 0x00,0x2f,0x3f, 0x00,0x1f,0x3f, 0x00,0x10,0x3f,
+ 0x1f,0x1f,0x3f, 0x27,0x1f,0x3f, 0x2f,0x1f,0x3f, 0x37,0x1f,0x3f,
+ 0x3f,0x1f,0x3f, 0x3f,0x1f,0x37, 0x3f,0x1f,0x2f, 0x3f,0x1f,0x27,
+
+ 0x3f,0x1f,0x1f, 0x3f,0x27,0x1f, 0x3f,0x2f,0x1f, 0x3f,0x37,0x1f,
+ 0x3f,0x3f,0x1f, 0x37,0x3f,0x1f, 0x2f,0x3f,0x1f, 0x27,0x3f,0x1f,
+ 0x1f,0x3f,0x1f, 0x1f,0x3f,0x27, 0x1f,0x3f,0x2f, 0x1f,0x3f,0x37,
+ 0x1f,0x3f,0x3f, 0x1f,0x37,0x3f, 0x1f,0x2f,0x3f, 0x1f,0x27,0x3f,
+ 0x2d,0x2d,0x3f, 0x31,0x2d,0x3f, 0x36,0x2d,0x3f, 0x3a,0x2d,0x3f,
+ 0x3f,0x2d,0x3f, 0x3f,0x2d,0x3a, 0x3f,0x2d,0x36, 0x3f,0x2d,0x31,
+ 0x3f,0x2d,0x2d, 0x3f,0x31,0x2d, 0x3f,0x36,0x2d, 0x3f,0x3a,0x2d,
+ 0x3f,0x3f,0x2d, 0x3a,0x3f,0x2d, 0x36,0x3f,0x2d, 0x31,0x3f,0x2d,
+ 0x2d,0x3f,0x2d, 0x2d,0x3f,0x31, 0x2d,0x3f,0x36, 0x2d,0x3f,0x3a,
+ 0x2d,0x3f,0x3f, 0x2d,0x3a,0x3f, 0x2d,0x36,0x3f, 0x2d,0x31,0x3f,
+ 0x00,0x00,0x1c, 0x07,0x00,0x1c, 0x0e,0x00,0x1c, 0x15,0x00,0x1c,
+ 0x1c,0x00,0x1c, 0x1c,0x00,0x15, 0x1c,0x00,0x0e, 0x1c,0x00,0x07,
+ 0x1c,0x00,0x00, 0x1c,0x07,0x00, 0x1c,0x0e,0x00, 0x1c,0x15,0x00,
+ 0x1c,0x1c,0x00, 0x15,0x1c,0x00, 0x0e,0x1c,0x00, 0x07,0x1c,0x00,
+ 0x00,0x1c,0x00, 0x00,0x1c,0x07, 0x00,0x1c,0x0e, 0x00,0x1c,0x15,
+ 0x00,0x1c,0x1c, 0x00,0x15,0x1c, 0x00,0x0e,0x1c, 0x00,0x07,0x1c,
+
+ 0x0e,0x0e,0x1c, 0x11,0x0e,0x1c, 0x15,0x0e,0x1c, 0x18,0x0e,0x1c,
+ 0x1c,0x0e,0x1c, 0x1c,0x0e,0x18, 0x1c,0x0e,0x15, 0x1c,0x0e,0x11,
+ 0x1c,0x0e,0x0e, 0x1c,0x11,0x0e, 0x1c,0x15,0x0e, 0x1c,0x18,0x0e,
+ 0x1c,0x1c,0x0e, 0x18,0x1c,0x0e, 0x15,0x1c,0x0e, 0x11,0x1c,0x0e,
+ 0x0e,0x1c,0x0e, 0x0e,0x1c,0x11, 0x0e,0x1c,0x15, 0x0e,0x1c,0x18,
+ 0x0e,0x1c,0x1c, 0x0e,0x18,0x1c, 0x0e,0x15,0x1c, 0x0e,0x11,0x1c,
+ 0x14,0x14,0x1c, 0x16,0x14,0x1c, 0x18,0x14,0x1c, 0x1a,0x14,0x1c,
+ 0x1c,0x14,0x1c, 0x1c,0x14,0x1a, 0x1c,0x14,0x18, 0x1c,0x14,0x16,
+ 0x1c,0x14,0x14, 0x1c,0x16,0x14, 0x1c,0x18,0x14, 0x1c,0x1a,0x14,
+ 0x1c,0x1c,0x14, 0x1a,0x1c,0x14, 0x18,0x1c,0x14, 0x16,0x1c,0x14,
+ 0x14,0x1c,0x14, 0x14,0x1c,0x16, 0x14,0x1c,0x18, 0x14,0x1c,0x1a,
+ 0x14,0x1c,0x1c, 0x14,0x1a,0x1c, 0x14,0x18,0x1c, 0x14,0x16,0x1c,
+ 0x00,0x00,0x10, 0x04,0x00,0x10, 0x08,0x00,0x10, 0x0c,0x00,0x10,
+ 0x10,0x00,0x10, 0x10,0x00,0x0c, 0x10,0x00,0x08, 0x10,0x00,0x04,
+ 0x10,0x00,0x00, 0x10,0x04,0x00, 0x10,0x08,0x00, 0x10,0x0c,0x00,
+ 0x10,0x10,0x00, 0x0c,0x10,0x00, 0x08,0x10,0x00, 0x04,0x10,0x00,
+
+ 0x00,0x10,0x00, 0x00,0x10,0x04, 0x00,0x10,0x08, 0x00,0x10,0x0c,
+ 0x00,0x10,0x10, 0x00,0x0c,0x10, 0x00,0x08,0x10, 0x00,0x04,0x10,
+ 0x08,0x08,0x10, 0x0a,0x08,0x10, 0x0c,0x08,0x10, 0x0e,0x08,0x10,
+ 0x10,0x08,0x10, 0x10,0x08,0x0e, 0x10,0x08,0x0c, 0x10,0x08,0x0a,
+ 0x10,0x08,0x08, 0x10,0x0a,0x08, 0x10,0x0c,0x08, 0x10,0x0e,0x08,
+ 0x10,0x10,0x08, 0x0e,0x10,0x08, 0x0c,0x10,0x08, 0x0a,0x10,0x08,
+ 0x08,0x10,0x08, 0x08,0x10,0x0a, 0x08,0x10,0x0c, 0x08,0x10,0x0e,
+ 0x08,0x10,0x10, 0x08,0x0e,0x10, 0x08,0x0c,0x10, 0x08,0x0a,0x10,
+ 0x0b,0x0b,0x10, 0x0c,0x0b,0x10, 0x0d,0x0b,0x10, 0x0f,0x0b,0x10,
+ 0x10,0x0b,0x10, 0x10,0x0b,0x0f, 0x10,0x0b,0x0d, 0x10,0x0b,0x0c,
+ 0x10,0x0b,0x0b, 0x10,0x0c,0x0b, 0x10,0x0d,0x0b, 0x10,0x0f,0x0b,
+ 0x10,0x10,0x0b, 0x0f,0x10,0x0b, 0x0d,0x10,0x0b, 0x0c,0x10,0x0b,
+ 0x0b,0x10,0x0b, 0x0b,0x10,0x0c, 0x0b,0x10,0x0d, 0x0b,0x10,0x0f,
+ 0x0b,0x10,0x10, 0x0b,0x0f,0x10, 0x0b,0x0d,0x10, 0x0b,0x0c,0x10,
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00
+};
+
+static u8 sequ_01[] VAR16 = { 0x08, 0x03, 0x00, 0x02 };
+static u8 crtc_01[] VAR16 = {
+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
+ 0xff };
+static u8 actl_01[] VAR16 = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x0c, 0x00, 0x0f, 0x08 };
+static u8 grdc_01[] VAR16 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff };
+static u8 sequ_03[] VAR16 = { 0x00, 0x03, 0x00, 0x02 };
+static u8 crtc_03[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+ 0xff };
+static u8 sequ_04[] VAR16 = { 0x09, 0x03, 0x00, 0x02 };
+static u8 crtc_04[] VAR16 = {
+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
+ 0xff };
+static u8 actl_04[] VAR16 = {
+ 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x03, 0x00 };
+static u8 grdc_04[] VAR16 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff };
+static u8 sequ_06[] VAR16 = { 0x01, 0x01, 0x00, 0x06 };
+static u8 crtc_06[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2,
+ 0xff };
+static u8 actl_06[] VAR16 = {
+ 0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+ 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+ 0x01, 0x00, 0x01, 0x00 };
+static u8 grdc_06[] VAR16 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0f, 0xff };
+static u8 crtc_07[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
+ 0xff };
+static u8 actl_07[] VAR16 = {
+ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x0e, 0x00, 0x0f, 0x08 };
+static u8 grdc_07[] VAR16 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff };
+static u8 sequ_0d[] VAR16 = { 0x09, 0x0f, 0x00, 0x06 };
+static u8 crtc_0d[] VAR16 = {
+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3,
+ 0xff };
+static u8 actl_0d[] VAR16 = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x0f, 0x00 };
+static u8 grdc_0d[] VAR16 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff };
+static u8 sequ_0e[] VAR16 = { 0x01, 0x0f, 0x00, 0x06 };
+static u8 crtc_0e[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3,
+ 0xff };
+static u8 crtc_0f[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
+ 0xff };
+static u8 actl_0f[] VAR16 = {
+ 0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+ 0x01, 0x00, 0x01, 0x00 };
+static u8 actl_10[] VAR16 = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00 };
+static u8 crtc_11[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
+ 0xff };
+static u8 actl_11[] VAR16 = {
+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00 };
+static u8 sequ_13[] VAR16 = { 0x01, 0x0f, 0x00, 0x0e };
+static u8 crtc_13[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
+ 0xff };
+static u8 actl_13[] VAR16 = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x41, 0x00, 0x0f, 0x00 };
+static u8 grdc_13[] VAR16 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff };
+static u8 crtc_6A[] VAR16 = {
+ 0x7f, 0x63, 0x63, 0x83, 0x6b, 0x1b, 0x72, 0xf0,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x59, 0x8d, 0x57, 0x32, 0x00, 0x57, 0x73, 0xe3,
+ 0xff };
+
+#define PAL(x) x, sizeof(x)
+
+struct stdvga_mode_s {
+ u16 mode;
+ struct vgamode_s info;
+
+ u8 pelmask;
+ u8 *dac;
+ u16 dacsize;
+ u8 *sequ_regs;
+ u8 miscreg;
+ u8 *crtc_regs;
+ u8 *actl_regs;
+ u8 *grdc_regs;
+};
+
+static struct stdvga_mode_s vga_modes[] VAR16 = {
+ //mode { model tx ty bpp cw ch sstart }
+ // pelm dac sequ misc crtc actl grdc
+ {0x00, { MM_TEXT, 40, 25, 4, 9, 16, SEG_CTEXT }
+ , 0xFF, PAL(palette2), sequ_01, 0x67, crtc_01, actl_01, grdc_01},
+ {0x01, { MM_TEXT, 40, 25, 4, 9, 16, SEG_CTEXT }
+ , 0xFF, PAL(palette2), sequ_01, 0x67, crtc_01, actl_01, grdc_01},
+ {0x02, { MM_TEXT, 80, 25, 4, 9, 16, SEG_CTEXT }
+ , 0xFF, PAL(palette2), sequ_03, 0x67, crtc_03, actl_01, grdc_01},
+ {0x03, { MM_TEXT, 80, 25, 4, 9, 16, SEG_CTEXT }
+ , 0xFF, PAL(palette2), sequ_03, 0x67, crtc_03, actl_01, grdc_01},
+ {0x04, { MM_CGA, 320, 200, 2, 8, 8, SEG_CTEXT }
+ , 0xFF, PAL(palette1), sequ_04, 0x63, crtc_04, actl_04, grdc_04},
+ {0x05, { MM_CGA, 320, 200, 2, 8, 8, SEG_CTEXT }
+ , 0xFF, PAL(palette1), sequ_04, 0x63, crtc_04, actl_04, grdc_04},
+ {0x06, { MM_CGA, 640, 200, 1, 8, 8, SEG_CTEXT }
+ , 0xFF, PAL(palette1), sequ_06, 0x63, crtc_06, actl_06, grdc_06},
+ {0x07, { MM_TEXT, 80, 25, 4, 9, 16, SEG_MTEXT }
+ , 0xFF, PAL(palette0), sequ_03, 0x66, crtc_07, actl_07, grdc_07},
+ {0x0D, { MM_PLANAR, 320, 200, 4, 8, 8, SEG_GRAPH }
+ , 0xFF, PAL(palette1), sequ_0d, 0x63, crtc_0d, actl_0d, grdc_0d},
+ {0x0E, { MM_PLANAR, 640, 200, 4, 8, 8, SEG_GRAPH }
+ , 0xFF, PAL(palette1), sequ_0e, 0x63, crtc_0e, actl_0d, grdc_0d},
+ {0x0F, { MM_PLANAR, 640, 350, 1, 8, 14, SEG_GRAPH }
+ , 0xFF, PAL(palette0), sequ_0e, 0xa3, crtc_0f, actl_0f, grdc_0d},
+ {0x10, { MM_PLANAR, 640, 350, 4, 8, 14, SEG_GRAPH }
+ , 0xFF, PAL(palette2), sequ_0e, 0xa3, crtc_0f, actl_10, grdc_0d},
+ {0x11, { MM_PLANAR, 640, 480, 1, 8, 16, SEG_GRAPH }
+ , 0xFF, PAL(palette2), sequ_0e, 0xe3, crtc_11, actl_11, grdc_0d},
+ {0x12, { MM_PLANAR, 640, 480, 4, 8, 16, SEG_GRAPH }
+ , 0xFF, PAL(palette2), sequ_0e, 0xe3, crtc_11, actl_10, grdc_0d},
+ {0x13, { MM_PACKED, 320, 200, 8, 8, 8, SEG_GRAPH }
+ , 0xFF, PAL(palette3), sequ_13, 0x63, crtc_13, actl_13, grdc_13},
+ {0x6A, { MM_PLANAR, 800, 600, 4, 8, 16, SEG_GRAPH }
+ , 0xFF, PAL(palette2), sequ_0e, 0xe3, crtc_6A, actl_10, grdc_0d},
+};
+
+
+/****************************************************************
+ * Mode functions
+ ****************************************************************/
+
+static int
+is_stdvga_mode(struct vgamode_s *vmode_g)
+{
+ return (vmode_g >= &vga_modes[0].info
+ && vmode_g <= &vga_modes[ARRAY_SIZE(vga_modes)-1].info);
+}
+
+struct vgamode_s *
+stdvga_find_mode(int mode)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(vga_modes); i++) {
+ struct stdvga_mode_s *stdmode_g = &vga_modes[i];
+ if (GET_GLOBAL(stdmode_g->mode) == mode)
+ return &stdmode_g->info;
+ }
+ return NULL;
+}
+
+void
+stdvga_list_modes(u16 seg, u16 *dest, u16 *last)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(vga_modes) && dest < last; i++) {
+ struct stdvga_mode_s *stdmode_g = &vga_modes[i];
+ u16 mode = GET_GLOBAL(stdmode_g->mode);
+ if (mode == 0xffff)
+ continue;
+ SET_FARVAR(seg, *dest, mode);
+ dest++;
+ }
+
+ SET_FARVAR(seg, *dest, 0xffff);
+}
+
+void
+stdvga_build_video_param(void)
+{
+ static u8 parammodes[] VAR16 = {
+ 0, 0, 0, 0, 0x04, 0x05, 0x06, 0x07,
+ 0, 0, 0, 0, 0, 0x0d, 0x0e, 0,
+ 0, 0x0f, 0x10, 0, 0, 0, 0, 0x01,
+ 0x03, 0x07, 0x11, 0x12, 0x13
+ };
+
+ int i;
+ for (i=0; i<ARRAY_SIZE(parammodes); i++) {
+ int mode = GET_GLOBAL(parammodes[i]);
+ if (! mode)
+ continue;
+ struct video_param_s *vparam_g = &video_param_table[i];
+ struct vgamode_s *vmode_g = stdvga_find_mode(mode);
+ if (!vmode_g)
+ continue;
+ int width = GET_GLOBAL(vmode_g->width);
+ int height = GET_GLOBAL(vmode_g->height);
+ u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
+ int cheight = GET_GLOBAL(vmode_g->cheight);
+ if (memmodel == MM_TEXT) {
+ SET_VGA(vparam_g->twidth, width);
+ SET_VGA(vparam_g->theightm1, height-1);
+ } else {
+ int cwidth = GET_GLOBAL(vmode_g->cwidth);
+ SET_VGA(vparam_g->twidth, width / cwidth);
+ SET_VGA(vparam_g->theightm1, (height / cheight) - 1);
+ }
+ SET_VGA(vparam_g->cheight, cheight);
+ SET_VGA(vparam_g->slength, calc_page_size(memmodel, width, height));
+ struct stdvga_mode_s *stdmode_g = container_of(
+ vmode_g, struct stdvga_mode_s, info);
+ memcpy_far(get_global_seg(), vparam_g->sequ_regs
+ , get_global_seg(), GET_GLOBAL(stdmode_g->sequ_regs)
+ , ARRAY_SIZE(vparam_g->sequ_regs));
+ SET_VGA(vparam_g->miscreg, GET_GLOBAL(stdmode_g->miscreg));
+ memcpy_far(get_global_seg(), vparam_g->crtc_regs
+ , get_global_seg(), GET_GLOBAL(stdmode_g->crtc_regs)
+ , ARRAY_SIZE(vparam_g->crtc_regs));
+ memcpy_far(get_global_seg(), vparam_g->actl_regs
+ , get_global_seg(), GET_GLOBAL(stdmode_g->actl_regs)
+ , ARRAY_SIZE(vparam_g->actl_regs));
+ memcpy_far(get_global_seg(), vparam_g->grdc_regs
+ , get_global_seg(), GET_GLOBAL(stdmode_g->grdc_regs)
+ , ARRAY_SIZE(vparam_g->grdc_regs));
+ }
+
+ // Fill available legacy modes in video_func_static table
+ u32 modes = 0;
+ for (i = 0; i < ARRAY_SIZE(vga_modes); i++) {
+ u16 mode = vga_modes[i].mode;
+ if (mode <= 0x13)
+ modes |= 1<<i;
+ }
+ SET_VGA(static_functionality.modes, modes);
+}
+
+void
+stdvga_override_crtc(int mode, u8 *crtc)
+{
+ struct vgamode_s *vmode_g = stdvga_find_mode(mode);
+ if (!vmode_g)
+ return;
+ struct stdvga_mode_s *stdmode_g = container_of(
+ vmode_g, struct stdvga_mode_s, info);
+ SET_VGA(stdmode_g->crtc_regs, crtc);
+}
+
+static void
+clear_screen(struct vgamode_s *vmode_g)
+{
+ switch (GET_GLOBAL(vmode_g->memmodel)) {
+ case MM_TEXT:
+ memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
+ break;
+ case MM_CGA:
+ memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
+ break;
+ default:
+ // XXX - old code gets/sets/restores sequ register 2 to 0xf -
+ // but it should always be 0xf anyway.
+ memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
+ }
+}
+
+int
+stdvga_set_mode(struct vgamode_s *vmode_g, int flags)
+{
+ if (! is_stdvga_mode(vmode_g)) {
+ warn_internalerror();
+ return -1;
+ }
+ struct stdvga_mode_s *stdmode_g = container_of(
+ vmode_g, struct stdvga_mode_s, info);
+
+ // if palette loading (bit 3 of modeset ctl = 0)
+ if (!(flags & MF_NOPALETTE)) { // Set the PEL mask
+ stdvga_pelmask_write(GET_GLOBAL(stdmode_g->pelmask));
+
+ // From which palette
+ u8 *palette_g = GET_GLOBAL(stdmode_g->dac);
+ u16 palsize = GET_GLOBAL(stdmode_g->dacsize) / 3;
+
+ // Always 256*3 values
+ stdvga_dac_write(get_global_seg(), palette_g, 0, palsize);
+ int i;
+ for (i = palsize; i < 0x0100; i++) {
+ static u8 rgb[3] VAR16;
+ stdvga_dac_write(get_global_seg(), rgb, i, 1);
+ }
+
+ if (flags & MF_GRAYSUM)
+ stdvga_perform_gray_scale_summing(0x00, 0x100);
+ }
+
+ // Set Attribute Ctl
+ u8 *regs = GET_GLOBAL(stdmode_g->actl_regs);
+ int i;
+ for (i = 0; i <= 0x13; i++)
+ stdvga_attr_write(i, GET_GLOBAL(regs[i]));
+ stdvga_attr_write(0x14, 0x00);
+
+ // Set Sequencer Ctl
+ stdvga_sequ_write(0x00, 0x03);
+ regs = GET_GLOBAL(stdmode_g->sequ_regs);
+ for (i = 1; i <= 4; i++)
+ stdvga_sequ_write(i, GET_GLOBAL(regs[i - 1]));
+
+ // Set Grafx Ctl
+ regs = GET_GLOBAL(stdmode_g->grdc_regs);
+ for (i = 0; i <= 8; i++)
+ stdvga_grdc_write(i, GET_GLOBAL(regs[i]));
+
+ // Set CRTC address VGA or MDA
+ u8 miscreg = GET_GLOBAL(stdmode_g->miscreg);
+ u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
+ if (!(miscreg & 1))
+ crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
+
+ // Disable CRTC write protection
+ stdvga_crtc_write(crtc_addr, 0x11, 0x00);
+ // Set CRTC regs
+ regs = GET_GLOBAL(stdmode_g->crtc_regs);
+ for (i = 0; i <= 0x18; i++)
+ stdvga_crtc_write(crtc_addr, i, GET_GLOBAL(regs[i]));
+
+ // Set the misc register
+ stdvga_misc_write(miscreg);
+
+ // Enable video
+ stdvga_attrindex_write(0x20);
+
+ // Clear screen
+ if (!(flags & MF_NOCLEARMEM))
+ clear_screen(vmode_g);
+
+ // Write the fonts in memory
+ u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
+ if (memmodel == MM_TEXT)
+ stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, 0, 16);
+
+ return 0;
+}
+
+// Load the standard palette associated with 8bpp packed pixel vga modes.
+void
+stdvga_set_packed_palette(void)
+{
+ stdvga_dac_write(get_global_seg(), palette3, 0, sizeof(palette3) / 3);
+}
diff --git a/roms/seabios/vgasrc/vbe.c b/roms/seabios/vgasrc/vbe.c
new file mode 100644
index 00000000..af3d0ccb
--- /dev/null
+++ b/roms/seabios/vgasrc/vbe.c
@@ -0,0 +1,426 @@
+// Video Bios Extensions handlers
+//
+// Copyright (C) 2012 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2011 Julian Pidancet <julian.pidancet@citrix.com>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// 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 "std/vbe.h" // struct vbe_info
+#include "string.h" // memset_far
+#include "vgabios.h" // handle_104f
+#include "vgahw.h" // vgahw_set_mode
+
+u32 VBE_total_memory VAR16 = 256 * 1024;
+u32 VBE_capabilities VAR16;
+u32 VBE_framebuffer VAR16;
+u16 VBE_win_granularity VAR16;
+
+static void
+vbe_104f00(struct bregs *regs)
+{
+ u16 seg = regs->es;
+ struct vbe_info *info = (void*)(regs->di+0);
+
+ if (GET_FARVAR(seg, info->signature) == VBE2_SIGNATURE) {
+ dprintf(4, "Get VBE Controller: VBE2 Signature found\n");
+ } else if (GET_FARVAR(seg, info->signature) == VESA_SIGNATURE) {
+ dprintf(4, "Get VBE Controller: VESA Signature found\n");
+ } else {
+ dprintf(4, "Get VBE Controller: Invalid Signature\n");
+ }
+
+ memset_far(seg, info, 0, sizeof(*info));
+
+ SET_FARVAR(seg, info->signature, VESA_SIGNATURE);
+
+ SET_FARVAR(seg, info->version, 0x0300);
+
+ SET_FARVAR(seg, info->oem_string,
+ SEGOFF(get_global_seg(), (u32)VBE_OEM_STRING));
+ SET_FARVAR(seg, info->capabilities, GET_GLOBAL(VBE_capabilities));
+
+ /* We generate our mode list in the reserved field of the info block */
+ u16 *destmode = (void*)info->reserved;
+ SET_FARVAR(seg, info->video_mode, SEGOFF(seg, (u32)destmode));
+
+ /* Total memory (in 64k blocks) */
+ SET_FARVAR(seg, info->total_memory
+ , GET_GLOBAL(VBE_total_memory) / (64*1024));
+
+ SET_FARVAR(seg, info->oem_vendor_string,
+ SEGOFF(get_global_seg(), (u32)VBE_VENDOR_STRING));
+ SET_FARVAR(seg, info->oem_product_string,
+ SEGOFF(get_global_seg(), (u32)VBE_PRODUCT_STRING));
+ SET_FARVAR(seg, info->oem_revision_string,
+ SEGOFF(get_global_seg(), (u32)VBE_REVISION_STRING));
+
+ /* Fill list of modes */
+ u16 *last = (void*)&info->reserved[sizeof(info->reserved)];
+ vgahw_list_modes(seg, destmode, last - 1);
+
+ regs->ax = 0x004f;
+}
+
+static void
+vbe_104f01(struct bregs *regs)
+{
+ u16 seg = regs->es;
+ struct vbe_mode_info *info = (void*)(regs->di+0);
+ u16 mode = regs->cx;
+
+ dprintf(1, "VBE mode info request: %x\n", mode);
+
+ struct vgamode_s *vmode_g = vgahw_find_mode(mode & ~MF_VBEFLAGS);
+ if (! vmode_g) {
+ dprintf(1, "VBE mode %x not found\n", mode);
+ regs->ax = 0x014f;
+ return;
+ }
+
+ memset_far(seg, info, 0, sizeof(*info));
+
+ // Basic information about video controller.
+ u32 win_granularity = GET_GLOBAL(VBE_win_granularity);
+ SET_FARVAR(seg, info->winA_attributes,
+ (win_granularity ? VBE_WINDOW_ATTRIBUTE_RELOCATABLE : 0) |
+ VBE_WINDOW_ATTRIBUTE_READABLE |
+ VBE_WINDOW_ATTRIBUTE_WRITEABLE);
+ SET_FARVAR(seg, info->winB_attributes, 0);
+ SET_FARVAR(seg, info->win_granularity, win_granularity);
+ SET_FARVAR(seg, info->win_size, 64); /* Bank size 64K */
+ SET_FARVAR(seg, info->winA_seg, GET_GLOBAL(vmode_g->sstart));
+ SET_FARVAR(seg, info->winB_seg, 0x0);
+ extern void entry_104f05(void);
+ SET_FARVAR(seg, info->win_func_ptr
+ , SEGOFF(get_global_seg(), (u32)entry_104f05));
+ // Basic information about mode.
+ int width = GET_GLOBAL(vmode_g->width);
+ int height = GET_GLOBAL(vmode_g->height);
+ int linesize = DIV_ROUND_UP(width * vga_bpp(vmode_g), 8);
+ SET_FARVAR(seg, info->bytes_per_scanline, linesize);
+ SET_FARVAR(seg, info->xres, width);
+ SET_FARVAR(seg, info->yres, height);
+ SET_FARVAR(seg, info->xcharsize, GET_GLOBAL(vmode_g->cwidth));
+ SET_FARVAR(seg, info->ycharsize, GET_GLOBAL(vmode_g->cheight));
+ int depth = GET_GLOBAL(vmode_g->depth);
+ SET_FARVAR(seg, info->bits_per_pixel, depth);
+ u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
+ SET_FARVAR(seg, info->mem_model, memmodel);
+ SET_FARVAR(seg, info->reserved0, 1);
+
+ // Mode specific info.
+ u16 mode_attr = VBE_MODE_ATTRIBUTE_SUPPORTED |
+ VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE |
+ VBE_MODE_ATTRIBUTE_COLOR_MODE |
+ VBE_MODE_ATTRIBUTE_GRAPHICS_MODE |
+ VBE_MODE_ATTRIBUTE_NOT_VGA_COMPATIBLE;
+ u32 framebuffer = 0;
+ int planes = 1, banks = 1;
+ u32 pages = GET_GLOBAL(VBE_total_memory) / ALIGN(height * linesize, 64*1024);
+ switch (memmodel) {
+ case MM_TEXT:
+ mode_attr &= ~VBE_MODE_ATTRIBUTE_GRAPHICS_MODE;
+ mode_attr |= VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT;
+ if (GET_GLOBAL(vmode_g->sstart) == SEG_MTEXT)
+ mode_attr &= ~VBE_MODE_ATTRIBUTE_COLOR_MODE;
+ pages = 1;
+ break;
+ case MM_CGA:
+ pages = 1;
+ banks = 2;
+ SET_FARVAR(seg, info->bank_size, 8);
+ break;
+ case MM_PLANAR:
+ planes = 4;
+ pages /= 4;
+ break;
+ default:
+ framebuffer = GET_GLOBAL(VBE_framebuffer);
+ if (framebuffer)
+ mode_attr |= VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE;
+ break;
+ }
+ if (pages > 128)
+ pages = 128;
+ if (pages < 2)
+ pages++;
+ SET_FARVAR(seg, info->mode_attributes, mode_attr);
+ SET_FARVAR(seg, info->planes, planes);
+ SET_FARVAR(seg, info->pages, pages - 1);
+ SET_FARVAR(seg, info->banks, banks);
+
+ // Pixel color breakdown
+ u8 r_size, r_pos, g_size, g_pos, b_size, b_pos, a_size, a_pos;
+ switch (depth) {
+ case 15: r_size = 5; r_pos = 10; g_size = 5; g_pos = 5;
+ b_size = 5; b_pos = 0; a_size = 1; a_pos = 15; break;
+ case 16: r_size = 5; r_pos = 11; g_size = 6; g_pos = 5;
+ b_size = 5; b_pos = 0; a_size = 0; a_pos = 0; break;
+ case 24: r_size = 8; r_pos = 16; g_size = 8; g_pos = 8;
+ b_size = 8; b_pos = 0; a_size = 0; a_pos = 0; break;
+ case 32: r_size = 8; r_pos = 16; g_size = 8; g_pos = 8;
+ b_size = 8; b_pos = 0; a_size = 8; a_pos = 24;
+ SET_FARVAR(seg, info->directcolor_info,
+ VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE);
+ break;
+ default: r_size = 0; r_pos = 0; g_size = 0; g_pos = 0;
+ b_size = 0; b_pos = 0; a_size = 0; a_pos = 0; break;
+ }
+ SET_FARVAR(seg, info->red_size, r_size);
+ SET_FARVAR(seg, info->red_pos, r_pos);
+ SET_FARVAR(seg, info->green_size, g_size);
+ SET_FARVAR(seg, info->green_pos, g_pos);
+ SET_FARVAR(seg, info->blue_size, b_size);
+ SET_FARVAR(seg, info->blue_pos, b_pos);
+ SET_FARVAR(seg, info->alpha_size, a_size);
+ SET_FARVAR(seg, info->alpha_pos, a_pos);
+
+ // Linear framebuffer info.
+ if (framebuffer) {
+ SET_FARVAR(seg, info->phys_base, framebuffer);
+
+ SET_FARVAR(seg, info->reserved1, 0);
+ SET_FARVAR(seg, info->reserved2, 0);
+ SET_FARVAR(seg, info->linear_bytes_per_scanline, linesize);
+ SET_FARVAR(seg, info->linear_pages, 0);
+ SET_FARVAR(seg, info->linear_red_size, r_size);
+ SET_FARVAR(seg, info->linear_red_pos, r_pos);
+ SET_FARVAR(seg, info->linear_green_size, g_size);
+ SET_FARVAR(seg, info->linear_green_pos, g_pos);
+ SET_FARVAR(seg, info->linear_blue_size, b_size);
+ SET_FARVAR(seg, info->linear_blue_pos, b_pos);
+ SET_FARVAR(seg, info->linear_alpha_size, a_size);
+ SET_FARVAR(seg, info->linear_alpha_pos, a_pos);
+ }
+
+ regs->ax = 0x004f;
+}
+
+static void
+vbe_104f02(struct bregs *regs)
+{
+ dprintf(1, "VBE mode set: %x\n", regs->bx);
+
+ int mode = regs->bx & ~MF_VBEFLAGS;
+ int flags = regs->bx & MF_VBEFLAGS;
+ int ret = vga_set_mode(mode, flags);
+
+ regs->ah = ret;
+ regs->al = 0x4f;
+}
+
+static void
+vbe_104f03(struct bregs *regs)
+{
+ regs->bx = GET_BDA_EXT(vbe_mode);
+ dprintf(1, "VBE current mode=%x\n", regs->bx);
+ regs->ax = 0x004f;
+}
+
+static void
+vbe_104f04(struct bregs *regs)
+{
+ u16 seg = regs->es;
+ void *data = (void*)(regs->bx+0);
+ u16 states = regs->cx;
+ u8 cmd = regs->dl;
+ if (states & ~0x0f || cmd > 2)
+ goto fail;
+ int ret = vgahw_save_restore(states | (cmd<<8), seg, data);
+ if (ret < 0)
+ goto fail;
+ if (cmd == 0)
+ regs->bx = ret / 64;
+ regs->ax = 0x004f;
+ return;
+fail:
+ regs->ax = 0x014f;
+}
+
+void VISIBLE16
+vbe_104f05(struct bregs *regs)
+{
+ if (regs->bh > 1 || regs->bl > 1)
+ goto fail;
+ if (GET_BDA_EXT(vbe_mode) & MF_LINEARFB) {
+ regs->ah = VBE_RETURN_STATUS_INVALID;
+ return;
+ }
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (! vmode_g)
+ goto fail;
+ if (regs->bh) {
+ int ret = vgahw_get_window(vmode_g, regs->bl);
+ if (ret < 0)
+ goto fail;
+ regs->dx = ret;
+ regs->ax = 0x004f;
+ return;
+ }
+ int ret = vgahw_set_window(vmode_g, regs->bl, regs->dx);
+ if (ret)
+ goto fail;
+ regs->ax = 0x004f;
+ return;
+fail:
+ regs->ax = 0x014f;
+}
+
+static void
+vbe_104f06(struct bregs *regs)
+{
+ if (regs->bl > 0x02)
+ goto fail;
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (! vmode_g)
+ goto fail;
+ int bpp = vga_bpp(vmode_g);
+
+ if (regs->bl == 0x00) {
+ int ret = vgahw_set_linelength(vmode_g, DIV_ROUND_UP(regs->cx * bpp, 8));
+ if (ret)
+ goto fail;
+ } else if (regs->bl == 0x02) {
+ int ret = vgahw_set_linelength(vmode_g, regs->cx);
+ if (ret)
+ goto fail;
+ }
+ int linelength = vgahw_get_linelength(vmode_g);
+ if (linelength < 0)
+ goto fail;
+
+ regs->bx = linelength;
+ regs->cx = (linelength * 8) / bpp;
+ regs->dx = GET_GLOBAL(VBE_total_memory) / linelength;
+ regs->ax = 0x004f;
+ return;
+fail:
+ regs->ax = 0x014f;
+}
+
+static void
+vbe_104f07(struct bregs *regs)
+{
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (! vmode_g)
+ goto fail;
+ int bpp = vga_bpp(vmode_g);
+ int linelength = vgahw_get_linelength(vmode_g);
+ if (linelength < 0)
+ goto fail;
+
+ int ret;
+ switch (regs->bl) {
+ case 0x80:
+ case 0x00:
+ ret = vgahw_set_displaystart(
+ vmode_g, DIV_ROUND_UP(regs->cx * bpp, 8) + linelength * regs->dx);
+ if (ret)
+ goto fail;
+ break;
+ case 0x01:
+ ret = vgahw_get_displaystart(vmode_g);
+ if (ret < 0)
+ goto fail;
+ regs->dx = ret / linelength;
+ regs->cx = (ret % linelength) * 8 / bpp;
+ break;
+ default:
+ goto fail;
+ }
+ regs->ax = 0x004f;
+ return;
+fail:
+ regs->ax = 0x014f;
+}
+
+static void
+vbe_104f08(struct bregs *regs)
+{
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (! vmode_g)
+ goto fail;
+ u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
+ if (memmodel == MM_DIRECT || memmodel == MM_YUV) {
+ regs->ax = 0x034f;
+ return;
+ }
+ if (regs->bl > 1)
+ goto fail;
+ if (regs->bl == 0) {
+ int ret = vgahw_set_dacformat(vmode_g, regs->bh);
+ if (ret < 0)
+ goto fail;
+ }
+ int ret = vgahw_get_dacformat(vmode_g);
+ if (ret < 0)
+ goto fail;
+ regs->bh = ret;
+ regs->ax = 0x004f;
+ return;
+fail:
+ regs->ax = 0x014f;
+}
+
+static void
+vbe_104f0a(struct bregs *regs)
+{
+ debug_stub(regs);
+ regs->ax = 0x0100;
+}
+
+static void
+vbe_104f10(struct bregs *regs)
+{
+ switch (regs->bl) {
+ case 0x00:
+ regs->bx = 0x0f30;
+ break;
+ case 0x01:
+ MASK_BDA_EXT(flags, BF_PM_MASK, regs->bh & BF_PM_MASK);
+ break;
+ case 0x02:
+ regs->bh = GET_BDA_EXT(flags) & BF_PM_MASK;
+ break;
+ default:
+ regs->ax = 0x014f;
+ return;
+ }
+ regs->ax = 0x004f;
+}
+
+static void
+vbe_104fXX(struct bregs *regs)
+{
+ debug_stub(regs);
+ regs->ax = 0x0100;
+}
+
+void noinline
+handle_104f(struct bregs *regs)
+{
+ if (!CONFIG_VGA_VBE) {
+ vbe_104fXX(regs);
+ return;
+ }
+
+ switch (regs->al) {
+ case 0x00: vbe_104f00(regs); break;
+ case 0x01: vbe_104f01(regs); break;
+ case 0x02: vbe_104f02(regs); break;
+ case 0x03: vbe_104f03(regs); break;
+ case 0x04: vbe_104f04(regs); break;
+ case 0x05: vbe_104f05(regs); break;
+ case 0x06: vbe_104f06(regs); break;
+ case 0x07: vbe_104f07(regs); break;
+ case 0x08: vbe_104f08(regs); break;
+ case 0x0a: vbe_104f0a(regs); break;
+ case 0x10: vbe_104f10(regs); break;
+ default: vbe_104fXX(regs); break;
+ }
+}
diff --git a/roms/seabios/vgasrc/vgabios.c b/roms/seabios/vgasrc/vgabios.c
new file mode 100644
index 00000000..4aa50e1c
--- /dev/null
+++ b/roms/seabios/vgasrc/vgabios.c
@@ -0,0 +1,1176 @@
+// VGA bios implementation
+//
+// Copyright (C) 2009-2013 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_BDA
+#include "bregs.h" // struct bregs
+#include "clext.h" // clext_1012
+#include "config.h" // CONFIG_*
+#include "output.h" // dprintf
+#include "std/vbe.h" // VBE_RETURN_STATUS_FAILED
+#include "stdvga.h" // stdvga_set_cursor_shape
+#include "string.h" // memset_far
+#include "vgabios.h" // calc_page_size
+#include "vgahw.h" // vgahw_set_mode
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Return the bits per pixel in system memory for a given mode.
+int
+vga_bpp(struct vgamode_s *vmode_g)
+{
+ switch (GET_GLOBAL(vmode_g->memmodel)) {
+ case MM_TEXT:
+ return 16;
+ case MM_PLANAR:
+ return 1;
+ }
+ u8 depth = GET_GLOBAL(vmode_g->depth);
+ if (depth > 8)
+ return ALIGN(depth, 8);
+ return depth;
+}
+
+u16
+calc_page_size(u8 memmodel, u16 width, u16 height)
+{
+ switch (memmodel) {
+ case MM_TEXT:
+ return ALIGN(width * height * 2, 2*1024);
+ case MM_CGA:
+ return 16*1024;
+ default:
+ return ALIGN(width * height / 8, 8*1024);
+ }
+}
+
+// Determine cursor shape (taking into account possible cursor scaling)
+u16
+get_cursor_shape(void)
+{
+ u16 cursor_type = GET_BDA(cursor_type);
+ u8 emulate_cursor = (GET_BDA(video_ctl) & 1) == 0;
+ if (!emulate_cursor)
+ return cursor_type;
+ u8 start = (cursor_type >> 8) & 0x3f;
+ u8 end = cursor_type & 0x1f;
+ u16 cheight = GET_BDA(char_height);
+ if (cheight <= 8 || end >= 8 || start >= 0x20)
+ return cursor_type;
+ if (end != (start + 1))
+ start = ((start + 1) * cheight / 8) - 1;
+ else
+ start = ((end + 1) * cheight / 8) - 2;
+ end = ((end + 1) * cheight / 8) - 1;
+ return (start << 8) | end;
+}
+
+static void
+set_cursor_shape(u16 cursor_type)
+{
+ vgafb_set_swcursor(0);
+ SET_BDA(cursor_type, cursor_type);
+ if (CONFIG_VGA_STDVGA_PORTS)
+ stdvga_set_cursor_shape(get_cursor_shape());
+}
+
+static void
+set_cursor_pos(struct cursorpos cp)
+{
+ u8 page = cp.page, x = cp.x, y = cp.y;
+
+ // Should not happen...
+ if (page > 7)
+ return;
+
+ vgafb_set_swcursor(0);
+
+ // Bios cursor pos
+ SET_BDA(cursor_pos[page], (y << 8) | x);
+
+ if (!CONFIG_VGA_STDVGA_PORTS)
+ return;
+
+ // Set the hardware cursor
+ u8 current = GET_BDA(video_page);
+ if (cp.page != current)
+ return;
+
+ // Calculate the memory address
+ stdvga_set_cursor_pos((int)text_address(cp));
+}
+
+struct cursorpos
+get_cursor_pos(u8 page)
+{
+ if (page == 0xff)
+ // special case - use current page
+ page = GET_BDA(video_page);
+ if (page > 7) {
+ struct cursorpos cp = { 0, 0, 0xfe };
+ return cp;
+ }
+ u16 xy = GET_BDA(cursor_pos[page]);
+ struct cursorpos cp = {xy, xy>>8, page};
+ return cp;
+}
+
+static void
+set_active_page(u8 page)
+{
+ if (page > 7)
+ return;
+
+ // Get the mode
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (!vmode_g)
+ return;
+
+ vgafb_set_swcursor(0);
+
+ // Calculate memory address of start of page
+ struct cursorpos cp = {0, 0, page};
+ int address = (int)text_address(cp);
+ vgahw_set_displaystart(vmode_g, address);
+
+ // And change the BIOS page
+ SET_BDA(video_pagestart, address);
+ SET_BDA(video_page, page);
+
+ dprintf(1, "Set active page %02x address %04x\n", page, address);
+
+ // Display the cursor, now the page is active
+ set_cursor_pos(get_cursor_pos(page));
+}
+
+static void
+set_scan_lines(u8 lines)
+{
+ stdvga_set_scan_lines(lines);
+ SET_BDA(char_height, lines);
+ u16 vde = stdvga_get_vde();
+ u8 rows = vde / lines;
+ SET_BDA(video_rows, rows - 1);
+ u16 cols = GET_BDA(video_cols);
+ SET_BDA(video_pagesize, calc_page_size(MM_TEXT, cols, rows));
+ if (lines == 8)
+ set_cursor_shape(0x0607);
+ else
+ set_cursor_shape(((lines - 3) << 8) | (lines - 2));
+}
+
+
+/****************************************************************
+ * Character writing
+ ****************************************************************/
+
+// Write a character to the screen and calculate new cursor position.
+static void
+write_char(struct cursorpos *pcp, struct carattr ca)
+{
+ vgafb_write_char(*pcp, ca);
+ pcp->x++;
+ // Do we need to wrap ?
+ if (pcp->x == GET_BDA(video_cols)) {
+ pcp->x = 0;
+ pcp->y++;
+ }
+}
+
+// Write a character to the screen at a given position. Implement
+// special characters and scroll the screen if necessary.
+static void
+write_teletype(struct cursorpos *pcp, struct carattr ca)
+{
+ switch (ca.car) {
+ case 7:
+ //FIXME should beep
+ break;
+ case 8:
+ if (pcp->x > 0)
+ pcp->x--;
+ break;
+ case '\r':
+ pcp->x = 0;
+ break;
+ case '\n':
+ pcp->y++;
+ break;
+ default:
+ write_char(pcp, ca);
+ break;
+ }
+
+ // Do we need to scroll ?
+ u16 nbrows = GET_BDA(video_rows);
+ if (pcp->y > nbrows) {
+ pcp->y--;
+
+ struct cursorpos dest = {0, 0, pcp->page};
+ struct cursorpos src = {0, 1, pcp->page};
+ struct cursorpos size = {GET_BDA(video_cols), nbrows};
+ vgafb_move_chars(dest, src, size);
+
+ struct cursorpos clr = {0, nbrows, pcp->page};
+ struct carattr attr = {' ', 0, 0};
+ struct cursorpos clrsize = {GET_BDA(video_cols), 1};
+ vgafb_clear_chars(clr, attr, clrsize);
+ }
+}
+
+
+/****************************************************************
+ * Save and restore bda state
+ ****************************************************************/
+
+struct saveBDAstate {
+ u8 bda_0x49[28];
+ u8 bda_0x84[6];
+ u16 vbe_mode;
+ struct segoff_s font0;
+ struct segoff_s font1;
+};
+
+int
+bda_save_restore(int cmd, u16 seg, void *data)
+{
+ if (!(cmd & SR_BDA))
+ return 0;
+ struct saveBDAstate *info = data;
+ if (cmd & SR_SAVE) {
+ memcpy_far(seg, info->bda_0x49, SEG_BDA, (void*)0x49
+ , sizeof(info->bda_0x49));
+ memcpy_far(seg, info->bda_0x84, SEG_BDA, (void*)0x84
+ , sizeof(info->bda_0x84));
+ SET_FARVAR(seg, info->vbe_mode, GET_BDA_EXT(vbe_mode));
+ SET_FARVAR(seg, info->font0, GET_IVT(0x1f));
+ SET_FARVAR(seg, info->font1, GET_IVT(0x43));
+ }
+ if (cmd & SR_RESTORE) {
+ memcpy_far(SEG_BDA, (void*)0x49, seg, info->bda_0x49
+ , sizeof(info->bda_0x49));
+ memcpy_far(SEG_BDA, (void*)0x84, seg, info->bda_0x84
+ , sizeof(info->bda_0x84));
+ u16 vbe_mode = GET_FARVAR(seg, info->vbe_mode);
+ SET_BDA_EXT(vbe_mode, vbe_mode);
+ struct vgamode_s *vmode_g = vgahw_find_mode(vbe_mode & ~MF_VBEFLAGS);
+ SET_BDA_EXT(vgamode_offset, (u32)vmode_g);
+ SET_IVT(0x1f, GET_FARVAR(seg, info->font0));
+ SET_IVT(0x43, GET_FARVAR(seg, info->font1));
+ }
+ return sizeof(*info);
+}
+
+
+/****************************************************************
+ * Mode setting
+ ****************************************************************/
+
+struct vgamode_s *
+get_current_mode(void)
+{
+ return (void*)(GET_BDA_EXT(vgamode_offset)+0);
+}
+
+// Setup BDA after a mode switch.
+int
+vga_set_mode(int mode, int flags)
+{
+ dprintf(1, "set VGA mode %x\n", mode);
+ struct vgamode_s *vmode_g = vgahw_find_mode(mode);
+ if (!vmode_g)
+ return VBE_RETURN_STATUS_FAILED;
+
+ vgafb_set_swcursor(0);
+
+ int ret = vgahw_set_mode(vmode_g, flags);
+ if (ret)
+ return ret;
+
+ // Set the BIOS mem
+ int width = GET_GLOBAL(vmode_g->width);
+ int height = GET_GLOBAL(vmode_g->height);
+ u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
+ int cheight = GET_GLOBAL(vmode_g->cheight);
+ if (mode < 0x100)
+ SET_BDA(video_mode, mode);
+ else
+ SET_BDA(video_mode, 0xff);
+ SET_BDA_EXT(vbe_mode, mode | (flags & MF_VBEFLAGS));
+ SET_BDA_EXT(vgamode_offset, (u32)vmode_g);
+ if (memmodel == MM_TEXT) {
+ SET_BDA(video_cols, width);
+ SET_BDA(video_rows, height-1);
+ SET_BDA(cursor_type, 0x0607);
+ } else {
+ int cwidth = GET_GLOBAL(vmode_g->cwidth);
+ SET_BDA(video_cols, width / cwidth);
+ SET_BDA(video_rows, (height / cheight) - 1);
+ SET_BDA(cursor_type, vga_emulate_text() ? 0x0607 : 0x0000);
+ }
+ SET_BDA(video_pagesize, calc_page_size(memmodel, width, height));
+ SET_BDA(crtc_address, CONFIG_VGA_STDVGA_PORTS ? stdvga_get_crtc() : 0);
+ SET_BDA(char_height, cheight);
+ SET_BDA(video_ctl, 0x60 | (flags & MF_NOCLEARMEM ? 0x80 : 0x00));
+ SET_BDA(video_switches, 0xF9);
+ SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
+ int i;
+ for (i=0; i<8; i++)
+ SET_BDA(cursor_pos[i], 0x0000);
+ SET_BDA(video_pagestart, 0x0000);
+ SET_BDA(video_page, 0x00);
+
+ // Set the ints 0x1F and 0x43
+ SET_IVT(0x1f, SEGOFF(get_global_seg(), (u32)&vgafont8[128 * 8]));
+
+ switch (cheight) {
+ case 8:
+ SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont8));
+ break;
+ case 14:
+ SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont14));
+ break;
+ case 16:
+ SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont16));
+ break;
+ }
+
+ return 0;
+}
+
+
+/****************************************************************
+ * VGA int 10 handler
+ ****************************************************************/
+
+static void
+handle_1000(struct bregs *regs)
+{
+ int mode = regs->al & 0x7f;
+
+ // Set regs->al
+ if (mode > 7)
+ regs->al = 0x20;
+ else if (mode == 6)
+ regs->al = 0x3f;
+ else
+ regs->al = 0x30;
+
+ int flags = MF_LEGACY | (GET_BDA(modeset_ctl) & (MF_NOPALETTE|MF_GRAYSUM));
+ if (regs->al & 0x80)
+ flags |= MF_NOCLEARMEM;
+
+ vga_set_mode(mode, flags);
+}
+
+static void
+handle_1001(struct bregs *regs)
+{
+ set_cursor_shape(regs->cx);
+}
+
+static void
+handle_1002(struct bregs *regs)
+{
+ struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
+ set_cursor_pos(cp);
+}
+
+static void
+handle_1003(struct bregs *regs)
+{
+ regs->cx = GET_BDA(cursor_type);
+ struct cursorpos cp = get_cursor_pos(regs->bh);
+ regs->dl = cp.x;
+ regs->dh = cp.y;
+}
+
+// Read light pen pos (unimplemented)
+static void
+handle_1004(struct bregs *regs)
+{
+ debug_stub(regs);
+ regs->ax = regs->bx = regs->cx = regs->dx = 0;
+}
+
+static void
+handle_1005(struct bregs *regs)
+{
+ set_active_page(regs->al);
+}
+
+static void
+verify_scroll(struct bregs *regs, int dir)
+{
+ u8 ulx = regs->cl, uly = regs->ch, lrx = regs->dl, lry = regs->dh;
+ u16 nbrows = GET_BDA(video_rows) + 1;
+ if (lry >= nbrows)
+ lry = nbrows - 1;
+ u16 nbcols = GET_BDA(video_cols);
+ if (lrx >= nbcols)
+ lrx = nbcols - 1;
+ int wincols = lrx - ulx + 1, winrows = lry - uly + 1;
+ if (wincols <= 0 || winrows <= 0)
+ return;
+
+ u8 page = GET_BDA(video_page);
+ int clearlines = regs->al, movelines = winrows - clearlines;
+ if (!clearlines || movelines <= 0) {
+ // Clear whole area.
+ struct cursorpos clr = {ulx, uly, page};
+ struct carattr attr = {' ', regs->bh, 1};
+ struct cursorpos clrsize = {wincols, winrows};
+ vgafb_clear_chars(clr, attr, clrsize);
+ return;
+ }
+
+ if (dir > 0) {
+ // Normal scroll
+ struct cursorpos dest = {ulx, uly, page};
+ struct cursorpos src = {ulx, uly + clearlines, page};
+ struct cursorpos size = {wincols, movelines};
+ vgafb_move_chars(dest, src, size);
+
+ struct cursorpos clr = {ulx, uly + movelines, page};
+ struct carattr attr = {' ', regs->bh, 1};
+ struct cursorpos clrsize = {wincols, clearlines};
+ vgafb_clear_chars(clr, attr, clrsize);
+ } else {
+ // Scroll down
+ struct cursorpos dest = {ulx, uly + clearlines, page};
+ struct cursorpos src = {ulx, uly, page};
+ struct cursorpos size = {wincols, movelines};
+ vgafb_move_chars(dest, src, size);
+
+ struct cursorpos clr = {ulx, uly, page};
+ struct carattr attr = {' ', regs->bh, 1};
+ struct cursorpos clrsize = {wincols, clearlines};
+ vgafb_clear_chars(clr, attr, clrsize);
+ }
+}
+
+static void
+handle_1006(struct bregs *regs)
+{
+ verify_scroll(regs, 1);
+}
+
+static void
+handle_1007(struct bregs *regs)
+{
+ verify_scroll(regs, -1);
+}
+
+static void
+handle_1008(struct bregs *regs)
+{
+ struct carattr ca = vgafb_read_char(get_cursor_pos(regs->bh));
+ regs->al = ca.car;
+ regs->ah = ca.attr;
+}
+
+static void noinline
+handle_1009(struct bregs *regs)
+{
+ struct carattr ca = {regs->al, regs->bl, 1};
+ struct cursorpos cp = get_cursor_pos(regs->bh);
+ int count = regs->cx;
+ while (count--)
+ write_char(&cp, ca);
+}
+
+static void noinline
+handle_100a(struct bregs *regs)
+{
+ struct carattr ca = {regs->al, regs->bl, 0};
+ struct cursorpos cp = get_cursor_pos(regs->bh);
+ int count = regs->cx;
+ while (count--)
+ write_char(&cp, ca);
+}
+
+
+static void
+handle_100b00(struct bregs *regs)
+{
+ stdvga_set_border_color(regs->bl);
+}
+
+static void
+handle_100b01(struct bregs *regs)
+{
+ stdvga_set_palette(regs->bl);
+}
+
+static void
+handle_100bXX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+static void
+handle_100b(struct bregs *regs)
+{
+ if (!CONFIG_VGA_STDVGA_PORTS) {
+ handle_100bXX(regs);
+ return;
+ }
+ switch (regs->bh) {
+ case 0x00: handle_100b00(regs); break;
+ case 0x01: handle_100b01(regs); break;
+ default: handle_100bXX(regs); break;
+ }
+}
+
+
+static void
+handle_100c(struct bregs *regs)
+{
+ // XXX - page (regs->bh) is unused
+ vgafb_write_pixel(regs->al, regs->cx, regs->dx);
+}
+
+static void
+handle_100d(struct bregs *regs)
+{
+ // XXX - page (regs->bh) is unused
+ regs->al = vgafb_read_pixel(regs->cx, regs->dx);
+}
+
+static void noinline
+handle_100e(struct bregs *regs)
+{
+ // Ralf Brown Interrupt list is WRONG on bh(page)
+ // We do output only on the current page !
+ struct carattr ca = {regs->al, regs->bl, 0};
+ struct cursorpos cp = get_cursor_pos(0xff);
+ write_teletype(&cp, ca);
+ set_cursor_pos(cp);
+}
+
+static void
+handle_100f(struct bregs *regs)
+{
+ regs->bh = GET_BDA(video_page);
+ regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80);
+ regs->ah = GET_BDA(video_cols);
+}
+
+
+static void
+handle_101000(struct bregs *regs)
+{
+ if (regs->bl > 0x14)
+ return;
+ stdvga_attr_write(regs->bl, regs->bh);
+}
+
+static void
+handle_101001(struct bregs *regs)
+{
+ stdvga_set_overscan_border_color(regs->bh);
+}
+
+static void
+handle_101002(struct bregs *regs)
+{
+ stdvga_set_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
+}
+
+static void
+handle_101003(struct bregs *regs)
+{
+ stdvga_toggle_intensity(regs->bl);
+}
+
+static void
+handle_101007(struct bregs *regs)
+{
+ if (regs->bl > 0x14)
+ return;
+ regs->bh = stdvga_attr_read(regs->bl);
+}
+
+static void
+handle_101008(struct bregs *regs)
+{
+ regs->bh = stdvga_get_overscan_border_color();
+}
+
+static void
+handle_101009(struct bregs *regs)
+{
+ stdvga_get_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
+}
+
+static void noinline
+handle_101010(struct bregs *regs)
+{
+ u8 rgb[3] = {regs->dh, regs->ch, regs->cl};
+ stdvga_dac_write(GET_SEG(SS), rgb, regs->bx, 1);
+}
+
+static void
+handle_101012(struct bregs *regs)
+{
+ stdvga_dac_write(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
+}
+
+static void
+handle_101013(struct bregs *regs)
+{
+ stdvga_select_video_dac_color_page(regs->bl, regs->bh);
+}
+
+static void noinline
+handle_101015(struct bregs *regs)
+{
+ u8 rgb[3];
+ stdvga_dac_read(GET_SEG(SS), rgb, regs->bx, 1);
+ regs->dh = rgb[0];
+ regs->ch = rgb[1];
+ regs->cl = rgb[2];
+}
+
+static void
+handle_101017(struct bregs *regs)
+{
+ stdvga_dac_read(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
+}
+
+static void
+handle_101018(struct bregs *regs)
+{
+ stdvga_pelmask_write(regs->bl);
+}
+
+static void
+handle_101019(struct bregs *regs)
+{
+ regs->bl = stdvga_pelmask_read();
+}
+
+static void
+handle_10101a(struct bregs *regs)
+{
+ stdvga_read_video_dac_state(&regs->bl, &regs->bh);
+}
+
+static void
+handle_10101b(struct bregs *regs)
+{
+ stdvga_perform_gray_scale_summing(regs->bx, regs->cx);
+}
+
+static void
+handle_1010XX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+static void
+handle_1010(struct bregs *regs)
+{
+ if (!CONFIG_VGA_STDVGA_PORTS) {
+ handle_1010XX(regs);
+ return;
+ }
+ switch (regs->al) {
+ case 0x00: handle_101000(regs); break;
+ case 0x01: handle_101001(regs); break;
+ case 0x02: handle_101002(regs); break;
+ case 0x03: handle_101003(regs); break;
+ case 0x07: handle_101007(regs); break;
+ case 0x08: handle_101008(regs); break;
+ case 0x09: handle_101009(regs); break;
+ case 0x10: handle_101010(regs); break;
+ case 0x12: handle_101012(regs); break;
+ case 0x13: handle_101013(regs); break;
+ case 0x15: handle_101015(regs); break;
+ case 0x17: handle_101017(regs); break;
+ case 0x18: handle_101018(regs); break;
+ case 0x19: handle_101019(regs); break;
+ case 0x1a: handle_10101a(regs); break;
+ case 0x1b: handle_10101b(regs); break;
+ default: handle_1010XX(regs); break;
+ }
+}
+
+
+static void
+handle_101100(struct bregs *regs)
+{
+ stdvga_load_font(regs->es, (void*)(regs->bp+0), regs->cx
+ , regs->dx, regs->bl, regs->bh);
+}
+
+static void
+handle_101101(struct bregs *regs)
+{
+ stdvga_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
+}
+
+static void
+handle_101102(struct bregs *regs)
+{
+ stdvga_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
+}
+
+static void
+handle_101103(struct bregs *regs)
+{
+ stdvga_set_text_block_specifier(regs->bl);
+}
+
+static void
+handle_101104(struct bregs *regs)
+{
+ stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
+}
+
+static void
+handle_101110(struct bregs *regs)
+{
+ stdvga_load_font(regs->es, (void*)(regs->bp+0), regs->cx
+ , regs->dx, regs->bl, regs->bh);
+ set_scan_lines(regs->bh);
+}
+
+static void
+handle_101111(struct bregs *regs)
+{
+ stdvga_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
+ set_scan_lines(14);
+}
+
+static void
+handle_101112(struct bregs *regs)
+{
+ stdvga_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
+ set_scan_lines(8);
+}
+
+static void
+handle_101114(struct bregs *regs)
+{
+ stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
+ set_scan_lines(16);
+}
+
+static void
+handle_101120(struct bregs *regs)
+{
+ SET_IVT(0x1f, SEGOFF(regs->es, regs->bp));
+}
+
+void
+load_gfx_font(u16 seg, u16 off, u8 height, u8 bl, u8 dl)
+{
+ u8 rows;
+
+ SET_IVT(0x43, SEGOFF(seg, off));
+ switch(bl) {
+ case 0:
+ rows = dl;
+ break;
+ case 1:
+ rows = 14;
+ break;
+ case 3:
+ rows = 43;
+ break;
+ case 2:
+ default:
+ rows = 25;
+ break;
+ }
+ SET_BDA(video_rows, rows - 1);
+ SET_BDA(char_height, height);
+}
+
+static void
+handle_101121(struct bregs *regs)
+{
+ load_gfx_font(regs->es, regs->bp, regs->cx, regs->bl, regs->dl);
+}
+
+static void
+handle_101122(struct bregs *regs)
+{
+ load_gfx_font(get_global_seg(), (u32)vgafont14, 14, regs->bl, regs->dl);
+}
+
+static void
+handle_101123(struct bregs *regs)
+{
+ load_gfx_font(get_global_seg(), (u32)vgafont8, 8, regs->bl, regs->dl);
+}
+
+static void
+handle_101124(struct bregs *regs)
+{
+ load_gfx_font(get_global_seg(), (u32)vgafont16, 16, regs->bl, regs->dl);
+}
+
+static void
+handle_101130(struct bregs *regs)
+{
+ switch (regs->bh) {
+ case 0x00: {
+ struct segoff_s so = GET_IVT(0x1f);
+ regs->es = so.seg;
+ regs->bp = so.offset;
+ break;
+ }
+ case 0x01: {
+ struct segoff_s so = GET_IVT(0x43);
+ regs->es = so.seg;
+ regs->bp = so.offset;
+ break;
+ }
+ case 0x02:
+ regs->es = get_global_seg();
+ regs->bp = (u32)vgafont14;
+ break;
+ case 0x03:
+ regs->es = get_global_seg();
+ regs->bp = (u32)vgafont8;
+ break;
+ case 0x04:
+ regs->es = get_global_seg();
+ regs->bp = (u32)vgafont8 + 128 * 8;
+ break;
+ case 0x05:
+ regs->es = get_global_seg();
+ regs->bp = (u32)vgafont14alt;
+ break;
+ case 0x06:
+ regs->es = get_global_seg();
+ regs->bp = (u32)vgafont16;
+ break;
+ case 0x07:
+ regs->es = get_global_seg();
+ regs->bp = (u32)vgafont16alt;
+ break;
+ default:
+ dprintf(1, "Get font info BH(%02x) was discarded\n", regs->bh);
+ return;
+ }
+ // Set byte/char of on screen font
+ regs->cx = GET_BDA(char_height) & 0xff;
+
+ // Set Highest char row
+ regs->dl = GET_BDA(video_rows);
+}
+
+static void
+handle_1011XX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+static void
+handle_1011(struct bregs *regs)
+{
+ if (CONFIG_VGA_STDVGA_PORTS) {
+ switch (regs->al) {
+ case 0x00: handle_101100(regs); return;
+ case 0x01: handle_101101(regs); return;
+ case 0x02: handle_101102(regs); return;
+ case 0x03: handle_101103(regs); return;
+ case 0x04: handle_101104(regs); return;
+ case 0x10: handle_101110(regs); return;
+ case 0x11: handle_101111(regs); return;
+ case 0x12: handle_101112(regs); return;
+ case 0x14: handle_101114(regs); return;
+ }
+ }
+ switch (regs->al) {
+ case 0x30: handle_101130(regs); break;
+ case 0x20: handle_101120(regs); break;
+ case 0x21: handle_101121(regs); break;
+ case 0x22: handle_101122(regs); break;
+ case 0x23: handle_101123(regs); break;
+ case 0x24: handle_101124(regs); break;
+ default: handle_1011XX(regs); break;
+ }
+}
+
+
+static void
+handle_101210(struct bregs *regs)
+{
+ u16 crtc_addr = GET_BDA(crtc_address);
+ if (crtc_addr == VGAREG_MDA_CRTC_ADDRESS)
+ regs->bx = 0x0103;
+ else
+ regs->bx = 0x0003;
+ regs->cx = GET_BDA(video_switches) & 0x0f;
+}
+
+static void
+handle_101230(struct bregs *regs)
+{
+ u8 mctl = GET_BDA(modeset_ctl);
+ u8 vswt = GET_BDA(video_switches);
+ switch (regs->al) {
+ case 0x00:
+ // 200 lines
+ mctl = (mctl & ~0x10) | 0x80;
+ vswt = (vswt & ~0x0f) | 0x08;
+ break;
+ case 0x01:
+ // 350 lines
+ mctl &= ~0x90;
+ vswt = (vswt & ~0x0f) | 0x09;
+ break;
+ case 0x02:
+ // 400 lines
+ mctl = (mctl & ~0x80) | 0x10;
+ vswt = (vswt & ~0x0f) | 0x09;
+ break;
+ default:
+ dprintf(1, "Select vert res (%02x) was discarded\n", regs->al);
+ break;
+ }
+ SET_BDA(modeset_ctl, mctl);
+ SET_BDA(video_switches, vswt);
+ regs->al = 0x12;
+}
+
+static void
+handle_101231(struct bregs *regs)
+{
+ u8 v = (regs->al & 0x01) << 3;
+ u8 mctl = GET_BDA(video_ctl) & ~0x08;
+ SET_BDA(video_ctl, mctl | v);
+ regs->al = 0x12;
+}
+
+static void
+handle_101232(struct bregs *regs)
+{
+ if (CONFIG_VGA_STDVGA_PORTS) {
+ stdvga_enable_video_addressing(regs->al);
+ regs->al = 0x12;
+ }
+}
+
+static void
+handle_101233(struct bregs *regs)
+{
+ u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
+ u8 v2 = GET_BDA(modeset_ctl) & ~0x02;
+ SET_BDA(modeset_ctl, v | v2);
+ regs->al = 0x12;
+}
+
+static void
+handle_101234(struct bregs *regs)
+{
+ SET_BDA(video_ctl, (GET_BDA(video_ctl) & ~0x01) | (regs->al & 0x01));
+ regs->al = 0x12;
+}
+
+static void
+handle_101235(struct bregs *regs)
+{
+ debug_stub(regs);
+ regs->al = 0x12;
+}
+
+static void
+handle_101236(struct bregs *regs)
+{
+ debug_stub(regs);
+ regs->al = 0x12;
+}
+
+static void
+handle_1012XX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+static void
+handle_1012(struct bregs *regs)
+{
+ if (CONFIG_VGA_CIRRUS && regs->bl >= 0x80) {
+ clext_1012(regs);
+ return;
+ }
+
+ switch (regs->bl) {
+ case 0x10: handle_101210(regs); break;
+ case 0x30: handle_101230(regs); break;
+ case 0x31: handle_101231(regs); break;
+ case 0x32: handle_101232(regs); break;
+ case 0x33: handle_101233(regs); break;
+ case 0x34: handle_101234(regs); break;
+ case 0x35: handle_101235(regs); break;
+ case 0x36: handle_101236(regs); break;
+ default: handle_1012XX(regs); break;
+ }
+}
+
+
+// Write string
+static void noinline
+handle_1013(struct bregs *regs)
+{
+ struct cursorpos cp;
+ if (regs->dh == 0xff)
+ // if row=0xff special case : use current cursor position
+ cp = get_cursor_pos(regs->bh);
+ else
+ cp = (struct cursorpos) {regs->dl, regs->dh, regs->bh};
+
+ u16 count = regs->cx;
+ u8 *offset_far = (void*)(regs->bp + 0);
+ u8 attr = regs->bl;
+ while (count--) {
+ u8 car = GET_FARVAR(regs->es, *offset_far);
+ offset_far++;
+ if (regs->al & 2) {
+ attr = GET_FARVAR(regs->es, *offset_far);
+ offset_far++;
+ }
+
+ struct carattr ca = {car, attr, 1};
+ write_teletype(&cp, ca);
+ }
+
+ if (regs->al & 1)
+ set_cursor_pos(cp);
+}
+
+
+static void
+handle_101a00(struct bregs *regs)
+{
+ regs->bx = GET_BDA(dcc_index);
+ regs->al = 0x1a;
+}
+
+static void
+handle_101a01(struct bregs *regs)
+{
+ SET_BDA(dcc_index, regs->bl);
+ dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh);
+ regs->al = 0x1a;
+}
+
+static void
+handle_101aXX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+static void
+handle_101a(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x00: handle_101a00(regs); break;
+ case 0x01: handle_101a01(regs); break;
+ default: handle_101aXX(regs); break;
+ }
+}
+
+
+struct video_func_static static_functionality VAR16 = {
+ .modes = 0x00, // Filled in by stdvga_build_video_param()
+ .scanlines = 0x07, // 200, 350, 400 scan lines
+ .cblocks = 0x02, // mamimum number of visible charsets in text mode
+ .active_cblocks = 0x08, // total number of charset blocks in text mode
+ .misc_flags = 0x0ce7,
+};
+
+static void
+handle_101b(struct bregs *regs)
+{
+ u16 seg = regs->es;
+ struct video_func_info *info = (void*)(regs->di+0);
+ memset_far(seg, info, 0, sizeof(*info));
+ // Address of static functionality table
+ SET_FARVAR(seg, info->static_functionality
+ , SEGOFF(get_global_seg(), (u32)&static_functionality));
+
+ // Hard coded copy from BIOS area. Should it be cleaner ?
+ memcpy_far(seg, info->bda_0x49, SEG_BDA, (void*)0x49
+ , sizeof(info->bda_0x49));
+ memcpy_far(seg, info->bda_0x84, SEG_BDA, (void*)0x84
+ , sizeof(info->bda_0x84));
+
+ SET_FARVAR(seg, info->dcc_index, GET_BDA(dcc_index));
+ SET_FARVAR(seg, info->colors, 16);
+ SET_FARVAR(seg, info->pages, 8);
+ SET_FARVAR(seg, info->scan_lines, 2);
+ SET_FARVAR(seg, info->video_mem, 3);
+ regs->al = 0x1B;
+}
+
+
+static void
+handle_101c(struct bregs *regs)
+{
+ u16 seg = regs->es;
+ void *data = (void*)(regs->bx+0);
+ u16 states = regs->cx;
+ u8 cmd = regs->al;
+ if (states & ~0x07 || cmd > 2)
+ goto fail;
+ int ret = vgahw_save_restore(states | (cmd<<8), seg, data);
+ if (ret < 0)
+ goto fail;
+ if (cmd == 0)
+ regs->bx = ret / 64;
+ regs->al = 0x1c;
+fail:
+ return;
+}
+
+static void
+handle_10XX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+// INT 10h Video Support Service Entry Point
+void VISIBLE16
+handle_10(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_VGA_10);
+ switch (regs->ah) {
+ case 0x00: handle_1000(regs); break;
+ case 0x01: handle_1001(regs); break;
+ case 0x02: handle_1002(regs); break;
+ case 0x03: handle_1003(regs); break;
+ case 0x04: handle_1004(regs); break;
+ case 0x05: handle_1005(regs); break;
+ case 0x06: handle_1006(regs); break;
+ case 0x07: handle_1007(regs); break;
+ case 0x08: handle_1008(regs); break;
+ case 0x09: handle_1009(regs); break;
+ case 0x0a: handle_100a(regs); break;
+ case 0x0b: handle_100b(regs); break;
+ case 0x0c: handle_100c(regs); break;
+ case 0x0d: handle_100d(regs); break;
+ case 0x0e: handle_100e(regs); break;
+ case 0x0f: handle_100f(regs); break;
+ case 0x10: handle_1010(regs); break;
+ case 0x11: handle_1011(regs); break;
+ case 0x12: handle_1012(regs); break;
+ case 0x13: handle_1013(regs); break;
+ case 0x1a: handle_101a(regs); break;
+ case 0x1b: handle_101b(regs); break;
+ case 0x1c: handle_101c(regs); break;
+ case 0x4f: handle_104f(regs); break;
+ default: handle_10XX(regs); break;
+ }
+}
diff --git a/roms/seabios/vgasrc/vgabios.h b/roms/seabios/vgasrc/vgabios.h
new file mode 100644
index 00000000..fd796f2e
--- /dev/null
+++ b/roms/seabios/vgasrc/vgabios.h
@@ -0,0 +1,149 @@
+#ifndef __VGABIOS_H
+#define __VGABIOS_H
+
+#include "config.h" // CONFIG_VGA_EMULATE_TEXT
+#include "types.h" // u8
+#include "farptr.h" // struct segoff_s
+#include "std/vga.h" // struct video_param_s
+
+// Save/Restore flags
+#define SR_HARDWARE 0x0001
+#define SR_BDA 0x0002
+#define SR_DAC 0x0004
+#define SR_REGISTERS 0x0008
+#define SR_SAVE 0x0100
+#define SR_RESTORE 0x0200
+
+// Mode flags
+#define MF_LEGACY 0x0001
+#define MF_GRAYSUM 0x0002
+#define MF_NOPALETTE 0x0008
+#define MF_CUSTOMCRTC 0x0800
+#define MF_LINEARFB 0x4000
+#define MF_NOCLEARMEM 0x8000
+#define MF_VBEFLAGS 0xfe00
+
+// Memory model types
+#define MM_TEXT 0x00
+#define MM_CGA 0x01
+#define MM_HERCULES 0x02
+#define MM_PLANAR 0x03
+#define MM_PACKED 0x04
+#define MM_NON_CHAIN_4_256 0x05
+#define MM_DIRECT 0x06
+#define MM_YUV 0x07
+
+struct vgamode_s {
+ u8 memmodel;
+ u16 width;
+ u16 height;
+ u8 depth;
+ u8 cwidth;
+ u8 cheight;
+ u16 sstart;
+};
+
+// Graphics pixel operations.
+struct gfx_op {
+ struct vgamode_s *vmode_g;
+ u32 linelength;
+ u32 displaystart;
+
+ u8 op;
+ u16 x, y;
+
+ u8 pixels[8];
+ u16 xlen, ylen;
+ u16 srcy;
+};
+
+#define GO_READ8 1
+#define GO_WRITE8 2
+#define GO_MEMSET 3
+#define GO_MEMMOVE 4
+
+// Custom internal storage in BDA
+#define VGA_CUSTOM_BDA 0xb9
+
+struct vga_bda_s {
+ u8 flags;
+ u16 vbe_mode;
+ u16 vgamode_offset;
+} PACKED;
+
+#define BF_PM_MASK 0x0f
+#define BF_EMULATE_TEXT 0x10
+#define BF_SWCURSOR 0x20
+
+#define GET_BDA_EXT(var) \
+ GET_FARVAR(SEG_BDA, ((struct vga_bda_s *)VGA_CUSTOM_BDA)->var)
+#define SET_BDA_EXT(var, val) \
+ SET_FARVAR(SEG_BDA, ((struct vga_bda_s *)VGA_CUSTOM_BDA)->var, (val))
+#define MASK_BDA_EXT(var, off, on) \
+ SET_BDA_EXT(var, (GET_BDA_EXT(var) & ~(off)) | (on))
+
+static inline int vga_emulate_text(void) {
+ return CONFIG_VGA_EMULATE_TEXT && GET_BDA_EXT(flags) & BF_EMULATE_TEXT;
+}
+
+// Debug settings
+#define DEBUG_VGA_POST 1
+#define DEBUG_VGA_10 3
+
+// vgafonts.c
+extern u8 vgafont8[];
+extern u8 vgafont14[];
+extern u8 vgafont16[];
+extern u8 vgafont14alt[];
+extern u8 vgafont16alt[];
+
+// vgainit.c
+extern struct video_save_pointer_s video_save_pointer_table;
+extern struct video_param_s video_param_table[29];
+
+// vgabios.c
+extern int VgaBDF;
+extern int HaveRunInit;
+#define SET_VGA(var, val) SET_FARVAR(get_global_seg(), (var), (val))
+struct carattr {
+ u8 car, attr, use_attr, pad;
+};
+struct cursorpos {
+ u8 x, y, page, pad;
+};
+int vga_bpp(struct vgamode_s *vmode_g);
+u16 calc_page_size(u8 memmodel, u16 width, u16 height);
+u16 get_cursor_shape(void);
+struct cursorpos get_cursor_pos(u8 page);
+int bda_save_restore(int cmd, u16 seg, void *data);
+struct vgamode_s *get_current_mode(void);
+int vga_set_mode(int mode, int flags);
+extern struct video_func_static static_functionality;
+
+// vgafb.c
+void init_gfx_op(struct gfx_op *op, struct vgamode_s *vmode_g);
+void handle_gfx_op(struct gfx_op *op);
+void *text_address(struct cursorpos cp);
+void vgafb_move_chars(struct cursorpos dest
+ , struct cursorpos src, struct cursorpos movesize);
+void vgafb_clear_chars(struct cursorpos dest
+ , struct carattr ca, struct cursorpos movesize);
+void vgafb_write_char(struct cursorpos cp, struct carattr ca);
+struct carattr vgafb_read_char(struct cursorpos cp);
+void vgafb_write_pixel(u8 color, u16 x, u16 y);
+u8 vgafb_read_pixel(u16 x, u16 y);
+void vgafb_set_swcursor(int enable);
+
+// vbe.c
+extern u32 VBE_total_memory;
+extern u32 VBE_capabilities;
+extern u32 VBE_framebuffer;
+extern u16 VBE_win_granularity;
+#define VBE_OEM_STRING "SeaBIOS VBE(C) 2011"
+#define VBE_VENDOR_STRING "SeaBIOS Developers"
+#define VBE_PRODUCT_STRING "SeaBIOS VBE Adapter"
+#define VBE_REVISION_STRING "Rev. 1"
+struct bregs;
+void handle_104f(struct bregs *regs);
+
+#endif // vgabios.h
diff --git a/roms/seabios/vgasrc/vgaentry.S b/roms/seabios/vgasrc/vgaentry.S
new file mode 100644
index 00000000..d9ebdb93
--- /dev/null
+++ b/roms/seabios/vgasrc/vgaentry.S
@@ -0,0 +1,147 @@
+// Rom layout and bios assembler to C interface.
+//
+// Copyright (C) 2009-2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// 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_*
+
+
+/****************************************************************
+ * Rom Header
+ ****************************************************************/
+
+ .section .rom.header
+ .code16
+ .global _rom_header, _rom_header_size, _rom_header_checksum
+_rom_header:
+ .word 0xaa55
+_rom_header_size:
+ .byte 0
+_rom_header_entry:
+ jmp _optionrom_entry
+_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 points
+ ****************************************************************/
+
+ // This macro implements a call while avoiding instructions
+ // that old versions of x86emu have problems with.
+ .macro VGA_CALLL cfunc
+#if CONFIG_VGA_FIXUP_ASM
+ pushw %ax
+ callw \cfunc
+#else
+ calll \cfunc
+#endif
+ .endm
+
+ // This macro is the same as ENTRY_ARG except VGA_CALLL is used.
+ .macro ENTRY_ARG_VGA 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
+ VGA_CALLL \cfunc
+ movl %ebx, %esp // Restore %esp (including high bits)
+ POPBREGS
+ .endm
+
+ DECLFUNC entry_104f05
+entry_104f05:
+ ENTRY_ARG_VGA vbe_104f05
+ lretw
+
+ DECLFUNC _optionrom_entry
+_optionrom_entry:
+ ENTRY_ARG_VGA vga_post
+ lretw
+
+ DECLFUNC entry_10
+entry_10:
+ ENTRY_ARG_VGA handle_10
+ iretw
+
+ // Entry point using extra stack
+ DECLFUNC entry_10_extrastack
+entry_10_extrastack:
+ cli
+ cld
+ pushw %ds // Set %ds:%eax to space on ExtraStack
+ pushl %eax
+ movw %cs:ExtraStackSeg, %ds
+ movl $(CONFIG_VGA_EXTRA_STACK_SIZE-PUSHBREGS_size-16), %eax
+ SAVEBREGS_POP_DSEAX // Save registers on extra stack
+ 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
+ VGA_CALLL handle_10
+
+ 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
+
+ // Timer irq handling
+ DECLFUNC entry_timer_hook
+entry_timer_hook:
+ ENTRY handle_timer_hook
+ ljmpw *%cs:Timer_Hook_Resume
+
+ // Timer irq handling on extra stack
+ DECLFUNC entry_timer_hook_extrastack
+entry_timer_hook_extrastack:
+ cli
+ cld
+ pushw %ds // Set %ds:%eax to space on ExtraStack
+ pushl %eax
+ movw %cs:ExtraStackSeg, %ds
+ movl $(CONFIG_VGA_EXTRA_STACK_SIZE-PUSHBREGS_size-8), %eax
+ SAVEBREGS_POP_DSEAX
+ 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 handle_timer_hook
+
+ movl %esp, %eax // Restore registers and return
+ movw PUSHBREGS_size+4(%eax), %ss
+ movl PUSHBREGS_size(%eax), %esp
+ RESTOREBREGS_DSEAX
+ ljmpw *%cs:Timer_Hook_Resume
diff --git a/roms/seabios/vgasrc/vgafb.c b/roms/seabios/vgasrc/vgafb.c
new file mode 100644
index 00000000..1a94fcf7
--- /dev/null
+++ b/roms/seabios/vgasrc/vgafb.c
@@ -0,0 +1,702 @@
+// Code for manipulating VGA framebuffers.
+//
+// Copyright (C) 2009-2014 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_BDA
+#include "byteorder.h" // cpu_to_be16
+#include "output.h" // dprintf
+#include "stdvga.h" // stdvga_planar4_plane
+#include "string.h" // memset_far
+#include "vgabios.h" // vgafb_scroll
+#include "vgahw.h" // vgahw_get_linelength
+
+static inline void
+memmove_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
+{
+ if (src < dst) {
+ dst += stride * (lines - 1);
+ src += stride * (lines - 1);
+ stride = -stride;
+ }
+ for (; lines; lines--, dst+=stride, src+=stride)
+ memcpy_far(seg, dst, seg, src, copylen);
+}
+
+static inline void
+memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines)
+{
+ for (; lines; lines--, dst+=stride)
+ memset_far(seg, dst, val, setlen);
+}
+
+static inline void
+memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines)
+{
+ for (; lines; lines--, dst+=stride)
+ memset16_far(seg, dst, val, setlen);
+}
+
+
+/****************************************************************
+ * Basic stdvga graphic manipulation
+ ****************************************************************/
+
+static void
+gfx_planar(struct gfx_op *op)
+{
+ if (!CONFIG_VGA_STDVGA_PORTS)
+ return;
+ void *dest_far = (void*)(op->y * op->linelength + op->x / 8);
+ int plane;
+ switch (op->op) {
+ default:
+ case GO_READ8:
+ memset(op->pixels, 0, sizeof(op->pixels));
+ for (plane = 0; plane < 4; plane++) {
+ stdvga_planar4_plane(plane);
+ u8 data = GET_FARVAR(SEG_GRAPH, *(u8*)dest_far);
+ int pixel;
+ for (pixel=0; pixel<8; pixel++)
+ op->pixels[pixel] |= ((data>>(7-pixel)) & 1) << plane;
+ }
+ break;
+ case GO_WRITE8:
+ for (plane = 0; plane<4; plane++) {
+ stdvga_planar4_plane(plane);
+ u8 data = 0;
+ int pixel;
+ for (pixel=0; pixel<8; pixel++)
+ data |= ((op->pixels[pixel]>>plane) & 1) << (7-pixel);
+ SET_FARVAR(SEG_GRAPH, *(u8*)dest_far, data);
+ }
+ break;
+ case GO_MEMSET:
+ for (plane = 0; plane < 4; plane++) {
+ stdvga_planar4_plane(plane);
+ u8 data = (op->pixels[0] & (1<<plane)) ? 0xff : 0x00;
+ memset_stride(SEG_GRAPH, dest_far, data
+ , op->xlen / 8, op->linelength, op->ylen);
+ }
+ break;
+ case GO_MEMMOVE: ;
+ void *src_far = (void*)(op->srcy * op->linelength + op->x / 8);
+ for (plane = 0; plane < 4; plane++) {
+ stdvga_planar4_plane(plane);
+ memmove_stride(SEG_GRAPH, dest_far, src_far
+ , op->xlen / 8, op->linelength, op->ylen);
+ }
+ break;
+ }
+ stdvga_planar4_plane(-1);
+}
+
+static void
+gfx_cga(struct gfx_op *op)
+{
+ int bpp = GET_GLOBAL(op->vmode_g->depth);
+ void *dest_far = (void*)(op->y / 2 * op->linelength + op->x / 8 * bpp);
+ switch (op->op) {
+ default:
+ case GO_READ8:
+ if (op->y & 1)
+ dest_far += 0x2000;
+ if (bpp == 1) {
+ u8 data = GET_FARVAR(SEG_CTEXT, *(u8*)dest_far);
+ int pixel;
+ for (pixel=0; pixel<8; pixel++)
+ op->pixels[pixel] = (data >> (7-pixel)) & 1;
+ } else {
+ u16 data = GET_FARVAR(SEG_CTEXT, *(u16*)dest_far);
+ data = be16_to_cpu(data);
+ int pixel;
+ for (pixel=0; pixel<8; pixel++)
+ op->pixels[pixel] = (data >> ((7-pixel)*2)) & 3;
+ }
+ break;
+ case GO_WRITE8:
+ if (op->y & 1)
+ dest_far += 0x2000;
+ if (bpp == 1) {
+ u8 data = 0;
+ int pixel;
+ for (pixel=0; pixel<8; pixel++)
+ data |= (op->pixels[pixel] & 1) << (7-pixel);
+ SET_FARVAR(SEG_CTEXT, *(u8*)dest_far, data);
+ } else {
+ u16 data = 0;
+ int pixel;
+ for (pixel=0; pixel<8; pixel++)
+ data |= (op->pixels[pixel] & 3) << ((7-pixel) * 2);
+ data = cpu_to_be16(data);
+ SET_FARVAR(SEG_CTEXT, *(u16*)dest_far, data);
+ }
+ break;
+ case GO_MEMSET: ;
+ u8 data = op->pixels[0];
+ if (bpp == 1)
+ data = (data&1) | ((data&1)<<1);
+ data &= 3;
+ data |= (data<<2) | (data<<4) | (data<<6);
+ memset_stride(SEG_CTEXT, dest_far, data
+ , op->xlen / 8 * bpp, op->linelength, op->ylen / 2);
+ memset_stride(SEG_CTEXT, dest_far + 0x2000, data
+ , op->xlen / 8 * bpp, op->linelength, op->ylen / 2);
+ break;
+ case GO_MEMMOVE: ;
+ void *src_far = (void*)(op->srcy / 2 * op->linelength + op->x / 8 * bpp);
+ memmove_stride(SEG_CTEXT, dest_far, src_far
+ , op->xlen / 8 * bpp, op->linelength, op->ylen / 2);
+ memmove_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000
+ , op->xlen / 8 * bpp, op->linelength, op->ylen / 2);
+ break;
+ }
+}
+
+static void
+gfx_packed(struct gfx_op *op)
+{
+ void *dest_far = (void*)(op->y * op->linelength + op->x);
+ switch (op->op) {
+ default:
+ case GO_READ8:
+ memcpy_far(GET_SEG(SS), op->pixels, SEG_GRAPH, dest_far, 8);
+ break;
+ case GO_WRITE8:
+ memcpy_far(SEG_GRAPH, dest_far, GET_SEG(SS), op->pixels, 8);
+ break;
+ case GO_MEMSET:
+ memset_stride(SEG_GRAPH, dest_far, op->pixels[0]
+ , op->xlen, op->linelength, op->ylen);
+ break;
+ case GO_MEMMOVE: ;
+ void *src_far = (void*)(op->srcy * op->linelength + op->x);
+ memmove_stride(SEG_GRAPH, dest_far, src_far
+ , op->xlen, op->linelength, op->ylen);
+ break;
+ }
+}
+
+
+/****************************************************************
+ * Direct framebuffers in high mem
+ ****************************************************************/
+
+// Use int 1587 call to copy memory to/from the framebuffer.
+static void
+memcpy_high(void *dest, void *src, u32 len)
+{
+ u64 gdt[6];
+ gdt[2] = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE((u32)src);
+ gdt[3] = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE((u32)dest);
+
+ // Call int 1587 to copy data.
+ len/=2;
+ u32 flags;
+ u32 eax = 0x8700;
+ u32 si = (u32)&gdt;
+ SET_SEG(ES, GET_SEG(SS));
+ asm volatile(
+ "stc\n"
+ "int $0x15\n"
+ "cli\n"
+ "cld\n"
+ "pushfl\n"
+ "popl %0\n"
+ : "=r" (flags), "+a" (eax), "+S" (si), "+c" (len)
+ : : "cc", "memory");
+}
+
+static void
+memmove_stride_high(void *dst, void *src, int copylen, int stride, int lines)
+{
+ if (src < dst) {
+ dst += stride * (lines - 1);
+ src += stride * (lines - 1);
+ stride = -stride;
+ }
+ for (; lines; lines--, dst+=stride, src+=stride)
+ memcpy_high(dst, src, copylen);
+}
+
+// Map a CGA color to a "direct" mode rgb value.
+static u32
+get_color(int depth, u8 attr)
+{
+ int rbits, gbits, bbits;
+ switch (depth) {
+ case 15: rbits=5; gbits=5; bbits=5; break;
+ case 16: rbits=5; gbits=6; bbits=5; break;
+ default:
+ case 24: rbits=8; gbits=8; bbits=8; break;
+ }
+ int h = (attr&8) ? 1 : 0;
+ int r = (attr&4) ? 2 : 0, g = (attr&2) ? 2 : 0, b = (attr&1) ? 2 : 0;
+ if ((attr & 0xf) == 6)
+ g = 1;
+ int rv = DIV_ROUND_CLOSEST(((1<<rbits) - 1) * (r + h), 3);
+ int gv = DIV_ROUND_CLOSEST(((1<<gbits) - 1) * (g + h), 3);
+ int bv = DIV_ROUND_CLOSEST(((1<<bbits) - 1) * (b + h), 3);
+ return (rv << (gbits+bbits)) + (gv << bbits) + bv;
+}
+
+// Find the closest attribute for a given framebuffer color
+static u8
+reverse_color(int depth, u32 color)
+{
+ int rbits, gbits, bbits;
+ switch (depth) {
+ case 15: rbits=5; gbits=5; bbits=5; break;
+ case 16: rbits=5; gbits=6; bbits=5; break;
+ default:
+ case 24: rbits=8; gbits=8; bbits=8; break;
+ }
+ int rv = (color >> (gbits+bbits)) & ((1<<rbits)-1);
+ int gv = (color >> bbits) & ((1<<gbits)-1);
+ int bv = color & ((1<<bbits)-1);
+ int r = DIV_ROUND_CLOSEST(rv * 3, (1<<rbits) - 1);
+ int g = DIV_ROUND_CLOSEST(gv * 3, (1<<gbits) - 1);
+ int b = DIV_ROUND_CLOSEST(bv * 3, (1<<bbits) - 1);
+ int h = r && g && b && (r != 2 || g != 2 || b != 2);
+ return (h ? 8 : 0) | ((r-h) ? 4 : 0) | ((g-h) ? 2 : 0) | ((b-h) ? 1 : 0);
+}
+
+static void
+gfx_direct(struct gfx_op *op)
+{
+ void *fb = (void*)GET_GLOBAL(VBE_framebuffer);
+ if (!fb)
+ return;
+ int depth = GET_GLOBAL(op->vmode_g->depth);
+ int bypp = DIV_ROUND_UP(depth, 8);
+ void *dest_far = (fb + op->displaystart + op->y * op->linelength
+ + op->x * bypp);
+ switch (op->op) {
+ default:
+ case GO_READ8: {
+ u8 data[64];
+ memcpy_high(MAKE_FLATPTR(GET_SEG(SS), data), dest_far, bypp * 8);
+ int i;
+ for (i=0; i<8; i++)
+ op->pixels[i] = reverse_color(depth, *(u32*)&data[i*bypp]);
+ break;
+ }
+ case GO_WRITE8: {
+ u8 data[64];
+ int i;
+ for (i=0; i<8; i++)
+ *(u32*)&data[i*bypp] = get_color(depth, op->pixels[i]);
+ memcpy_high(dest_far, MAKE_FLATPTR(GET_SEG(SS), data), bypp * 8);
+ break;
+ }
+ case GO_MEMSET: {
+ u32 color = get_color(depth, op->pixels[0]);
+ u8 data[64];
+ int i;
+ for (i=0; i<8; i++)
+ *(u32*)&data[i*bypp] = color;
+ memcpy_high(dest_far, MAKE_FLATPTR(GET_SEG(SS), data), bypp * 8);
+ memcpy_high(dest_far + bypp * 8, dest_far, op->xlen * bypp - bypp * 8);
+ for (i=1; i < op->ylen; i++)
+ memcpy_high(dest_far + op->linelength * i
+ , dest_far, op->xlen * bypp);
+ break;
+ }
+ case GO_MEMMOVE: ;
+ void *src_far = (fb + op->displaystart + op->srcy * op->linelength
+ + op->x * bypp);
+ memmove_stride_high(dest_far, src_far
+ , op->xlen * bypp, op->linelength, op->ylen);
+ break;
+ }
+}
+
+
+/****************************************************************
+ * Gfx interface
+ ****************************************************************/
+
+// Prepare a struct gfx_op for use.
+void
+init_gfx_op(struct gfx_op *op, struct vgamode_s *vmode_g)
+{
+ memset(op, 0, sizeof(*op));
+ op->vmode_g = vmode_g;
+ op->linelength = vgahw_get_linelength(vmode_g);
+ op->displaystart = vgahw_get_displaystart(vmode_g);
+}
+
+// Issue a graphics operation.
+void
+handle_gfx_op(struct gfx_op *op)
+{
+ switch (GET_GLOBAL(op->vmode_g->memmodel)) {
+ case MM_PLANAR:
+ gfx_planar(op);
+ break;
+ case MM_CGA:
+ gfx_cga(op);
+ break;
+ case MM_PACKED:
+ gfx_packed(op);
+ break;
+ case MM_DIRECT:
+ gfx_direct(op);
+ break;
+ default:
+ break;
+ }
+}
+
+// Move characters when in graphics mode.
+static void
+gfx_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+ , struct cursorpos src, struct cursorpos movesize)
+{
+ struct gfx_op op;
+ init_gfx_op(&op, vmode_g);
+ op.x = dest.x * 8;
+ op.xlen = movesize.x * 8;
+ int cheight = GET_BDA(char_height);
+ op.y = dest.y * cheight;
+ op.ylen = movesize.y * cheight;
+ op.srcy = src.y * cheight;
+ op.op = GO_MEMMOVE;
+ handle_gfx_op(&op);
+}
+
+// Clear area of screen in graphics mode.
+static void
+gfx_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest
+ , struct carattr ca, struct cursorpos clearsize)
+{
+ struct gfx_op op;
+ init_gfx_op(&op, vmode_g);
+ op.x = dest.x * 8;
+ op.xlen = clearsize.x * 8;
+ int cheight = GET_BDA(char_height);
+ op.y = dest.y * cheight;
+ op.ylen = clearsize.y * cheight;
+ op.pixels[0] = ca.attr;
+ if (vga_emulate_text())
+ op.pixels[0] = ca.attr >> 4;
+ op.op = GO_MEMSET;
+ handle_gfx_op(&op);
+}
+
+// Return the font for a given character
+struct segoff_s
+get_font_data(u8 c)
+{
+ int char_height = GET_BDA(char_height);
+ struct segoff_s font;
+ if (char_height == 8 && c >= 128) {
+ font = GET_IVT(0x1f);
+ c -= 128;
+ } else {
+ font = GET_IVT(0x43);
+ }
+ font.offset += c * char_height;
+ return font;
+}
+
+// Write a character to the screen in graphics mode.
+static void
+gfx_write_char(struct vgamode_s *vmode_g
+ , struct cursorpos cp, struct carattr ca)
+{
+ if (cp.x >= GET_BDA(video_cols))
+ return;
+
+ struct segoff_s font = get_font_data(ca.car);
+ struct gfx_op op;
+ init_gfx_op(&op, vmode_g);
+ op.x = cp.x * 8;
+ int cheight = GET_BDA(char_height);
+ op.y = cp.y * cheight;
+ u8 fgattr = ca.attr, bgattr = 0x00;
+ int usexor = 0;
+ if (vga_emulate_text()) {
+ if (ca.use_attr) {
+ bgattr = fgattr >> 4;
+ fgattr = fgattr & 0x0f;
+ } else {
+ // Read bottom right pixel of the cell to guess bg color
+ op.op = GO_READ8;
+ op.y += cheight-1;
+ handle_gfx_op(&op);
+ op.y -= cheight-1;
+ bgattr = op.pixels[7];
+ fgattr = bgattr ^ 0x7;
+ }
+ } else if (fgattr & 0x80 && GET_GLOBAL(vmode_g->depth) < 8) {
+ usexor = 1;
+ fgattr &= 0x7f;
+ }
+ int i;
+ for (i = 0; i < cheight; i++, op.y++) {
+ u8 fontline = GET_FARVAR(font.seg, *(u8*)(font.offset+i));
+ if (usexor) {
+ op.op = GO_READ8;
+ handle_gfx_op(&op);
+ int j;
+ for (j = 0; j < 8; j++)
+ op.pixels[j] ^= (fontline & (0x80>>j)) ? fgattr : 0x00;
+ } else {
+ int j;
+ for (j = 0; j < 8; j++)
+ op.pixels[j] = (fontline & (0x80>>j)) ? fgattr : bgattr;
+ }
+ op.op = GO_WRITE8;
+ handle_gfx_op(&op);
+ }
+}
+
+// Read a character from the screen in graphics mode.
+static struct carattr
+gfx_read_char(struct vgamode_s *vmode_g, struct cursorpos cp)
+{
+ u8 lines[16];
+ int cheight = GET_BDA(char_height);
+ if (cp.x >= GET_BDA(video_cols) || cheight > ARRAY_SIZE(lines))
+ goto fail;
+
+ // Read cell from screen
+ struct gfx_op op;
+ init_gfx_op(&op, vmode_g);
+ op.op = GO_READ8;
+ op.x = cp.x * 8;
+ op.y = cp.y * cheight;
+ int car = 0;
+ u8 fgattr = 0x00, bgattr = 0x00;
+ if (vga_emulate_text()) {
+ // Read bottom right pixel of the cell to guess bg color
+ op.y += cheight-1;
+ handle_gfx_op(&op);
+ op.y -= cheight-1;
+ bgattr = op.pixels[7];
+ fgattr = bgattr ^ 0x7;
+ // Report space character for blank cells (skip null character check)
+ car = 1;
+ }
+ u8 i, j;
+ for (i=0; i<cheight; i++, op.y++) {
+ u8 line = 0;
+ handle_gfx_op(&op);
+ for (j=0; j<8; j++)
+ if (op.pixels[j] != bgattr) {
+ line |= 0x80 >> j;
+ fgattr = op.pixels[j];
+ }
+ lines[i] = line;
+ }
+
+ // Determine font
+ for (; car<256; car++) {
+ struct segoff_s font = get_font_data(car);
+ if (memcmp_far(GET_SEG(SS), lines
+ , font.seg, (void*)(font.offset+0), cheight) == 0)
+ return (struct carattr){car, fgattr | (bgattr << 4), 0};
+ }
+fail:
+ return (struct carattr){0, 0, 0};
+}
+
+// Draw/undraw a cursor on the framebuffer by xor'ing the cursor cell
+void
+gfx_set_swcursor(struct vgamode_s *vmode_g, int enable, struct cursorpos cp)
+{
+ u16 cursor_type = get_cursor_shape();
+ u8 start = cursor_type >> 8, end = cursor_type & 0xff;
+ struct gfx_op op;
+ init_gfx_op(&op, vmode_g);
+ op.x = cp.x * 8;
+ int cheight = GET_BDA(char_height);
+ op.y = cp.y * cheight + start;
+
+ int i;
+ for (i = start; i < cheight && i <= end; i++, op.y++) {
+ op.op = GO_READ8;
+ handle_gfx_op(&op);
+ int j;
+ for (j = 0; j < 8; j++)
+ op.pixels[j] ^= 0x07;
+ op.op = GO_WRITE8;
+ handle_gfx_op(&op);
+ }
+}
+
+// Set the pixel at the given position.
+void
+vgafb_write_pixel(u8 color, u16 x, u16 y)
+{
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (!vmode_g)
+ return;
+ vgafb_set_swcursor(0);
+
+ struct gfx_op op;
+ init_gfx_op(&op, vmode_g);
+ op.x = ALIGN_DOWN(x, 8);
+ op.y = y;
+ op.op = GO_READ8;
+ handle_gfx_op(&op);
+
+ int usexor = color & 0x80 && GET_GLOBAL(vmode_g->depth) < 8;
+ if (usexor)
+ op.pixels[x & 0x07] ^= color & 0x7f;
+ else
+ op.pixels[x & 0x07] = color;
+ op.op = GO_WRITE8;
+ handle_gfx_op(&op);
+}
+
+// Return the pixel at the given position.
+u8
+vgafb_read_pixel(u16 x, u16 y)
+{
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (!vmode_g)
+ return 0;
+ vgafb_set_swcursor(0);
+
+ struct gfx_op op;
+ init_gfx_op(&op, vmode_g);
+ op.x = ALIGN_DOWN(x, 8);
+ op.y = y;
+ op.op = GO_READ8;
+ handle_gfx_op(&op);
+
+ return op.pixels[x & 0x07];
+}
+
+
+/****************************************************************
+ * Text ops
+ ****************************************************************/
+
+// Return the fb offset for the given character address when in text mode.
+void *
+text_address(struct cursorpos cp)
+{
+ int stride = GET_BDA(video_cols) * 2;
+ u32 pageoffset = GET_BDA(video_pagesize) * cp.page;
+ return (void*)pageoffset + cp.y * stride + cp.x * 2;
+}
+
+// Move characters on screen.
+void
+vgafb_move_chars(struct cursorpos dest
+ , struct cursorpos src, struct cursorpos movesize)
+{
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (!vmode_g)
+ return;
+ vgafb_set_swcursor(0);
+
+ if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
+ gfx_move_chars(vmode_g, dest, src, movesize);
+ return;
+ }
+
+ int stride = GET_BDA(video_cols) * 2;
+ memmove_stride(GET_GLOBAL(vmode_g->sstart)
+ , text_address(dest), text_address(src)
+ , movesize.x * 2, stride, movesize.y);
+}
+
+// Clear area of screen.
+void
+vgafb_clear_chars(struct cursorpos dest
+ , struct carattr ca, struct cursorpos clearsize)
+{
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (!vmode_g)
+ return;
+ vgafb_set_swcursor(0);
+
+ if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
+ gfx_clear_chars(vmode_g, dest, ca, clearsize);
+ return;
+ }
+
+ int stride = GET_BDA(video_cols) * 2;
+ u16 attr = ((ca.use_attr ? ca.attr : 0x07) << 8) | ca.car;
+ memset16_stride(GET_GLOBAL(vmode_g->sstart), text_address(dest), attr
+ , clearsize.x * 2, stride, clearsize.y);
+}
+
+// Write a character to the screen.
+void
+vgafb_write_char(struct cursorpos cp, struct carattr ca)
+{
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (!vmode_g)
+ return;
+ vgafb_set_swcursor(0);
+
+ if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
+ gfx_write_char(vmode_g, cp, ca);
+ return;
+ }
+
+ void *dest_far = text_address(cp);
+ if (ca.use_attr) {
+ u16 dummy = (ca.attr << 8) | ca.car;
+ SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)dest_far, dummy);
+ } else {
+ SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)dest_far, ca.car);
+ }
+}
+
+// Return the character at the given position on the screen.
+struct carattr
+vgafb_read_char(struct cursorpos cp)
+{
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (!vmode_g)
+ return (struct carattr){0, 0, 0};
+ vgafb_set_swcursor(0);
+
+ if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT)
+ return gfx_read_char(vmode_g, cp);
+
+ u16 *dest_far = text_address(cp);
+ u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *dest_far);
+ return (struct carattr){v, v>>8, 0};
+}
+
+// Draw/undraw a cursor on the screen
+void
+vgafb_set_swcursor(int enable)
+{
+ if (!vga_emulate_text())
+ return;
+ u8 flags = GET_BDA_EXT(flags);
+ if (!!(flags & BF_SWCURSOR) == enable)
+ // Already in requested mode.
+ return;
+ struct vgamode_s *vmode_g = get_current_mode();
+ if (!vmode_g)
+ return;
+ struct cursorpos cp = get_cursor_pos(0xff);
+ if (cp.x >= GET_BDA(video_cols) || cp.y > GET_BDA(video_rows)
+ || GET_BDA(cursor_type) >= 0x2000)
+ // Cursor not visible
+ return;
+
+ SET_BDA_EXT(flags, (flags & ~BF_SWCURSOR) | (enable ? BF_SWCURSOR : 0));
+
+ if (GET_GLOBAL(vmode_g->memmodel) != MM_TEXT) {
+ gfx_set_swcursor(vmode_g, enable, cp);
+ return;
+ }
+
+ // In text mode, swap foreground and background attributes for cursor
+ void *dest_far = text_address(cp) + 1;
+ u8 attr = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)dest_far);
+ attr = (attr >> 4) | (attr << 4);
+ SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)dest_far, attr);
+}
diff --git a/roms/seabios/vgasrc/vgafonts.c b/roms/seabios/vgasrc/vgafonts.c
new file mode 100644
index 00000000..47a6437f
--- /dev/null
+++ b/roms/seabios/vgasrc/vgafonts.c
@@ -0,0 +1,785 @@
+#include "vgabios.h" // vgafont8
+
+/*
+ * These fonts come from ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+ * The package is (c) by Joseph Gil
+ * The individual fonts are public domain
+ */
+u8 vgafont8[256 * 8] VAR16 = {
+ 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,
+ 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00,
+ 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38,
+ 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
+ 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
+ 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00,
+ 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00,
+ 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00,
+ 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00,
+ 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00,
+ 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00,
+ 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18,
+ 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00,
+ 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30,
+ 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7,
+ 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
+ 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00,
+ 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
+ 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00,
+ 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f,
+ 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03,
+ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00,
+ 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00,
+ 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0,
+ 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00,
+ 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00,
+ 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00,
+ 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0,
+ 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
+ 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00,
+ 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00,
+ 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0,
+ 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00,
+ 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00,
+ 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00,
+ 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00,
+ 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
+ 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c,
+ 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+u8 vgafont14[256 * 14] VAR16 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x66, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x6c, 0x6c, 0x78, 0x6c, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x7c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x8c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x70, 0x1c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0xc6, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0x40, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+u8 vgafont16[256 * 16] VAR16 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+u8 vgafont14alt[1] VAR16;
+u8 vgafont16alt[1] VAR16;
diff --git a/roms/seabios/vgasrc/vgahw.h b/roms/seabios/vgasrc/vgahw.h
new file mode 100644
index 00000000..39f818ab
--- /dev/null
+++ b/roms/seabios/vgasrc/vgahw.h
@@ -0,0 +1,143 @@
+#ifndef __VGAHW_H
+#define __VGAHW_H
+
+#include "types.h" // u8
+#include "config.h" // CONFIG_*
+
+#include "cbvga.h" // cbvga_setup
+#include "clext.h" // clext_set_mode
+#include "bochsvga.h" // bochsvga_set_mode
+#include "stdvga.h" // stdvga_set_mode
+#include "geodevga.h" // geodevga_setup
+
+static inline struct vgamode_s *vgahw_find_mode(int mode) {
+ if (CONFIG_VGA_CIRRUS)
+ return clext_find_mode(mode);
+ if (CONFIG_VGA_BOCHS)
+ return bochsvga_find_mode(mode);
+ if (CONFIG_VGA_COREBOOT)
+ return cbvga_find_mode(mode);
+ return stdvga_find_mode(mode);
+}
+
+static inline int vgahw_set_mode(struct vgamode_s *vmode_g, int flags) {
+ if (CONFIG_VGA_CIRRUS)
+ return clext_set_mode(vmode_g, flags);
+ if (CONFIG_VGA_BOCHS)
+ return bochsvga_set_mode(vmode_g, flags);
+ if (CONFIG_VGA_COREBOOT)
+ return cbvga_set_mode(vmode_g, flags);
+ return stdvga_set_mode(vmode_g, flags);
+}
+
+static inline void vgahw_list_modes(u16 seg, u16 *dest, u16 *last) {
+ if (CONFIG_VGA_CIRRUS)
+ clext_list_modes(seg, dest, last);
+ else if (CONFIG_VGA_BOCHS)
+ bochsvga_list_modes(seg, dest, last);
+ else if (CONFIG_VGA_COREBOOT)
+ cbvga_list_modes(seg, dest, last);
+ else
+ stdvga_list_modes(seg, dest, last);
+}
+
+static inline int vgahw_setup(void) {
+ if (CONFIG_VGA_CIRRUS)
+ return clext_setup();
+ if (CONFIG_VGA_BOCHS)
+ return bochsvga_setup();
+ if (CONFIG_VGA_GEODEGX2 || CONFIG_VGA_GEODELX)
+ return geodevga_setup();
+ if (CONFIG_VGA_COREBOOT)
+ return cbvga_setup();
+ return stdvga_setup();
+}
+
+static inline int vgahw_get_window(struct vgamode_s *vmode_g, int window) {
+ if (CONFIG_VGA_CIRRUS)
+ return clext_get_window(vmode_g, window);
+ if (CONFIG_VGA_BOCHS)
+ return bochsvga_get_window(vmode_g, window);
+ if (CONFIG_VGA_COREBOOT)
+ return cbvga_get_window(vmode_g, window);
+ return stdvga_get_window(vmode_g, window);
+}
+
+static inline int vgahw_set_window(struct vgamode_s *vmode_g, int window
+ , int val) {
+ if (CONFIG_VGA_CIRRUS)
+ return clext_set_window(vmode_g, window, val);
+ if (CONFIG_VGA_BOCHS)
+ return bochsvga_set_window(vmode_g, window, val);
+ if (CONFIG_VGA_COREBOOT)
+ return cbvga_set_window(vmode_g, window, val);
+ return stdvga_set_window(vmode_g, window, val);
+}
+
+static inline int vgahw_get_linelength(struct vgamode_s *vmode_g) {
+ if (CONFIG_VGA_CIRRUS)
+ return clext_get_linelength(vmode_g);
+ if (CONFIG_VGA_BOCHS)
+ return bochsvga_get_linelength(vmode_g);
+ if (CONFIG_VGA_COREBOOT)
+ return cbvga_get_linelength(vmode_g);
+ return stdvga_get_linelength(vmode_g);
+}
+
+static inline int vgahw_set_linelength(struct vgamode_s *vmode_g, int val) {
+ if (CONFIG_VGA_CIRRUS)
+ return clext_set_linelength(vmode_g, val);
+ if (CONFIG_VGA_BOCHS)
+ return bochsvga_set_linelength(vmode_g, val);
+ if (CONFIG_VGA_COREBOOT)
+ return cbvga_set_linelength(vmode_g, val);
+ return stdvga_set_linelength(vmode_g, val);
+}
+
+static inline int vgahw_get_displaystart(struct vgamode_s *vmode_g) {
+ if (CONFIG_VGA_CIRRUS)
+ return clext_get_displaystart(vmode_g);
+ if (CONFIG_VGA_BOCHS)
+ return bochsvga_get_displaystart(vmode_g);
+ if (CONFIG_VGA_COREBOOT)
+ return cbvga_get_displaystart(vmode_g);
+ return stdvga_get_displaystart(vmode_g);
+}
+
+static inline int vgahw_set_displaystart(struct vgamode_s *vmode_g, int val) {
+ if (CONFIG_VGA_CIRRUS)
+ return clext_set_displaystart(vmode_g, val);
+ if (CONFIG_VGA_BOCHS)
+ return bochsvga_set_displaystart(vmode_g, val);
+ if (CONFIG_VGA_COREBOOT)
+ return cbvga_set_displaystart(vmode_g, val);
+ return stdvga_set_displaystart(vmode_g, val);
+}
+
+static inline int vgahw_get_dacformat(struct vgamode_s *vmode_g) {
+ if (CONFIG_VGA_BOCHS)
+ return bochsvga_get_dacformat(vmode_g);
+ if (CONFIG_VGA_COREBOOT)
+ return cbvga_get_dacformat(vmode_g);
+ return stdvga_get_dacformat(vmode_g);
+}
+
+static inline int vgahw_set_dacformat(struct vgamode_s *vmode_g, int val) {
+ if (CONFIG_VGA_BOCHS)
+ return bochsvga_set_dacformat(vmode_g, val);
+ if (CONFIG_VGA_COREBOOT)
+ return cbvga_set_dacformat(vmode_g, val);
+ return stdvga_set_dacformat(vmode_g, val);
+}
+
+static inline int vgahw_save_restore(int cmd, u16 seg, void *data) {
+ if (CONFIG_VGA_CIRRUS)
+ return clext_save_restore(cmd, seg, data);
+ if (CONFIG_VGA_BOCHS)
+ return bochsvga_save_restore(cmd, seg, data);
+ if (CONFIG_VGA_COREBOOT)
+ return cbvga_save_restore(cmd, seg, data);
+ return stdvga_save_restore(cmd, seg, data);
+}
+
+#endif // vgahw.h
diff --git a/roms/seabios/vgasrc/vgainit.c b/roms/seabios/vgasrc/vgainit.c
new file mode 100644
index 00000000..8d122618
--- /dev/null
+++ b/roms/seabios/vgasrc/vgainit.c
@@ -0,0 +1,195 @@
+// Main VGA bios initialization
+//
+// Copyright (C) 2009-2013 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// 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/pci.h" // pci_config_readw
+#include "hw/pci_regs.h" // PCI_VENDOR_ID
+#include "hw/serialio.h" // serial_debug_preinit
+#include "output.h" // dprintf
+#include "std/optionrom.h" // struct pci_data
+#include "std/pmm.h" // struct pmmheader
+#include "string.h" // checksum_far
+#include "util.h" // VERSION
+#include "vgabios.h" // video_save_pointer_table
+#include "vgahw.h" // vgahw_setup
+
+struct video_save_pointer_s video_save_pointer_table VAR16;
+
+struct video_param_s video_param_table[29] VAR16;
+
+// Type of emulator platform - for dprintf with certain compile options.
+int PlatformRunningOn VAR16;
+
+
+/****************************************************************
+ * PCI Data
+ ****************************************************************/
+
+struct pci_data rom_pci_data VAR16 VISIBLE16 = {
+ .signature = PCI_ROM_SIGNATURE,
+ .vendor = CONFIG_VGA_VID,
+ .device = CONFIG_VGA_DID,
+ .dlen = 0x18,
+ .class_hi = 0x300,
+ .irevision = 1,
+ .type = PCIROM_CODETYPE_X86,
+ .indicator = 0x80,
+};
+
+
+/****************************************************************
+ * PMM call and extra stack setup
+ ****************************************************************/
+
+u16 ExtraStackSeg VAR16 VISIBLE16;
+
+static void
+allocate_extra_stack(void)
+{
+ if (!CONFIG_VGA_ALLOCATE_EXTRA_STACK)
+ return;
+ u32 pmmscan;
+ for (pmmscan=0; pmmscan < BUILD_BIOS_SIZE; pmmscan+=16) {
+ struct pmmheader *pmm = (void*)pmmscan;
+ if (GET_FARVAR(SEG_BIOS, pmm->signature) != PMM_SIGNATURE)
+ continue;
+ if (checksum_far(SEG_BIOS, pmm, GET_FARVAR(SEG_BIOS, pmm->length)))
+ continue;
+ struct segoff_s entry = GET_FARVAR(SEG_BIOS, pmm->entry);
+ dprintf(1, "Attempting to allocate VGA stack via pmm call to %04x:%04x\n"
+ , entry.seg, entry.offset);
+ u16 res1, res2;
+ asm volatile(
+ "pushl %0\n"
+ "pushw $(8|1)\n" // Permanent low memory request
+ "pushl $0xffffffff\n" // Anonymous handle
+ "pushl $" __stringify(CONFIG_VGA_EXTRA_STACK_SIZE/16) "\n"
+ "pushw $0x00\n" // PMM allocation request
+ "lcallw *12(%%esp)\n"
+ "addl $16, %%esp\n"
+ "cli\n"
+ "cld\n"
+ : "+r" (entry.segoff), "=a" (res1), "=d" (res2) : : "cc", "memory");
+ u32 res = res1 | (res2 << 16);
+ if (!res || res == PMM_FUNCTION_NOT_SUPPORTED)
+ return;
+ dprintf(1, "VGA stack allocated at %x\n", res);
+ SET_VGA(ExtraStackSeg, res >> 4);
+ extern void entry_10_extrastack(void);
+ SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10_extrastack));
+ return;
+ }
+}
+
+
+/****************************************************************
+ * Timer hook
+ ****************************************************************/
+
+struct segoff_s Timer_Hook_Resume VAR16 VISIBLE16;
+
+void VISIBLE16
+handle_timer_hook(void)
+{
+ if (!vga_emulate_text())
+ return;
+ vgafb_set_swcursor(GET_BDA(timer_counter) % 18 < 9);
+}
+
+static void
+hook_timer_irq(void)
+{
+ if (!CONFIG_VGA_EMULATE_TEXT)
+ return;
+ extern void entry_timer_hook(void);
+ extern void entry_timer_hook_extrastack(void);
+ struct segoff_s oldirq = GET_IVT(0x08);
+ struct segoff_s newirq = SEGOFF(get_global_seg(), (u32)entry_timer_hook);
+ if (CONFIG_VGA_ALLOCATE_EXTRA_STACK && GET_GLOBAL(ExtraStackSeg))
+ newirq = SEGOFF(get_global_seg(), (u32)entry_timer_hook_extrastack);
+ dprintf(1, "Hooking hardware timer irq (old=%x new=%x)\n"
+ , oldirq.segoff, newirq.segoff);
+ SET_VGA(Timer_Hook_Resume, oldirq);
+ SET_IVT(0x08, newirq);
+}
+
+
+/****************************************************************
+ * VGA post
+ ****************************************************************/
+
+static void
+init_bios_area(void)
+{
+ // init detected hardware BIOS Area
+ // set 80x25 color (not clear from RBIL but usual)
+ set_equipment_flags(0x30, 0x20);
+
+ // Set the basic modeset options
+ SET_BDA(modeset_ctl, 0x51);
+
+ SET_BDA(dcc_index, CONFIG_VGA_STDVGA_PORTS ? 0x08 : 0xff);
+ SET_BDA(video_savetable
+ , SEGOFF(get_global_seg(), (u32)&video_save_pointer_table));
+
+ // FIXME
+ SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
+ SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
+}
+
+int VgaBDF VAR16 = -1;
+int HaveRunInit VAR16;
+
+void VISIBLE16
+vga_post(struct bregs *regs)
+{
+ serial_debug_preinit();
+ dprintf(1, "Start SeaVGABIOS (version %s)\n", VERSION);
+ debug_enter(regs, DEBUG_VGA_POST);
+
+ if (CONFIG_VGA_PCI && !GET_GLOBAL(HaveRunInit)) {
+ u16 bdf = regs->ax;
+ if ((pci_config_readw(bdf, PCI_VENDOR_ID)
+ == GET_GLOBAL(rom_pci_data.vendor))
+ && (pci_config_readw(bdf, PCI_DEVICE_ID)
+ == GET_GLOBAL(rom_pci_data.device)))
+ SET_VGA(VgaBDF, bdf);
+ }
+
+ int ret = vgahw_setup();
+ if (ret) {
+ dprintf(1, "Failed to initialize VGA hardware. Exiting.\n");
+ return;
+ }
+
+ if (GET_GLOBAL(HaveRunInit))
+ return;
+
+ init_bios_area();
+
+ SET_VGA(video_save_pointer_table.videoparam
+ , SEGOFF(get_global_seg(), (u32)video_param_table));
+ if (CONFIG_VGA_STDVGA_PORTS)
+ stdvga_build_video_param();
+
+ extern void entry_10(void);
+ SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10));
+
+ allocate_extra_stack();
+
+ hook_timer_irq();
+
+ SET_VGA(HaveRunInit, 1);
+
+ // Fixup checksum
+ extern u8 _rom_header_size, _rom_header_checksum;
+ SET_VGA(_rom_header_checksum, 0);
+ u8 sum = -checksum_far(get_global_seg(), 0,
+ GET_GLOBAL(_rom_header_size) * 512);
+ SET_VGA(_rom_header_checksum, sum);
+}
diff --git a/roms/seabios/vgasrc/vgalayout.lds.S b/roms/seabios/vgasrc/vgalayout.lds.S
new file mode 100644
index 00000000..533734d8
--- /dev/null
+++ b/roms/seabios/vgasrc/vgalayout.lds.S
@@ -0,0 +1,23 @@
+// Linker definitions for an option rom
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH("i386")
+ENTRY(_optionrom_entry)
+SECTIONS
+{
+ .text 0 : {
+ KEEP(*(.rom.header))
+ *(.text.*)
+ _rodata = . ;
+ *(.rodata*)
+ *(.data16.*)
+ }
+
+ // Discard regular data sections to force a link error if
+ // 16bit code attempts to access data not marked with VAR16.
+ /DISCARD/ : { *(.text*) *(.rodata*) *(.data*) *(.bss*) *(COMMON) }
+}