Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
Jack Lange [Fri, 7 Jun 2013 20:01:11 +0000 (15:01 -0500)]
172 files changed:
bios/seabios/.config [new file with mode: 0644]
bios/seabios/COPYING [new file with mode: 0644]
bios/seabios/COPYING.LESSER [new file with mode: 0644]
bios/seabios/Makefile [new file with mode: 0644]
bios/seabios/README [new file with mode: 0644]
bios/seabios/README.palacios [new file with mode: 0644]
bios/seabios/TODO [new file with mode: 0644]
bios/seabios/palacios_config [new file with mode: 0644]
bios/seabios/palacios_fixes.patch [new file with mode: 0644]
bios/seabios/src/Kconfig [new file with mode: 0644]
bios/seabios/src/acpi-dsdt.dsl [new file with mode: 0644]
bios/seabios/src/acpi-dsdt.hex [new file with mode: 0644]
bios/seabios/src/acpi.c [new file with mode: 0644]
bios/seabios/src/acpi.h [new file with mode: 0644]
bios/seabios/src/ahci.c [new file with mode: 0644]
bios/seabios/src/ahci.h [new file with mode: 0644]
bios/seabios/src/apm.c [new file with mode: 0644]
bios/seabios/src/asm-offsets.c [new file with mode: 0644]
bios/seabios/src/ata.c [new file with mode: 0644]
bios/seabios/src/ata.h [new file with mode: 0644]
bios/seabios/src/biostables.c [new file with mode: 0644]
bios/seabios/src/biosvar.h [new file with mode: 0644]
bios/seabios/src/block.c [new file with mode: 0644]
bios/seabios/src/blockcmd.c [new file with mode: 0644]
bios/seabios/src/blockcmd.h [new file with mode: 0644]
bios/seabios/src/bmp.c [new file with mode: 0644]
bios/seabios/src/bmp.h [new file with mode: 0644]
bios/seabios/src/boot.c [new file with mode: 0644]
bios/seabios/src/boot.h [new file with mode: 0644]
bios/seabios/src/bootsplash.c [new file with mode: 0644]
bios/seabios/src/bregs.h [new file with mode: 0644]
bios/seabios/src/cdrom.c [new file with mode: 0644]
bios/seabios/src/clock.c [new file with mode: 0644]
bios/seabios/src/cmos.h [new file with mode: 0644]
bios/seabios/src/config.h [new file with mode: 0644]
bios/seabios/src/coreboot.c [new file with mode: 0644]
bios/seabios/src/disk.c [new file with mode: 0644]
bios/seabios/src/disk.h [new file with mode: 0644]
bios/seabios/src/entryfuncs.S [new file with mode: 0644]
bios/seabios/src/farptr.h [new file with mode: 0644]
bios/seabios/src/floppy.c [new file with mode: 0644]
bios/seabios/src/font.c [new file with mode: 0644]
bios/seabios/src/gen-defs.h [new file with mode: 0644]
bios/seabios/src/ioport.h [new file with mode: 0644]
bios/seabios/src/jpeg.c [new file with mode: 0644]
bios/seabios/src/jpeg.h [new file with mode: 0644]
bios/seabios/src/kbd.c [new file with mode: 0644]
bios/seabios/src/lzmadecode.c [new file with mode: 0644]
bios/seabios/src/lzmadecode.h [new file with mode: 0644]
bios/seabios/src/memmap.c [new file with mode: 0644]
bios/seabios/src/memmap.h [new file with mode: 0644]
bios/seabios/src/misc.c [new file with mode: 0644]
bios/seabios/src/mouse.c [new file with mode: 0644]
bios/seabios/src/mptable.c [new file with mode: 0644]
bios/seabios/src/mptable.h [new file with mode: 0644]
bios/seabios/src/mtrr.c [new file with mode: 0644]
bios/seabios/src/optionroms.c [new file with mode: 0644]
bios/seabios/src/output.c [new file with mode: 0644]
bios/seabios/src/paravirt.c [new file with mode: 0644]
bios/seabios/src/paravirt.h [new file with mode: 0644]
bios/seabios/src/pci.c [new file with mode: 0644]
bios/seabios/src/pci.h [new file with mode: 0644]
bios/seabios/src/pci_ids.h [new file with mode: 0644]
bios/seabios/src/pci_regs.h [new file with mode: 0644]
bios/seabios/src/pcibios.c [new file with mode: 0644]
bios/seabios/src/pciinit.c [new file with mode: 0644]
bios/seabios/src/pic.c [new file with mode: 0644]
bios/seabios/src/pic.h [new file with mode: 0644]
bios/seabios/src/pirtable.c [new file with mode: 0644]
bios/seabios/src/pmm.c [new file with mode: 0644]
bios/seabios/src/pnpbios.c [new file with mode: 0644]
bios/seabios/src/post.c [new file with mode: 0644]
bios/seabios/src/ps2port.c [new file with mode: 0644]
bios/seabios/src/ps2port.h [new file with mode: 0644]
bios/seabios/src/ramdisk.c [new file with mode: 0644]
bios/seabios/src/resume.c [new file with mode: 0644]
bios/seabios/src/romlayout.S [new file with mode: 0644]
bios/seabios/src/serial.c [new file with mode: 0644]
bios/seabios/src/shadow.c [new file with mode: 0644]
bios/seabios/src/smbios.c [new file with mode: 0644]
bios/seabios/src/smbios.h [new file with mode: 0644]
bios/seabios/src/smm.c [new file with mode: 0644]
bios/seabios/src/smp.c [new file with mode: 0644]
bios/seabios/src/ssdt-proc.dsl [new file with mode: 0644]
bios/seabios/src/stacks.c [new file with mode: 0644]
bios/seabios/src/system.c [new file with mode: 0644]
bios/seabios/src/types.h [new file with mode: 0644]
bios/seabios/src/usb-ehci.c [new file with mode: 0644]
bios/seabios/src/usb-ehci.h [new file with mode: 0644]
bios/seabios/src/usb-hid.c [new file with mode: 0644]
bios/seabios/src/usb-hid.h [new file with mode: 0644]
bios/seabios/src/usb-hub.c [new file with mode: 0644]
bios/seabios/src/usb-hub.h [new file with mode: 0644]
bios/seabios/src/usb-msc.c [new file with mode: 0644]
bios/seabios/src/usb-msc.h [new file with mode: 0644]
bios/seabios/src/usb-ohci.c [new file with mode: 0644]
bios/seabios/src/usb-ohci.h [new file with mode: 0644]
bios/seabios/src/usb-uhci.c [new file with mode: 0644]
bios/seabios/src/usb-uhci.h [new file with mode: 0644]
bios/seabios/src/usb.c [new file with mode: 0644]
bios/seabios/src/usb.h [new file with mode: 0644]
bios/seabios/src/util.c [new file with mode: 0644]
bios/seabios/src/util.h [new file with mode: 0644]
bios/seabios/src/vgahooks.c [new file with mode: 0644]
bios/seabios/src/virtio-blk.c [new file with mode: 0644]
bios/seabios/src/virtio-blk.h [new file with mode: 0644]
bios/seabios/src/virtio-pci.c [new file with mode: 0644]
bios/seabios/src/virtio-pci.h [new file with mode: 0644]
bios/seabios/src/virtio-ring.c [new file with mode: 0644]
bios/seabios/src/virtio-ring.h [new file with mode: 0644]
bios/seabios/src/xen.c [new file with mode: 0644]
bios/seabios/src/xen.h [new file with mode: 0644]
bios/seabios/tools/buildrom.py [new file with mode: 0755]
bios/seabios/tools/checkrom.py [new file with mode: 0755]
bios/seabios/tools/checkstack.py [new file with mode: 0755]
bios/seabios/tools/checksum.py [new file with mode: 0755]
bios/seabios/tools/encodeint.py [new file with mode: 0755]
bios/seabios/tools/gen-offsets.sh [new file with mode: 0755]
bios/seabios/tools/kconfig/.gitignore [new file with mode: 0644]
bios/seabios/tools/kconfig/Makefile [new file with mode: 0644]
bios/seabios/tools/kconfig/POTFILES.in [new file with mode: 0644]
bios/seabios/tools/kconfig/check.sh [new file with mode: 0755]
bios/seabios/tools/kconfig/conf.c [new file with mode: 0644]
bios/seabios/tools/kconfig/confdata.c [new file with mode: 0644]
bios/seabios/tools/kconfig/expr.c [new file with mode: 0644]
bios/seabios/tools/kconfig/expr.h [new file with mode: 0644]
bios/seabios/tools/kconfig/gconf.c [new file with mode: 0644]
bios/seabios/tools/kconfig/gconf.glade [new file with mode: 0644]
bios/seabios/tools/kconfig/images.c [new file with mode: 0644]
bios/seabios/tools/kconfig/kconfig_load.c [new file with mode: 0644]
bios/seabios/tools/kconfig/kxgettext.c [new file with mode: 0644]
bios/seabios/tools/kconfig/lex.zconf.c_shipped [new file with mode: 0644]
bios/seabios/tools/kconfig/lkc.h [new file with mode: 0644]
bios/seabios/tools/kconfig/lkc_proto.h [new file with mode: 0644]
bios/seabios/tools/kconfig/lxdialog/.gitignore [new file with mode: 0644]
bios/seabios/tools/kconfig/lxdialog/BIG.FAT.WARNING [new file with mode: 0644]
bios/seabios/tools/kconfig/lxdialog/check-lxdialog.sh [new file with mode: 0644]
bios/seabios/tools/kconfig/lxdialog/checklist.c [new file with mode: 0644]
bios/seabios/tools/kconfig/lxdialog/dialog.h [new file with mode: 0644]
bios/seabios/tools/kconfig/lxdialog/inputbox.c [new file with mode: 0644]
bios/seabios/tools/kconfig/lxdialog/menubox.c [new file with mode: 0644]
bios/seabios/tools/kconfig/lxdialog/textbox.c [new file with mode: 0644]
bios/seabios/tools/kconfig/lxdialog/util.c [new file with mode: 0644]
bios/seabios/tools/kconfig/lxdialog/yesno.c [new file with mode: 0644]
bios/seabios/tools/kconfig/mconf.c [new file with mode: 0644]
bios/seabios/tools/kconfig/menu.c [new file with mode: 0644]
bios/seabios/tools/kconfig/nconf.c [new file with mode: 0644]
bios/seabios/tools/kconfig/nconf.gui.c [new file with mode: 0644]
bios/seabios/tools/kconfig/nconf.h [new file with mode: 0644]
bios/seabios/tools/kconfig/qconf.cc [new file with mode: 0644]
bios/seabios/tools/kconfig/qconf.h [new file with mode: 0644]
bios/seabios/tools/kconfig/symbol.c [new file with mode: 0644]
bios/seabios/tools/kconfig/util.c [new file with mode: 0644]
bios/seabios/tools/kconfig/zconf.gperf [new file with mode: 0644]
bios/seabios/tools/kconfig/zconf.hash.c_shipped [new file with mode: 0644]
bios/seabios/tools/kconfig/zconf.l [new file with mode: 0644]
bios/seabios/tools/kconfig/zconf.tab.c_shipped [new file with mode: 0644]
bios/seabios/tools/kconfig/zconf.y [new file with mode: 0644]
bios/seabios/tools/layoutrom.py [new file with mode: 0755]
bios/seabios/tools/layoutrom.pyc [new file with mode: 0644]
bios/seabios/tools/readserial.py [new file with mode: 0755]
bios/seabios/tools/test-gcc.sh [new file with mode: 0755]
bios/seabios/tools/transdump.py [new file with mode: 0755]
bios/seabios/vgasrc/clext.c [new file with mode: 0644]
bios/seabios/vgasrc/vga.c [new file with mode: 0644]
bios/seabios/vgasrc/vgaentry.S [new file with mode: 0644]
bios/seabios/vgasrc/vgafb.c [new file with mode: 0644]
bios/seabios/vgasrc/vgafonts.c [new file with mode: 0644]
bios/seabios/vgasrc/vgaio.c [new file with mode: 0644]
bios/seabios/vgasrc/vgalayout.lds.S [new file with mode: 0644]
bios/seabios/vgasrc/vgatables.c [new file with mode: 0644]
bios/seabios/vgasrc/vgatables.h [new file with mode: 0644]

diff --git a/bios/seabios/.config b/bios/seabios/.config
new file mode 100644 (file)
index 0000000..992484a
--- /dev/null
@@ -0,0 +1,72 @@
+#
+# Automatically generated make config: don't edit
+# SeaBIOS Configuration
+# Wed Mar 14 18:51:09 2012
+#
+
+#
+# General Features
+#
+# CONFIG_COREBOOT is not set
+# CONFIG_XEN is not set
+# CONFIG_THREADS is not set
+CONFIG_RELOCATE_INIT=y
+CONFIG_BOOTMENU=y
+CONFIG_BOOTSPLASH=y
+CONFIG_BOOTORDER=y
+
+#
+# Hardware support
+#
+CONFIG_ATA=y
+CONFIG_ATA_DMA=y
+CONFIG_ATA_PIO32=y
+# CONFIG_AHCI is not set
+CONFIG_VIRTIO_BLK=y
+CONFIG_FLOPPY=y
+CONFIG_PS2PORT=y
+CONFIG_USB=y
+CONFIG_USB_UHCI=y
+CONFIG_USB_OHCI=y
+CONFIG_USB_EHCI=y
+CONFIG_USB_MSC=y
+CONFIG_USB_HUB=y
+CONFIG_USB_KEYBOARD=y
+CONFIG_USB_MOUSE=y
+CONFIG_SERIAL=y
+CONFIG_LPT=y
+CONFIG_USE_SMM=y
+# CONFIG_MTRR_INIT is not set
+
+#
+# BIOS interfaces
+#
+CONFIG_DRIVES=y
+CONFIG_CDROM_BOOT=y
+CONFIG_CDROM_EMU=y
+CONFIG_PCIBIOS=y
+CONFIG_APMBIOS=y
+CONFIG_PNPBIOS=y
+CONFIG_OPTIONROMS=y
+CONFIG_OPTIONROMS_DEPLOYED=y
+CONFIG_PMM=y
+CONFIG_BOOT=y
+CONFIG_KEYBOARD=y
+CONFIG_KBD_CALL_INT15_4F=y
+CONFIG_MOUSE=y
+CONFIG_S3_RESUME=y
+# CONFIG_DISABLE_A20 is not set
+
+#
+# BIOS Tables
+#
+CONFIG_PIRTABLE=y
+CONFIG_MPTABLE=y
+CONFIG_SMBIOS=y
+CONFIG_ACPI=y
+
+#
+# Debugging
+#
+CONFIG_DEBUG_LEVEL=1
+# CONFIG_DEBUG_SERIAL is not set
diff --git a/bios/seabios/COPYING b/bios/seabios/COPYING
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
@@ -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/bios/seabios/COPYING.LESSER b/bios/seabios/COPYING.LESSER
new file mode 100644 (file)
index 0000000..fc8a5de
--- /dev/null
@@ -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/bios/seabios/Makefile b/bios/seabios/Makefile
new file mode 100644 (file)
index 0000000..096b503
--- /dev/null
@@ -0,0 +1,230 @@
+# SeaBIOS build system
+#
+# Copyright (C) 2008-2010  Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU LGPLv3 license.
+
+# Program version
+VERSION=1.6.3-$(shell date +"%Y%m%d_%H%M%S")-$(shell hostname)
+
+# Output directory
+OUT=out/
+
+# Source files
+SRCBOTH=misc.c stacks.c pmm.c output.c util.c block.c floppy.c ata.c mouse.c \
+        kbd.c pci.c serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \
+        pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \
+        usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \
+        virtio-ring.c virtio-pci.c virtio-blk.c apm.c ahci.c
+SRC16=$(SRCBOTH) system.c disk.c font.c
+SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
+      acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
+      lzmadecode.c bootsplash.c jpeg.c usb-hub.c paravirt.c \
+      biostables.c xen.c bmp.c
+SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c
+
+cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
+              /dev/null 2>&1`"; then echo "$(2)"; else echo "$(3)"; fi ;)
+
+# Default compiler flags
+COMMONCFLAGS = -I$(OUT) -Os -MD \
+               -Wall -Wno-strict-aliasing -Wold-style-definition \
+               $(call cc-option,$(CC),-Wtype-limits,) \
+               -m32 -march=i386 -mregparm=3 -mpreferred-stack-boundary=2 \
+               -mrtd -minline-all-stringops \
+               -freg-struct-return -ffreestanding -fomit-frame-pointer \
+               -fno-delete-null-pointer-checks \
+               -ffunction-sections -fdata-sections -fno-common
+COMMONCFLAGS += $(call cc-option,$(CC),-nopie,)
+COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
+COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
+
+CFLAGS32FLAT = $(COMMONCFLAGS) -g -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 -g
+CFLAGS16INC = $(CFLAGSSEG) -DMODE16=1 \
+              $(call cc-option,$(CC),--param large-stack-frame=4,-fno-inline)
+CFLAGS16 = $(CFLAGS16INC) -g
+
+all: $(OUT) $(OUT)bios.bin
+
+# Run with "make V=1" to see the actual compile commands
+ifdef V
+Q=
+else
+Q=@
+MAKEFLAGS += --no-print-directory
+endif
+
+OBJCOPY=objcopy
+OBJDUMP=objdump
+STRIP=strip
+
+.PHONY : all clean distclean FORCE
+
+vpath %.c src vgasrc
+vpath %.S src vgasrc
+
+################ Build rules
+
+# Verify the gcc configuration and test if -fwhole-program works.
+TESTGCC:=$(shell CC="$(CC)" LD="$(LD)" tools/test-gcc.sh)
+ifeq "$(TESTGCC)" "-1"
+$(error "Please upgrade GCC and/or binutils")
+endif
+
+ifndef COMPSTRAT
+COMPSTRAT=$(TESTGCC)
+endif
+
+# Do a whole file compile - three methods are supported.
+ifeq "$(COMPSTRAT)" "1"
+# First method - use -fwhole-program without -combine.
+define whole-compile
+@echo "  Compiling whole program $3"
+$(Q)printf '$(foreach i,$2,#include "../$i"\n)' > $3.tmp.c
+$(Q)$(CC) $1 -fwhole-program -DWHOLE_PROGRAM -c $3.tmp.c -o $3
+endef
+else
+ifeq "$(COMPSTRAT)" "2"
+# Second menthod - don't use -fwhole-program at all.
+define whole-compile
+@echo "  Compiling whole program $3"
+$(Q)printf '$(foreach i,$2,#include "../$i"\n)' > $3.tmp.c
+$(Q)$(CC) $1 -c $3.tmp.c -o $3
+endef
+else
+# Third (and preferred) method - use -fwhole-program with -combine
+define whole-compile
+@echo "  Compiling whole program $3"
+$(Q)$(CC) $1 -fwhole-program -DWHOLE_PROGRAM -combine -c $2 -o $3
+endef
+endif
+endif
+
+%.strip.o: %.o
+       @echo "  Stripping $@"
+       $(Q)$(STRIP) $< -o $@
+
+$(OUT)%.s: %.c
+       @echo "  Compiling to assembler $@"
+       $(Q)$(CC) $(CFLAGS16INC) -S -c $< -o $@
+
+$(OUT)%.lds: %.lds.S
+       @echo "  Precompiling $@"
+       $(Q)$(CPP) -P -D__ASSEMBLY__ $< -o $@
+
+$(OUT)asm-offsets.s: $(OUT)autoconf.h
+
+$(OUT)asm-offsets.h: $(OUT)asm-offsets.s
+       @echo "  Generating offset file $@"
+       $(Q)./tools/gen-offsets.sh $< $@
+
+
+$(OUT)ccode.16.s: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS16) -S, $(addprefix src/, $(SRC16)),$@)
+
+$(OUT)code32seg.o: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS32SEG), $(addprefix src/, $(SRC32SEG)),$@)
+
+$(OUT)ccode32flat.o: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS32FLAT), $(addprefix src/, $(SRC32FLAT)),$@)
+
+$(OUT)code16.o: romlayout.S $(OUT)ccode.16.s $(OUT)asm-offsets.h
+       @echo "  Compiling (16bit) $@"
+       $(Q)$(CC) $(CFLAGS16INC) -c -D__ASSEMBLY__ $< -o $@
+
+$(OUT)romlayout16.lds: $(OUT)ccode32flat.o $(OUT)code32seg.o $(OUT)code16.o tools/layoutrom.py
+       @echo "  Building ld scripts (version \"$(VERSION)\")"
+       $(Q)echo 'const char VERSION[] = "$(VERSION)";' > $(OUT)version.c
+       $(Q)$(CC) $(CFLAGS32FLAT) -c $(OUT)version.c -o $(OUT)version.o
+       $(Q)$(LD) -melf_i386 -r $(OUT)ccode32flat.o $(OUT)version.o -o $(OUT)code32flat.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)./tools/layoutrom.py $(OUT)code16.o.objdump $(OUT)code32seg.o.objdump $(OUT)code32flat.o.objdump $(OUT)romlayout16.lds $(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds
+
+# These are actually built by tools/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)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.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py
+       @echo "  Prepping $@"
+       $(Q)$(OBJDUMP) -thr $< > $<.objdump
+       $(Q)$(OBJCOPY) -O binary $< $(OUT)bios.bin.raw
+       $(Q)./tools/checkrom.py $<.objdump $(OUT)bios.bin.raw $(OUT)bios.bin
+       $(Q)$(STRIP) -R .comment $< -o $(OUT)bios.bin.elf
+
+
+################ VGA build rules
+
+# VGA src files
+SRCVGA=src/output.c src/util.c vgasrc/vga.c vgasrc/vgafb.c vgasrc/vgaio.c \
+       vgasrc/vgatables.c vgasrc/vgafonts.c vgasrc/clext.c
+
+$(OUT)vgaccode.16.s: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS16) -S -Isrc, $(SRCVGA),$@)
+
+$(OUT)vgalayout16.o: vgaentry.S $(OUT)vgaccode.16.s $(OUT)asm-offsets.h
+       @echo "  Compiling (16bit) $@"
+       $(Q)$(CC) $(CFLAGS16INC) -c -D__ASSEMBLY__ -Isrc $< -o $@
+
+$(OUT)vgarom.o: $(OUT)vgalayout16.o $(OUT)vgalayout.lds
+       @echo "  Linking $@"
+       $(Q)$(LD) --gc-sections -T $(OUT)vgalayout.lds $(OUT)vgalayout16.o -o $@
+
+$(OUT)vgabios.bin.raw: $(OUT)vgarom.o
+       @echo "  Extracting binary $@"
+       $(Q)$(OBJCOPY) -O binary $< $@
+
+$(OUT)vgabios.bin: $(OUT)vgabios.bin.raw tools/buildrom.py
+       @echo "  Finalizing rom $@"
+       $(Q)./tools/buildrom.py $< $@
+
+####### dsdt build rules
+src/%.hex: src/%.dsl
+       @echo "Compiling DSDT"
+       $(Q)cpp -P $< > $(OUT)$*.dsl.i
+       $(Q)iasl -tc -p $(OUT)$* $(OUT)$*.dsl.i
+       $(Q)cp $(OUT)$*.hex $@
+
+$(OUT)ccode32flat.o: src/acpi-dsdt.hex
+
+####### Kconfig rules
+export HOSTCC             := $(CC)
+export CONFIG_SHELL       := sh
+export KCONFIG_AUTOHEADER := autoconf.h
+export KCONFIG_CONFIG     := $(CURDIR)/.config
+
+$(OUT)autoconf.h : $(KCONFIG_CONFIG)
+       $(Q)$(MAKE) silentoldconfig
+
+$(KCONFIG_CONFIG):
+       $(Q)$(MAKE) defconfig
+
+%onfig:
+       $(Q)mkdir -p $(OUT)/tools/kconfig/lxdialog
+       $(Q)mkdir -p $(OUT)/include/config
+       $(Q)$(MAKE) -C $(OUT) -f $(CURDIR)/tools/kconfig/Makefile srctree=$(CURDIR) src=tools/kconfig obj=tools/kconfig Q=$(Q) Kconfig=$(CURDIR)/src/Kconfig $@
+
+####### Generic rules
+clean:
+       $(Q)rm -rf $(OUT)
+
+distclean: clean
+       $(Q)rm -f .config .config.old
+
+$(OUT):
+       $(Q)mkdir $@
+
+-include $(OUT)*.d
diff --git a/bios/seabios/README b/bios/seabios/README
new file mode 100644 (file)
index 0000000..1f40433
--- /dev/null
@@ -0,0 +1,173 @@
+This code implements an X86 legacy bios.  It is intended to be
+compiled using standard gnu tools (eg, gas and gcc).
+
+To build, one should be able to run "make" in the main directory.  The
+resulting file "out/bios.bin" contains the processed bios image.
+
+
+Testing of images:
+
+To test the bios under bochs, one will need to instruct bochs to use
+the new bios image.  Use the 'romimage' option - for example:
+
+bochs -q 'floppya: 1_44=myfdimage.img' 'romimage: file=out/bios.bin'
+
+To test under qemu, one will need to create a directory with all the
+bios images and then overwrite the main bios image.  For example:
+
+cp /usr/share/qemu/*.bin mybiosdir/
+cp out/bios.bin mybiosdir/
+
+Once this is setup, one can instruct qemu to use the newly created
+directory for rom images.  For example:
+
+qemu -L mybiosdir/ -fda myfdimage.img
+
+
+Overview of files:
+
+The src/ directory contains the bios source code.  Several of the
+files are compiled twice - once for 16bit mode and once for 32bit
+mode.  (The build system will remove code that is not needed for a
+particular mode.)
+
+The tools/ directory contains helper utilities for manipulating and
+building the final rom.
+
+The out/ directory is created by the build process - it contains all
+temporary and final files.
+
+
+Build overview:
+
+The 16bit code is compiled via gcc to assembler (file out/ccode.16.s).
+The gcc "-fwhole-program" and "-ffunction-sections -fdata-sections"
+options are used to optimize the process so that gcc can efficiently
+compile and discard unneeded code.  (In the code, one can use the
+macros 'VISIBLE16' and 'VISIBLE32FLAT' to instruct a symbol to be
+outputted in 16bit and 32bit mode respectively.)
+
+This resulting assembler code is pulled into romlayout.S.  The gas
+option ".code16gcc" is used prior to including the gcc generated
+assembler - this option enables gcc to generate valid 16 bit code.
+
+The post code (post.c) is entered, via the function handle_post(), in
+32bit mode.  The 16bit post vector (in romlayout.S) transitions the
+cpu into 32 bit mode before calling the post.c code.
+
+In the last step of compilation, the 32 bit code is merged into the 16
+bit code so that one binary file contains both.  Currently, both 16bit
+and 32bit code will be located in the memory at 0xe0000-0xfffff.
+
+
+GCC 16 bit limitations:
+
+Although the 16bit code is compiled with gcc, developers need to be
+aware of the environment.  In particular, global variables _must_ be
+treated specially.
+
+The code has full access to stack variables and general purpose
+registers.  The entry code in romlayout.S will push the original
+registers on the stack before calling the C code and then pop them off
+(including any required changes) before returning from the interrupt.
+Changes to CS, DS, and ES segment registers in C code is also safe.
+Changes to other segment registers (SS, FS, GS) need to be restored
+manually.
+
+Stack variables (and pointers to stack variables) work as they
+normally do in standard C code.
+
+However, variables stored outside the stack need to be accessed via
+the GET_VAR and SET_VAR macros (or one of the helper macros described
+below).  This is due to the 16bit segment nature of the X86 cpu when
+it is in "real mode".  The C entry code will set DS and SS to point to
+the stack segment.  Variables not on the stack need to be accessed via
+an explicit segment register.  Any other access requires altering one
+of the other segment registers (usually ES) and then accessing the
+variable via that segment register.
+
+There are three low-level ways to access a remote variable:
+GET/SET_VAR, GET/SET_FARVAR, and GET/SET_FLATPTR.  The first set takes
+an explicit segment descriptor (eg, "CS") and offset.  The second set
+will take a segment id and offset, set ES to the segment id, and then
+make the access via the ES segment.  The last method is similar to the
+second, except it takes a pointer that would be valid in 32-bit flat
+mode instead of a segment/offset pair.
+
+Most BIOS variables are stored in global variables, the "BDA", or
+"EBDA" memory areas.  Because this is common, three sets of helper
+macros (GET/SET_GLOBAL, GET/SET_BDA, and GET/SET_EBDA) are available
+to simplify these accesses.
+
+Global variables defined in the C code can be read in 16bit mode if
+the variable declaration is marked with VAR16, VAR16VISIBLE,
+VAR16EXPORT, or VAR16FIXED.  The GET_GLOBAL macro will then allow read
+access to the variable.  Global variables are stored in the 0xf000
+segment, and their values are persistent across soft resets.  Because
+the f-segment is marked read-only during run-time, the 16bit code is
+not permitted to change the value of 16bit variables (use of the
+SET_GLOBAL macro from 16bit mode will cause a link error).  Code
+running in 32bit mode can not access variables with VAR16, but can
+access variables marked with VAR16VISIBLE, VAR16EXPORT, VAR16FIXED, or
+with no marking at all.  The 32bit code can use the GET/SET_GLOBAL
+macros, but they are not required.
+
+
+GCC 16 bit stack limitations:
+
+Another limitation of gcc is its use of 32-bit temporaries.  Gcc will
+allocate 32-bits of space for every variable - even if that variable
+is only defined as a 'u8' or 'u16'.  If one is not careful, using too
+much stack space can break old DOS applications.
+
+There does not appear to be explicit documentation on the minimum
+stack space available for bios calls.  However, Freedos has been
+observed to call into the bios with less than 150 bytes available.
+
+Note that the post code and boot code (irq 18/19) do not have a stack
+limitation because the entry points for these functions transition the
+cpu to 32bit mode and reset the stack to a known state.  Only the
+general purpose 16-bit service entry points are affected.
+
+There are some ways to reduce stack usage: making sure functions are
+tail-recursive often helps, reducing the number of parameters passed
+to functions often helps, sometimes reordering variable declarations
+helps, inlining of functions can sometimes help, and passing of packed
+structures can also help.  It is also possible to transition to/from
+an extra stack stored in the EBDA using the stack_hop helper function.
+
+Some useful stats: the overhead for the entry to a bios handler that
+takes a 'struct bregs' is 42 bytes of stack space (6 bytes from
+interrupt insn, 32 bytes to store registers, and 4 bytes for call
+insn).  An entry to an ISR handler without args takes 30 bytes (6 + 20
++ 4).
+
+
+Debugging the bios:
+
+The bios will output information messages to a special debug port.
+Under qemu, 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.
+
+The gdb-server mechanism of qemu is also useful.  One can use gdb with
+qemu to debug system images.  To use this, add '-s -S' to the qemu
+command line.  For example:
+
+qemu -L mybiosdir/ -fda myfdimage.img -s -S
+
+Then, in another session, run gdb with either out/rom16.o (to debug
+bios 16bit code) or out/rom32.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.  Note that gdb seems to get
+breakpoints confused when the cpu is in 16-bit real mode.  This makes
+stepping through the program difficult (though 'step instruction'
+still works).  Also, one may need to set 16bit break points at both
+the cpu address and memory address (eg, break *0x1234 ; break
+*0xf1234).
diff --git a/bios/seabios/README.palacios b/bios/seabios/README.palacios
new file mode 100644 (file)
index 0000000..06a4ca6
--- /dev/null
@@ -0,0 +1 @@
+cp palacios_config .config and then make
diff --git a/bios/seabios/TODO b/bios/seabios/TODO
new file mode 100644 (file)
index 0000000..23f26c0
--- /dev/null
@@ -0,0 +1,21 @@
+Review changes committed to coreboot, virtualbox, qemu, kvm, and bochs
+cvs tip.
+  * bochs cvs (20100104):
+    -- changes synched
+  * coreboot (r3348):    (bochs 20060708)
+    -- no noteworthy enhancements
+  * qemu - now uses SeaBIOS
+  * kvm - now uses SeaBIOS
+  * virtualbox (r13560): (bochs 20061231)
+    -- lots of mouse changes, logo, scsi/etherboot hooks,
+       floppy data rate?, int19 calls post
+
+The __call16 code does a long jump to the interrupt trampolines - this
+is unnecessary.
+
+Support PCIv3 roms?  Add support for PCI "configuration code"
+extensions?
+
+Possibly add option to eliminate tsc based delays on emulators.
+
+Possibly support sending debug information over EHCI debug port.
diff --git a/bios/seabios/palacios_config b/bios/seabios/palacios_config
new file mode 100644 (file)
index 0000000..992484a
--- /dev/null
@@ -0,0 +1,72 @@
+#
+# Automatically generated make config: don't edit
+# SeaBIOS Configuration
+# Wed Mar 14 18:51:09 2012
+#
+
+#
+# General Features
+#
+# CONFIG_COREBOOT is not set
+# CONFIG_XEN is not set
+# CONFIG_THREADS is not set
+CONFIG_RELOCATE_INIT=y
+CONFIG_BOOTMENU=y
+CONFIG_BOOTSPLASH=y
+CONFIG_BOOTORDER=y
+
+#
+# Hardware support
+#
+CONFIG_ATA=y
+CONFIG_ATA_DMA=y
+CONFIG_ATA_PIO32=y
+# CONFIG_AHCI is not set
+CONFIG_VIRTIO_BLK=y
+CONFIG_FLOPPY=y
+CONFIG_PS2PORT=y
+CONFIG_USB=y
+CONFIG_USB_UHCI=y
+CONFIG_USB_OHCI=y
+CONFIG_USB_EHCI=y
+CONFIG_USB_MSC=y
+CONFIG_USB_HUB=y
+CONFIG_USB_KEYBOARD=y
+CONFIG_USB_MOUSE=y
+CONFIG_SERIAL=y
+CONFIG_LPT=y
+CONFIG_USE_SMM=y
+# CONFIG_MTRR_INIT is not set
+
+#
+# BIOS interfaces
+#
+CONFIG_DRIVES=y
+CONFIG_CDROM_BOOT=y
+CONFIG_CDROM_EMU=y
+CONFIG_PCIBIOS=y
+CONFIG_APMBIOS=y
+CONFIG_PNPBIOS=y
+CONFIG_OPTIONROMS=y
+CONFIG_OPTIONROMS_DEPLOYED=y
+CONFIG_PMM=y
+CONFIG_BOOT=y
+CONFIG_KEYBOARD=y
+CONFIG_KBD_CALL_INT15_4F=y
+CONFIG_MOUSE=y
+CONFIG_S3_RESUME=y
+# CONFIG_DISABLE_A20 is not set
+
+#
+# BIOS Tables
+#
+CONFIG_PIRTABLE=y
+CONFIG_MPTABLE=y
+CONFIG_SMBIOS=y
+CONFIG_ACPI=y
+
+#
+# Debugging
+#
+CONFIG_DEBUG_LEVEL=1
+# CONFIG_DEBUG_SERIAL is not set
diff --git a/bios/seabios/palacios_fixes.patch b/bios/seabios/palacios_fixes.patch
new file mode 100644 (file)
index 0000000..427c4e8
--- /dev/null
@@ -0,0 +1,147 @@
+From 83f115d2f7f26dddcbbffe89aa8a7a97b28a6228 Mon Sep 17 00:00:00 2001
+From: Alexander Kudryavtsev <alexk@ispras.ru>
+Date: Mon, 12 Mar 2012 13:07:07 +0400
+Subject: [PATCH] Fixes needed to launch SEABIOS inside Palacios's VM: 1.
+ Allow to build ACPI tables without PIIX4 PM device 2.
+ Disable HPET table generation 3. Do not perform PCI setup
+ since it breaks Palacios 4. Do not initialize AP cores
+ since it breaks Palacios 5. Fix SRAT generation - do not
+ cut PCI hole since it is already cut off by Palacios
+
+---
+ src/acpi.c    |   44 +++++++++++++++++++++++++++++---------------
+ src/pciinit.c |    2 +-
+ src/smp.c     |    5 ++++-
+ 3 files changed, 34 insertions(+), 17 deletions(-)
+
+diff --git a/src/acpi.c b/src/acpi.c
+index 3d8b7c8..7d50990 100644
+--- a/src/acpi.c
++++ b/src/acpi.c
+@@ -262,18 +262,32 @@ build_fadt(struct pci_device *pci)
+     fadt->dsdt = cpu_to_le32((u32)dsdt);
+     fadt->model = 1;
+     fadt->reserved1 = 0;
+-    int pm_sci_int = pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE);
++    int pm_sci_int;
++    if (pci)
++        pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE);
++    else
++        pm_sci_int = 0;
+     fadt->sci_int = cpu_to_le16(pm_sci_int);
+-    fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
+-    fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE);
+-    fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04);
+-    fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08);
+-    fadt->pm1_evt_len = 4;
+-    fadt->pm1_cnt_len = 2;
+-    fadt->pm_tmr_len = 4;
++    if (pci) {
++        fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
++        fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE);
++        fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04);
++        fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08);
++        fadt->pm1_evt_len = 4;
++        fadt->pm1_cnt_len = 2;
++        fadt->pm_tmr_len = 4;
++        pci_init_device(fadt_init_tbl, pci, fadt);
++    } else {
++        fadt->smi_cmd = 0;
++        fadt->pm1a_evt_blk = 0;
++        fadt->pm1a_cnt_blk = 0;
++        fadt->pm_tmr_blk = 0;
++        fadt->pm1_evt_len = 0;
++        fadt->pm1_cnt_len = 0;
++        fadt->pm_tmr_len = 0;
++    }
+     fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+     fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+-    pci_init_device(fadt_init_tbl, pci, fadt);
+     /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC + RTC_S4 */
+     fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6) | (1 << 7));
+@@ -516,6 +530,7 @@ build_srat(void)
+     if (nb_numa_nodes == 0)
+         return NULL;
++
+     u64 *numadata = malloc_tmphigh(sizeof(u64) * (MaxCountCPUs + nb_numa_nodes));
+     if (!numadata) {
+         warn_noalloc();
+@@ -577,7 +592,7 @@ build_srat(void)
+         next_base = mem_base + mem_len;
+         /* Cut out the PCI hole */
+-        if (mem_base <= RamSize && next_base > RamSize) {
++        /*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);
+@@ -587,7 +602,7 @@ build_srat(void)
+             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++;
+@@ -623,9 +638,7 @@ acpi_bios_init(void)
+     // 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;
++    // If no PIIX4 is found we will not build certain structures and init it.
+     // Build ACPI tables
+     u32 tables[MAX_ACPI_TABLES], tbl_idx = 0;
+@@ -640,7 +653,8 @@ acpi_bios_init(void)
+     ACPI_INIT_TABLE(build_fadt(pci));
+     ACPI_INIT_TABLE(build_ssdt());
+     ACPI_INIT_TABLE(build_madt());
+-    ACPI_INIT_TABLE(build_hpet());
++    if(pci)
++        ACPI_INIT_TABLE(build_hpet());
+     ACPI_INIT_TABLE(build_srat());
+     u16 i, external_tables = qemu_cfg_acpi_additional_tables();
+diff --git a/src/pciinit.c b/src/pciinit.c
+index 0d8758e..ef8ccda 100644
+--- a/src/pciinit.c
++++ b/src/pciinit.c
+@@ -575,7 +575,7 @@ static int pci_bios_init_root_regions(u32 start, u32 end)
+ void
+ pci_setup(void)
+ {
+-    if (CONFIG_COREBOOT || usingXen()) {
++    if (1 || CONFIG_COREBOOT || usingXen()) {
+         // PCI setup already done by coreboot or Xen - just do probe.
+         pci_probe_devices();
+         return;
+diff --git a/src/smp.c b/src/smp.c
+index 8c077a1..21e7437 100644
+--- a/src/smp.c
++++ b/src/smp.c
+@@ -81,7 +81,7 @@ smp_probe(void)
+         MaxCountCPUs = 1;
+         return;
+     }
+-
++#if 0
+     // Init the counter.
+     writel(&CountCPUs, 1);
+@@ -121,6 +121,9 @@ smp_probe(void)
+     // Restore memory.
+     *(u64*)BUILD_AP_BOOT_ADDR = old;
++#endif
+
++    CountCPUs = inb_cmos(CMOS_BIOS_SMP_COUNT) + 1; // Fix for Palacios
+     MaxCountCPUs = qemu_cfg_get_max_cpus();
+     if (!MaxCountCPUs || MaxCountCPUs < CountCPUs)
+-- 
+1.7.5.4
diff --git a/bios/seabios/src/Kconfig b/bios/seabios/src/Kconfig
new file mode 100644 (file)
index 0000000..338f51a
--- /dev/null
@@ -0,0 +1,349 @@
+# Kconfig SeaBIOS configuration
+
+mainmenu "SeaBIOS Configuration"
+
+menu "General Features"
+
+    config COREBOOT
+        bool "Build for coreboot"
+        default n
+        help
+            Configure as a coreboot payload.
+
+    config XEN
+        depends on !COREBOOT
+        bool "Build for Xen HVM"
+        default n
+        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 THREAD_OPTIONROMS
+        depends on THREADS
+        bool "Hardware init during option ROM execution"
+        default n
+        help
+            Allow hardware init to run in parallel with optionrom execution.
+
+            This can reduce boot time, but can cause some timing
+            variations during option ROM code execution.  It is not
+            known if all option ROMs will behave properly with this
+            option.
+
+    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
+            algorighm.
+    config FLASH_FLOPPY
+        depends on COREBOOT_FLASH
+        bool "Floppy images in CBFS"
+        default y
+        help
+            Support floppy images in coreboot flash.
+
+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 VIRTIO_BLK
+        depends on DRIVES && !COREBOOT
+        bool "VirtIO controllers"
+        default y
+        help
+            Support boot from virtio 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_MSC
+        depends on USB && DRIVES
+        bool "USB drives"
+        default y
+        help
+            Support USB 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 !COREBOOT
+        bool "System Management Mode (SMM)"
+        default y
+        help
+            Support System Management Mode (on emulators).
+    config MTRR_INIT
+        depends on !COREBOOT
+        bool "Initialize MTRRs"
+        default y
+        help
+            Initialize the Memory Type Range Registers (on emulators).
+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
+        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
+        depends on COREBOOT
+        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.
+endmenu
+
+menu "BIOS Tables"
+    config PIRTABLE
+        depends on !COREBOOT
+        bool "PIR table"
+        default y
+        help
+            Support generation of a PIR table in 0xf000 segment.
+    config MPTABLE
+        depends on !COREBOOT
+        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
+        depends on !COREBOOT
+        bool "ACPI"
+        default y
+        help
+            Support generation of ACPI tables.
+endmenu
+
+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.
+endmenu
diff --git a/bios/seabios/src/acpi-dsdt.dsl b/bios/seabios/src/acpi-dsdt.dsl
new file mode 100644 (file)
index 0000000..08412e2
--- /dev/null
@@ -0,0 +1,934 @@
+/*
+ * 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
+ */
+DefinitionBlock (
+    "acpi-dsdt.aml",    // Output Filename
+    "DSDT",             // Signature
+    0x01,               // DSDT Compliance Revision
+    "BXPC",             // OEMID
+    "BXDSDT",           // TABLE ID
+    0x1                 // OEM Revision
+    )
+{
+    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)
+        }
+    }
+
+    /* PCI Bus definition */
+    Scope(\_SB) {
+        Device(PCI0) {
+            Name (_HID, EisaId ("PNP0A03"))
+            Name (_ADR, 0x00)
+            Name (_UID, 1)
+            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 */
+               Package() { 0x0001ffff, 0, LNKS, 0 },
+               Package() { 0x0001ffff, 1, LNKB, 0 },
+               Package() { 0x0001ffff, 2, LNKC, 0 },
+               Package() { 0x0001ffff, 3, LNKD, 0 },
+               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),
+            })
+
+            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,
+            }
+
+            OperationRegion(RMVC, SystemIO, 0xae0c, 0x04)
+            Field(RMVC, DWordAcc, NoLock, WriteAsZeros)
+            {
+                PCRM, 32,
+            }
+
+#define hotplug_slot(name, nr) \
+            Device (S##name) {                    \
+               Name (_ADR, nr##0000)              \
+               Method (_EJ0,1) {                  \
+                    Store(ShiftLeft(1, nr), B0EJ) \
+                    Return (0x0)                  \
+               }                                  \
+               Name (_SUN, name)                  \
+            }
+
+           hotplug_slot(1, 0x0001)
+           hotplug_slot(2, 0x0002)
+           hotplug_slot(3, 0x0003)
+           hotplug_slot(4, 0x0004)
+           hotplug_slot(5, 0x0005)
+           hotplug_slot(6, 0x0006)
+           hotplug_slot(7, 0x0007)
+           hotplug_slot(8, 0x0008)
+           hotplug_slot(9, 0x0009)
+           hotplug_slot(10, 0x000a)
+           hotplug_slot(11, 0x000b)
+           hotplug_slot(12, 0x000c)
+           hotplug_slot(13, 0x000d)
+           hotplug_slot(14, 0x000e)
+           hotplug_slot(15, 0x000f)
+           hotplug_slot(16, 0x0010)
+           hotplug_slot(17, 0x0011)
+           hotplug_slot(18, 0x0012)
+           hotplug_slot(19, 0x0013)
+           hotplug_slot(20, 0x0014)
+           hotplug_slot(21, 0x0015)
+           hotplug_slot(22, 0x0016)
+           hotplug_slot(23, 0x0017)
+           hotplug_slot(24, 0x0018)
+           hotplug_slot(25, 0x0019)
+           hotplug_slot(26, 0x001a)
+           hotplug_slot(27, 0x001b)
+           hotplug_slot(28, 0x001c)
+           hotplug_slot(29, 0x001d)
+           hotplug_slot(30, 0x001e)
+           hotplug_slot(31, 0x001f)
+
+            Name (_CRS, 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
+                    ,, , AddressRangeMemory, TypeStatic)
+            })
+        }
+
+        Device(HPET) {
+            Name(_HID,  EISAID("PNP0103"))
+            Name(_UID, 0)
+            Method (_STA, 0, NotSerialized) {
+                    Return(0x0F)
+            }
+            Name(_CRS, ResourceTemplate() {
+                DWordMemory(
+                    ResourceConsumer, PosDecode, MinFixed, MaxFixed,
+                    NonCacheable, ReadWrite,
+                    0x00000000,
+                    0xFED00000,
+                    0xFED003FF,
+                    0x00000000,
+                    0x00000400 /* 1K memory: FED00000 - FED003FF */
+                )
+            })
+        }
+    }
+
+    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)
+                         }
+                 }
+                 Method(_RMV) { Return (0x00) }
+        }
+
+       /* PIIX3 ISA bridge */
+        Device (ISA) {
+            Name (_ADR, 0x00010000)
+            Method(_RMV) { Return (0x00) }
+
+
+            /* PIIX PCI to ISA irq remapping */
+            OperationRegion (P40C, PCI_Config, 0x60, 0x04)
+
+            /* Real-time clock */
+            Device (RTC)
+            {
+                Name (_HID, EisaId ("PNP0B00"))
+                Name (_CRS, ResourceTemplate ()
+                {
+                    IO (Decode16, 0x0070, 0x0070, 0x10, 0x02)
+                    IRQNoFlags () {8}
+                    IO (Decode16, 0x0072, 0x0072, 0x02, 0x06)
+                })
+            }
+
+            /* Keyboard seems to be important for WinXP install */
+            Device (KBD)
+            {
+                Name (_HID, EisaId ("PNP0303"))
+                Method (_STA, 0, NotSerialized)
+                {
+                    Return (0x0f)
+                }
+
+                Method (_CRS, 0, NotSerialized)
+                {
+                     Name (TMP, ResourceTemplate ()
+                     {
+                    IO (Decode16,
+                        0x0060,             // Address Range Minimum
+                        0x0060,             // Address Range Maximum
+                        0x01,               // Address Alignment
+                        0x01,               // Address Length
+                        )
+                    IO (Decode16,
+                        0x0064,             // Address Range Minimum
+                        0x0064,             // Address Range Maximum
+                        0x01,               // Address Alignment
+                        0x01,               // Address Length
+                        )
+                    IRQNoFlags ()
+                        {1}
+                    })
+                    Return (TMP)
+                }
+            }
+
+           /* PS/2 mouse */
+            Device (MOU)
+            {
+                Name (_HID, EisaId ("PNP0F13"))
+                Method (_STA, 0, NotSerialized)
+                {
+                    Return (0x0f)
+                }
+
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (TMP, ResourceTemplate ()
+                    {
+                         IRQNoFlags () {12}
+                    })
+                    Return (TMP)
+                }
+            }
+
+           /* PS/2 floppy controller */
+           Device (FDC0)
+           {
+               Name (_HID, EisaId ("PNP0700"))
+               Method (_STA, 0, NotSerialized)
+               {
+                   Return (0x0F)
+               }
+               Method (_CRS, 0, NotSerialized)
+               {
+                   Name (BUF0, ResourceTemplate ()
+                    {
+                        IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04)
+                        IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01)
+                        IRQNoFlags () {6}
+                        DMA (Compatibility, NotBusMaster, Transfer8) {2}
+                    })
+                   Return (BUF0)
+               }
+           }
+
+           /* Parallel port */
+           Device (LPT)
+           {
+               Name (_HID, EisaId ("PNP0400"))
+               Method (_STA, 0, NotSerialized)
+               {
+                   Store (\_SB.PCI0.PX13.DRSA, Local0)
+                   And (Local0, 0x80000000, Local0)
+                   If (LEqual (Local0, 0))
+                   {
+                       Return (0x00)
+                   }
+                   Else
+                   {
+                       Return (0x0F)
+                   }
+               }
+               Method (_CRS, 0, NotSerialized)
+               {
+                   Name (BUF0, ResourceTemplate ()
+                    {
+                       IO (Decode16, 0x0378, 0x0378, 0x08, 0x08)
+                       IRQNoFlags () {7}
+                   })
+                   Return (BUF0)
+               }
+           }
+
+           /* Serial Ports */
+           Device (COM1)
+           {
+               Name (_HID, EisaId ("PNP0501"))
+               Name (_UID, 0x01)
+               Method (_STA, 0, NotSerialized)
+               {
+                   Store (\_SB.PCI0.PX13.DRSC, Local0)
+                   And (Local0, 0x08000000, Local0)
+                   If (LEqual (Local0, 0))
+                   {
+                       Return (0x00)
+                   }
+                   Else
+                   {
+                       Return (0x0F)
+                   }
+               }
+               Method (_CRS, 0, NotSerialized)
+               {
+                   Name (BUF0, ResourceTemplate ()
+                    {
+                       IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08)
+                       IRQNoFlags () {4}
+                   })
+                   Return (BUF0)
+               }
+           }
+
+           Device (COM2)
+           {
+               Name (_HID, EisaId ("PNP0501"))
+               Name (_UID, 0x02)
+               Method (_STA, 0, NotSerialized)
+               {
+                   Store (\_SB.PCI0.PX13.DRSC, Local0)
+                   And (Local0, 0x80000000, Local0)
+                   If (LEqual (Local0, 0))
+                   {
+                       Return (0x00)
+                   }
+                   Else
+                   {
+                       Return (0x0F)
+                   }
+               }
+               Method (_CRS, 0, NotSerialized)
+               {
+                   Name (BUF0, ResourceTemplate ()
+                    {
+                       IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08)
+                       IRQNoFlags () {3}
+                   })
+                   Return (BUF0)
+               }
+           }
+        }
+
+       /* PIIX4 PM */
+        Device (PX13) {
+           Name (_ADR, 0x00010003)
+
+           OperationRegion (P13C, PCI_Config, 0x5c, 0x24)
+           Field (P13C, DWordAcc, NoLock, Preserve)
+           {
+               DRSA, 32,
+               DRSB, 32,
+               DRSC, 32,
+               DRSE, 32,
+               DRSF, 32,
+               DRSG, 32,
+               DRSH, 32,
+               DRSI, 32,
+               DRSJ, 32
+           }
+       }
+
+#define gen_pci_device(name, nr)                                \
+        Device(SL##name) {                                      \
+            Name (_ADR, nr##0000)                               \
+            Method (_RMV) {                                     \
+                If (And(\_SB.PCI0.PCRM, ShiftLeft(1, nr))) {    \
+                    Return (0x1)                                \
+                }                                               \
+                Return (0x0)                                    \
+            }                                                   \
+            Name (_SUN, name)                                   \
+        }
+
+        /* VGA (slot 1) and ISA bus (slot 2) defined above */
+       gen_pci_device(3, 0x0003)
+       gen_pci_device(4, 0x0004)
+       gen_pci_device(5, 0x0005)
+       gen_pci_device(6, 0x0006)
+       gen_pci_device(7, 0x0007)
+       gen_pci_device(8, 0x0008)
+       gen_pci_device(9, 0x0009)
+       gen_pci_device(10, 0x000a)
+       gen_pci_device(11, 0x000b)
+       gen_pci_device(12, 0x000c)
+       gen_pci_device(13, 0x000d)
+       gen_pci_device(14, 0x000e)
+       gen_pci_device(15, 0x000f)
+       gen_pci_device(16, 0x0010)
+       gen_pci_device(17, 0x0011)
+       gen_pci_device(18, 0x0012)
+       gen_pci_device(19, 0x0013)
+       gen_pci_device(20, 0x0014)
+       gen_pci_device(21, 0x0015)
+       gen_pci_device(22, 0x0016)
+       gen_pci_device(23, 0x0017)
+       gen_pci_device(24, 0x0018)
+       gen_pci_device(25, 0x0019)
+       gen_pci_device(26, 0x001a)
+       gen_pci_device(27, 0x001b)
+       gen_pci_device(28, 0x001c)
+       gen_pci_device(29, 0x001d)
+       gen_pci_device(30, 0x001e)
+       gen_pci_device(31, 0x001f)
+    }
+
+    /* PCI IRQs */
+    Scope(\_SB) {
+         Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve)
+         {
+             PRQ0,   8,
+             PRQ1,   8,
+             PRQ2,   8,
+             PRQ3,   8
+         }
+
+        Device(LNKA){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 1)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 5, 10, 11 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ0, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ0, 0x80, PRQ0)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {1}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ0, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+                Method (_SRS, 1, NotSerialized)
+                {
+                    CreateDWordField (Arg0, 0x05, TMP)
+                    Store (TMP, PRQ0)
+                }
+        }
+        Device(LNKB){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 2)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 5, 10, 11 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ1, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ1, 0x80, PRQ1)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {1}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ1, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+                Method (_SRS, 1, NotSerialized)
+                {
+                    CreateDWordField (Arg0, 0x05, TMP)
+                    Store (TMP, PRQ1)
+                }
+        }
+        Device(LNKC){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 3)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 5, 10, 11 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ2, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ2, 0x80, PRQ2)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {1}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ2, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+                Method (_SRS, 1, NotSerialized)
+                {
+                    CreateDWordField (Arg0, 0x05, TMP)
+                    Store (TMP, PRQ2)
+                }
+        }
+        Device(LNKD){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 4)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 5, 10, 11 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ3, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ3, 0x80, PRQ3)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {1}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ3, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+                Method (_SRS, 1, NotSerialized)
+                {
+                    CreateDWordField (Arg0, 0x05, TMP)
+                    Store (TMP, PRQ3)
+                }
+        }
+        Device(LNKS){
+                Name(_HID, EISAID("PNP0C0F"))     // PCI interrupt link
+                Name(_UID, 5)
+                Name(_PRS, ResourceTemplate(){
+                    Interrupt (, Level, ActiveHigh, Shared)
+                        { 9 }
+                })
+                Method (_STA, 0, NotSerialized)
+                {
+                    Store (0x0B, Local0)
+                    If (And (0x80, PRQ0, Local1))
+                    {
+                         Store (0x09, Local0)
+                    }
+                    Return (Local0)
+                }
+                Method (_DIS, 0, NotSerialized)
+                {
+                    Or (PRQ0, 0x80, PRQ0)
+                }
+                Method (_CRS, 0, NotSerialized)
+                {
+                    Name (PRR0, ResourceTemplate ()
+                    {
+                        Interrupt (, Level, ActiveHigh, Shared)
+                            {9}
+                    })
+                    CreateDWordField (PRR0, 0x05, TMP)
+                    Store (PRQ0, Local0)
+                    If (LLess (Local0, 0x80))
+                    {
+                        Store (Local0, TMP)
+                    }
+                    Else
+                    {
+                        Store (Zero, TMP)
+                    }
+                    Return (PRR0)
+                }
+        }
+    }
+
+    /*
+     * S3 (suspend-to-ram), S4 (suspend-to-disk) and S5 (power-off) type codes:
+     * must match piix4 emulation.
+     */
+    Name (\_S3, Package (0x04)
+    {
+        0x01,  /* PM1a_CNT.SLP_TYP */
+        0x01,  /* PM1b_CNT.SLP_TYP */
+        Zero,  /* reserved */
+        Zero   /* reserved */
+    })
+    Name (\_S4, Package (0x04)
+    {
+        Zero,  /* PM1a_CNT.SLP_TYP */
+        Zero,  /* 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 */
+    })
+
+    /* 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
+            // 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
+            // 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 = cpuid 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)
+            }
+            Return(One)
+        }
+    }
+
+    Scope (\_GPE)
+    {
+        Name(_HID, "ACPI0006")
+
+        Method(_L00) {
+            Return(0x01)
+        }
+
+#define gen_pci_hotplug(nr)                                       \
+            If (And(\_SB.PCI0.PCIU, ShiftLeft(1, nr))) {          \
+                Notify(\_SB.PCI0.S##nr, 1)                        \
+            }                                                     \
+            If (And(\_SB.PCI0.PCID, ShiftLeft(1, nr))) {          \
+                Notify(\_SB.PCI0.S##nr, 3)                        \
+            }
+
+        Method(_L01) {
+            gen_pci_hotplug(1)
+            gen_pci_hotplug(2)
+            gen_pci_hotplug(3)
+            gen_pci_hotplug(4)
+            gen_pci_hotplug(5)
+            gen_pci_hotplug(6)
+            gen_pci_hotplug(7)
+            gen_pci_hotplug(8)
+            gen_pci_hotplug(9)
+            gen_pci_hotplug(10)
+            gen_pci_hotplug(11)
+            gen_pci_hotplug(12)
+            gen_pci_hotplug(13)
+            gen_pci_hotplug(14)
+            gen_pci_hotplug(15)
+            gen_pci_hotplug(16)
+            gen_pci_hotplug(17)
+            gen_pci_hotplug(18)
+            gen_pci_hotplug(19)
+            gen_pci_hotplug(20)
+            gen_pci_hotplug(21)
+            gen_pci_hotplug(22)
+            gen_pci_hotplug(23)
+            gen_pci_hotplug(24)
+            gen_pci_hotplug(25)
+            gen_pci_hotplug(26)
+            gen_pci_hotplug(27)
+            gen_pci_hotplug(28)
+            gen_pci_hotplug(29)
+            gen_pci_hotplug(30)
+            gen_pci_hotplug(31)
+
+            Return (0x01)
+
+        }
+        Method(_L02) {
+            // CPU hotplug event
+            Return(\_SB.PRSC())
+        }
+        Method(_L03) {
+            Return(0x01)
+        }
+        Method(_L04) {
+            Return(0x01)
+        }
+        Method(_L05) {
+            Return(0x01)
+        }
+        Method(_L06) {
+            Return(0x01)
+        }
+        Method(_L07) {
+            Return(0x01)
+        }
+        Method(_L08) {
+            Return(0x01)
+        }
+        Method(_L09) {
+            Return(0x01)
+        }
+        Method(_L0A) {
+            Return(0x01)
+        }
+        Method(_L0B) {
+            Return(0x01)
+        }
+        Method(_L0C) {
+            Return(0x01)
+        }
+        Method(_L0D) {
+            Return(0x01)
+        }
+        Method(_L0E) {
+            Return(0x01)
+        }
+        Method(_L0F) {
+            Return(0x01)
+        }
+    }
+
+}
diff --git a/bios/seabios/src/acpi-dsdt.hex b/bios/seabios/src/acpi-dsdt.hex
new file mode 100644 (file)
index 0000000..0f3b7cd
--- /dev/null
@@ -0,0 +1,1218 @@
+/*
+ * 
+ * Intel ACPI Component Architecture
+ * ASL Optimizing Compiler version 20100528 [Feb  9 2011]
+ * Copyright (c) 2000 - 2010 Intel Corporation
+ * Supports ACPI Specification Revision 4.0a
+ * 
+ * Compilation of "out/acpi-dsdt.dsl.i" - Tue Jan 22 14:33:33 2013
+ * 
+ * C source code output
+ * AML code block contains 0x2589 bytes
+ *
+ */
+unsigned char AmlCode[] =
+{
+    0x44,0x53,0x44,0x54,0x89,0x25,0x00,0x00,  /* 00000000    "DSDT.%.." */
+    0x01,0x13,0x42,0x58,0x50,0x43,0x00,0x00,  /* 00000008    "..BXPC.." */
+    0x42,0x58,0x44,0x53,0x44,0x54,0x00,0x00,  /* 00000010    "BXDSDT.." */
+    0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C,  /* 00000018    "....INTL" */
+    0x28,0x05,0x10,0x20,0x10,0x49,0x04,0x5C,  /* 00000020    "(.. .I.\" */
+    0x00,0x5B,0x80,0x44,0x42,0x47,0x5F,0x01,  /* 00000028    ".[.DBG_." */
+    0x0B,0x02,0x04,0x01,0x5B,0x81,0x0B,0x44,  /* 00000030    "....[..D" */
+    0x42,0x47,0x5F,0x01,0x44,0x42,0x47,0x42,  /* 00000038    "BG_.DBGB" */
+    0x08,0x14,0x2C,0x44,0x42,0x55,0x47,0x01,  /* 00000040    "..,DBUG." */
+    0x98,0x68,0x60,0x96,0x60,0x60,0x74,0x87,  /* 00000048    ".h`.``t." */
+    0x60,0x01,0x61,0x70,0x00,0x62,0xA2,0x10,  /* 00000050    "`.ap.b.." */
+    0x95,0x62,0x61,0x70,0x83,0x88,0x60,0x62,  /* 00000058    ".bap..`b" */
+    0x00,0x44,0x42,0x47,0x42,0x75,0x62,0x70,  /* 00000060    ".DBGBubp" */
+    0x0A,0x0A,0x44,0x42,0x47,0x42,0x10,0x43,  /* 00000068    "..DBGB.C" */
+    0xD8,0x5F,0x53,0x42,0x5F,0x5B,0x82,0x44,  /* 00000070    "._SB_[.D" */
+    0xD3,0x50,0x43,0x49,0x30,0x08,0x5F,0x48,  /* 00000078    ".PCI0._H" */
+    0x49,0x44,0x0C,0x41,0xD0,0x0A,0x03,0x08,  /* 00000080    "ID.A...." */
+    0x5F,0x41,0x44,0x52,0x00,0x08,0x5F,0x55,  /* 00000088    "_ADR.._U" */
+    0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x54,  /* 00000090    "ID.._PRT" */
+    0x12,0x4B,0x73,0x80,0x12,0x0B,0x04,0x0B,  /* 00000098    ".Ks....." */
+    0xFF,0xFF,0x00,0x4C,0x4E,0x4B,0x44,0x00,  /* 000000A0    "...LNKD." */
+    0x12,0x0B,0x04,0x0B,0xFF,0xFF,0x01,0x4C,  /* 000000A8    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0C,0x04,0x0B,  /* 000000B0    "NKA....." */
+    0xFF,0xFF,0x0A,0x02,0x4C,0x4E,0x4B,0x42,  /* 000000B8    "....LNKB" */
+    0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF,0x0A,  /* 000000C0    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 000000C8    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x01,0x00,0x00,0x4C,  /* 000000D0    ".......L" */
+    0x4E,0x4B,0x53,0x00,0x12,0x0D,0x04,0x0C,  /* 000000D8    "NKS....." */
+    0xFF,0xFF,0x01,0x00,0x01,0x4C,0x4E,0x4B,  /* 000000E0    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 000000E8    "B......." */
+    0x01,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 000000F0    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,  /* 000000F8    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 00000100    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x02,0x00,  /* 00000108    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 00000110    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x02,0x00,0x01,0x4C,  /* 00000118    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 00000120    "NKC....." */
+    0xFF,0xFF,0x02,0x00,0x0A,0x02,0x4C,0x4E,  /* 00000128    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 00000130    "KD......" */
+    0xFF,0x02,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 00000138    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000140    "A......." */
+    0x03,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 00000148    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00,  /* 00000150    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 00000158    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x02,  /* 00000160    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 00000168    "LNKA...." */
+    0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x03,0x4C,  /* 00000170    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 00000178    "NKB....." */
+    0xFF,0xFF,0x04,0x00,0x00,0x4C,0x4E,0x4B,  /* 00000180    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000188    "D......." */
+    0x04,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000190    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x04,0x00,  /* 00000198    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 000001A0    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,  /* 000001A8    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 000001B0    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x05,0x00,0x00,0x4C,  /* 000001B8    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 000001C0    "NKA....." */
+    0xFF,0xFF,0x05,0x00,0x01,0x4C,0x4E,0x4B,  /* 000001C8    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 000001D0    "B......." */
+    0x05,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 000001D8    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,  /* 000001E0    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 000001E8    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x06,0x00,  /* 000001F0    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 000001F8    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x06,0x00,0x01,0x4C,  /* 00000200    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 00000208    "NKC....." */
+    0xFF,0xFF,0x06,0x00,0x0A,0x02,0x4C,0x4E,  /* 00000210    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 00000218    "KD......" */
+    0xFF,0x06,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 00000220    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000228    "A......." */
+    0x07,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 00000230    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x07,0x00,  /* 00000238    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 00000240    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x07,0x00,0x0A,0x02,  /* 00000248    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 00000250    "LNKA...." */
+    0x0C,0xFF,0xFF,0x07,0x00,0x0A,0x03,0x4C,  /* 00000258    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 00000260    "NKB....." */
+    0xFF,0xFF,0x08,0x00,0x00,0x4C,0x4E,0x4B,  /* 00000268    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000270    "D......." */
+    0x08,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000278    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x08,0x00,  /* 00000280    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 00000288    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x08,0x00,0x0A,  /* 00000290    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 00000298    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x09,0x00,0x00,0x4C,  /* 000002A0    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 000002A8    "NKA....." */
+    0xFF,0xFF,0x09,0x00,0x01,0x4C,0x4E,0x4B,  /* 000002B0    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 000002B8    "B......." */
+    0x09,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 000002C0    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x09,  /* 000002C8    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 000002D0    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0A,0x00,  /* 000002D8    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 000002E0    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x0A,0x00,0x01,0x4C,  /* 000002E8    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 000002F0    "NKC....." */
+    0xFF,0xFF,0x0A,0x00,0x0A,0x02,0x4C,0x4E,  /* 000002F8    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 00000300    "KD......" */
+    0xFF,0x0A,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 00000308    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000310    "A......." */
+    0x0B,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 00000318    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0B,0x00,  /* 00000320    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 00000328    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x0B,0x00,0x0A,0x02,  /* 00000330    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 00000338    "LNKA...." */
+    0x0C,0xFF,0xFF,0x0B,0x00,0x0A,0x03,0x4C,  /* 00000340    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 00000348    "NKB....." */
+    0xFF,0xFF,0x0C,0x00,0x00,0x4C,0x4E,0x4B,  /* 00000350    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000358    "D......." */
+    0x0C,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000360    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0C,0x00,  /* 00000368    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 00000370    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x0C,0x00,0x0A,  /* 00000378    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 00000380    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x0D,0x00,0x00,0x4C,  /* 00000388    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 00000390    "NKA....." */
+    0xFF,0xFF,0x0D,0x00,0x01,0x4C,0x4E,0x4B,  /* 00000398    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 000003A0    "B......." */
+    0x0D,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 000003A8    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0D,  /* 000003B0    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 000003B8    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0E,0x00,  /* 000003C0    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 000003C8    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x0E,0x00,0x01,0x4C,  /* 000003D0    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 000003D8    "NKC....." */
+    0xFF,0xFF,0x0E,0x00,0x0A,0x02,0x4C,0x4E,  /* 000003E0    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 000003E8    "KD......" */
+    0xFF,0x0E,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 000003F0    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 000003F8    "A......." */
+    0x0F,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 00000400    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0F,0x00,  /* 00000408    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 00000410    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x0F,0x00,0x0A,0x02,  /* 00000418    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 00000420    "LNKA...." */
+    0x0C,0xFF,0xFF,0x0F,0x00,0x0A,0x03,0x4C,  /* 00000428    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 00000430    "NKB....." */
+    0xFF,0xFF,0x10,0x00,0x00,0x4C,0x4E,0x4B,  /* 00000438    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000440    "D......." */
+    0x10,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000448    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x10,0x00,  /* 00000450    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 00000458    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x10,0x00,0x0A,  /* 00000460    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 00000468    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x11,0x00,0x00,0x4C,  /* 00000470    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 00000478    "NKA....." */
+    0xFF,0xFF,0x11,0x00,0x01,0x4C,0x4E,0x4B,  /* 00000480    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 00000488    "B......." */
+    0x11,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 00000490    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x11,  /* 00000498    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 000004A0    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x12,0x00,  /* 000004A8    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 000004B0    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x12,0x00,0x01,0x4C,  /* 000004B8    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 000004C0    "NKC....." */
+    0xFF,0xFF,0x12,0x00,0x0A,0x02,0x4C,0x4E,  /* 000004C8    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 000004D0    "KD......" */
+    0xFF,0x12,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 000004D8    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 000004E0    "A......." */
+    0x13,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 000004E8    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x13,0x00,  /* 000004F0    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 000004F8    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x13,0x00,0x0A,0x02,  /* 00000500    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 00000508    "LNKA...." */
+    0x0C,0xFF,0xFF,0x13,0x00,0x0A,0x03,0x4C,  /* 00000510    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 00000518    "NKB....." */
+    0xFF,0xFF,0x14,0x00,0x00,0x4C,0x4E,0x4B,  /* 00000520    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000528    "D......." */
+    0x14,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000530    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x14,0x00,  /* 00000538    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 00000540    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x14,0x00,0x0A,  /* 00000548    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 00000550    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x15,0x00,0x00,0x4C,  /* 00000558    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 00000560    "NKA....." */
+    0xFF,0xFF,0x15,0x00,0x01,0x4C,0x4E,0x4B,  /* 00000568    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 00000570    "B......." */
+    0x15,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 00000578    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x15,  /* 00000580    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 00000588    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x16,0x00,  /* 00000590    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 00000598    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x16,0x00,0x01,0x4C,  /* 000005A0    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 000005A8    "NKC....." */
+    0xFF,0xFF,0x16,0x00,0x0A,0x02,0x4C,0x4E,  /* 000005B0    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 000005B8    "KD......" */
+    0xFF,0x16,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 000005C0    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 000005C8    "A......." */
+    0x17,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 000005D0    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x17,0x00,  /* 000005D8    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 000005E0    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x17,0x00,0x0A,0x02,  /* 000005E8    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 000005F0    "LNKA...." */
+    0x0C,0xFF,0xFF,0x17,0x00,0x0A,0x03,0x4C,  /* 000005F8    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 00000600    "NKB....." */
+    0xFF,0xFF,0x18,0x00,0x00,0x4C,0x4E,0x4B,  /* 00000608    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000610    "D......." */
+    0x18,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000618    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x18,0x00,  /* 00000620    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 00000628    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x18,0x00,0x0A,  /* 00000630    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 00000638    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x19,0x00,0x00,0x4C,  /* 00000640    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 00000648    "NKA....." */
+    0xFF,0xFF,0x19,0x00,0x01,0x4C,0x4E,0x4B,  /* 00000650    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 00000658    "B......." */
+    0x19,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 00000660    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x19,  /* 00000668    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 00000670    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1A,0x00,  /* 00000678    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 00000680    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x1A,0x00,0x01,0x4C,  /* 00000688    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 00000690    "NKC....." */
+    0xFF,0xFF,0x1A,0x00,0x0A,0x02,0x4C,0x4E,  /* 00000698    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 000006A0    "KD......" */
+    0xFF,0x1A,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 000006A8    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 000006B0    "A......." */
+    0x1B,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 000006B8    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1B,0x00,  /* 000006C0    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 000006C8    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x1B,0x00,0x0A,0x02,  /* 000006D0    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 000006D8    "LNKA...." */
+    0x0C,0xFF,0xFF,0x1B,0x00,0x0A,0x03,0x4C,  /* 000006E0    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C,  /* 000006E8    "NKB....." */
+    0xFF,0xFF,0x1C,0x00,0x00,0x4C,0x4E,0x4B,  /* 000006F0    ".....LNK" */
+    0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 000006F8    "D......." */
+    0x1C,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00,  /* 00000700    "...LNKA." */
+    0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x1C,0x00,  /* 00000708    "........" */
+    0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12,  /* 00000710    "..LNKB.." */
+    0x0E,0x04,0x0C,0xFF,0xFF,0x1C,0x00,0x0A,  /* 00000718    "........" */
+    0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D,  /* 00000720    ".LNKC..." */
+    0x04,0x0C,0xFF,0xFF,0x1D,0x00,0x00,0x4C,  /* 00000728    ".......L" */
+    0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,  /* 00000730    "NKA....." */
+    0xFF,0xFF,0x1D,0x00,0x01,0x4C,0x4E,0x4B,  /* 00000738    ".....LNK" */
+    0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,  /* 00000740    "B......." */
+    0x1D,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43,  /* 00000748    "....LNKC" */
+    0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x1D,  /* 00000750    "........" */
+    0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00,  /* 00000758    "...LNKD." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1E,0x00,  /* 00000760    "........" */
+    0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,  /* 00000768    ".LNKB..." */
+    0x04,0x0C,0xFF,0xFF,0x1E,0x00,0x01,0x4C,  /* 00000770    ".......L" */
+    0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,  /* 00000778    "NKC....." */
+    0xFF,0xFF,0x1E,0x00,0x0A,0x02,0x4C,0x4E,  /* 00000780    "......LN" */
+    0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,  /* 00000788    "KD......" */
+    0xFF,0x1E,0x00,0x0A,0x03,0x4C,0x4E,0x4B,  /* 00000790    ".....LNK" */
+    0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,  /* 00000798    "A......." */
+    0x1F,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00,  /* 000007A0    "...LNKC." */
+    0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1F,0x00,  /* 000007A8    "........" */
+    0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,  /* 000007B0    ".LNKD..." */
+    0x04,0x0C,0xFF,0xFF,0x1F,0x00,0x0A,0x02,  /* 000007B8    "........" */
+    0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,  /* 000007C0    "LNKA...." */
+    0x0C,0xFF,0xFF,0x1F,0x00,0x0A,0x03,0x4C,  /* 000007C8    ".......L" */
+    0x4E,0x4B,0x42,0x00,0x5B,0x80,0x50,0x43,  /* 000007D0    "NKB.[.PC" */
+    0x53,0x54,0x01,0x0B,0x00,0xAE,0x0A,0x08,  /* 000007D8    "ST......" */
+    0x5B,0x81,0x10,0x50,0x43,0x53,0x54,0x43,  /* 000007E0    "[..PCSTC" */
+    0x50,0x43,0x49,0x55,0x20,0x50,0x43,0x49,  /* 000007E8    "PCIU PCI" */
+    0x44,0x20,0x5B,0x80,0x53,0x45,0x4A,0x5F,  /* 000007F0    "D [.SEJ_" */
+    0x01,0x0B,0x08,0xAE,0x0A,0x04,0x5B,0x81,  /* 000007F8    "......[." */
+    0x0B,0x53,0x45,0x4A,0x5F,0x43,0x42,0x30,  /* 00000800    ".SEJ_CB0" */
+    0x45,0x4A,0x20,0x5B,0x80,0x52,0x4D,0x56,  /* 00000808    "EJ [.RMV" */
+    0x43,0x01,0x0B,0x0C,0xAE,0x0A,0x04,0x5B,  /* 00000810    "C......[" */
+    0x81,0x0B,0x52,0x4D,0x56,0x43,0x43,0x50,  /* 00000818    "..RMVCCP" */
+    0x43,0x52,0x4D,0x20,0x5B,0x82,0x25,0x53,  /* 00000820    "CRM [.%S" */
+    0x31,0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,  /* 00000828    "1__._ADR" */
+    0x0C,0x00,0x00,0x01,0x00,0x14,0x0F,0x5F,  /* 00000830    "......._" */
+    0x45,0x4A,0x30,0x01,0x70,0x0A,0x02,0x42,  /* 00000838    "EJ0.p..B" */
+    0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,  /* 00000840    "0EJ..._S" */
+    0x55,0x4E,0x01,0x5B,0x82,0x26,0x53,0x32,  /* 00000848    "UN.[.&S2" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00000850    "__._ADR." */
+    0x00,0x00,0x02,0x00,0x14,0x0F,0x5F,0x45,  /* 00000858    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0A,0x04,0x42,0x30,  /* 00000860    "J0.p..B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000868    "EJ..._SU" */
+    0x4E,0x0A,0x02,0x5B,0x82,0x26,0x53,0x33,  /* 00000870    "N..[.&S3" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00000878    "__._ADR." */
+    0x00,0x00,0x03,0x00,0x14,0x0F,0x5F,0x45,  /* 00000880    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0A,0x08,0x42,0x30,  /* 00000888    "J0.p..B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000890    "EJ..._SU" */
+    0x4E,0x0A,0x03,0x5B,0x82,0x26,0x53,0x34,  /* 00000898    "N..[.&S4" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000008A0    "__._ADR." */
+    0x00,0x00,0x04,0x00,0x14,0x0F,0x5F,0x45,  /* 000008A8    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0A,0x10,0x42,0x30,  /* 000008B0    "J0.p..B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 000008B8    "EJ..._SU" */
+    0x4E,0x0A,0x04,0x5B,0x82,0x26,0x53,0x35,  /* 000008C0    "N..[.&S5" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000008C8    "__._ADR." */
+    0x00,0x00,0x05,0x00,0x14,0x0F,0x5F,0x45,  /* 000008D0    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0A,0x20,0x42,0x30,  /* 000008D8    "J0.p. B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 000008E0    "EJ..._SU" */
+    0x4E,0x0A,0x05,0x5B,0x82,0x26,0x53,0x36,  /* 000008E8    "N..[.&S6" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000008F0    "__._ADR." */
+    0x00,0x00,0x06,0x00,0x14,0x0F,0x5F,0x45,  /* 000008F8    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0A,0x40,0x42,0x30,  /* 00000900    "J0.p.@B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000908    "EJ..._SU" */
+    0x4E,0x0A,0x06,0x5B,0x82,0x26,0x53,0x37,  /* 00000910    "N..[.&S7" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00000918    "__._ADR." */
+    0x00,0x00,0x07,0x00,0x14,0x0F,0x5F,0x45,  /* 00000920    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0A,0x80,0x42,0x30,  /* 00000928    "J0.p..B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000930    "EJ..._SU" */
+    0x4E,0x0A,0x07,0x5B,0x82,0x27,0x53,0x38,  /* 00000938    "N..[.'S8" */
+    0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00000940    "__._ADR." */
+    0x00,0x00,0x08,0x00,0x14,0x10,0x5F,0x45,  /* 00000948    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0B,0x00,0x01,0x42,  /* 00000950    "J0.p...B" */
+    0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,  /* 00000958    "0EJ..._S" */
+    0x55,0x4E,0x0A,0x08,0x5B,0x82,0x27,0x53,  /* 00000960    "UN..[.'S" */
+    0x39,0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,  /* 00000968    "9__._ADR" */
+    0x0C,0x00,0x00,0x09,0x00,0x14,0x10,0x5F,  /* 00000970    "......._" */
+    0x45,0x4A,0x30,0x01,0x70,0x0B,0x00,0x02,  /* 00000978    "EJ0.p..." */
+    0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,  /* 00000980    "B0EJ..._" */
+    0x53,0x55,0x4E,0x0A,0x09,0x5B,0x82,0x27,  /* 00000988    "SUN..[.'" */
+    0x53,0x31,0x30,0x5F,0x08,0x5F,0x41,0x44,  /* 00000990    "S10_._AD" */
+    0x52,0x0C,0x00,0x00,0x0A,0x00,0x14,0x10,  /* 00000998    "R......." */
+    0x5F,0x45,0x4A,0x30,0x01,0x70,0x0B,0x00,  /* 000009A0    "_EJ0.p.." */
+    0x04,0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,  /* 000009A8    ".B0EJ..." */
+    0x5F,0x53,0x55,0x4E,0x0A,0x0A,0x5B,0x82,  /* 000009B0    "_SUN..[." */
+    0x27,0x53,0x31,0x31,0x5F,0x08,0x5F,0x41,  /* 000009B8    "'S11_._A" */
+    0x44,0x52,0x0C,0x00,0x00,0x0B,0x00,0x14,  /* 000009C0    "DR......" */
+    0x10,0x5F,0x45,0x4A,0x30,0x01,0x70,0x0B,  /* 000009C8    "._EJ0.p." */
+    0x00,0x08,0x42,0x30,0x45,0x4A,0xA4,0x00,  /* 000009D0    "..B0EJ.." */
+    0x08,0x5F,0x53,0x55,0x4E,0x0A,0x0B,0x5B,  /* 000009D8    "._SUN..[" */
+    0x82,0x27,0x53,0x31,0x32,0x5F,0x08,0x5F,  /* 000009E0    ".'S12_._" */
+    0x41,0x44,0x52,0x0C,0x00,0x00,0x0C,0x00,  /* 000009E8    "ADR....." */
+    0x14,0x10,0x5F,0x45,0x4A,0x30,0x01,0x70,  /* 000009F0    ".._EJ0.p" */
+    0x0B,0x00,0x10,0x42,0x30,0x45,0x4A,0xA4,  /* 000009F8    "...B0EJ." */
+    0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x0C,  /* 00000A00    ".._SUN.." */
+    0x5B,0x82,0x27,0x53,0x31,0x33,0x5F,0x08,  /* 00000A08    "[.'S13_." */
+    0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x0D,  /* 00000A10    "_ADR...." */
+    0x00,0x14,0x10,0x5F,0x45,0x4A,0x30,0x01,  /* 00000A18    "..._EJ0." */
+    0x70,0x0B,0x00,0x20,0x42,0x30,0x45,0x4A,  /* 00000A20    "p.. B0EJ" */
+    0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,  /* 00000A28    "..._SUN." */
+    0x0D,0x5B,0x82,0x27,0x53,0x31,0x34,0x5F,  /* 00000A30    ".[.'S14_" */
+    0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,  /* 00000A38    "._ADR..." */
+    0x0E,0x00,0x14,0x10,0x5F,0x45,0x4A,0x30,  /* 00000A40    "...._EJ0" */
+    0x01,0x70,0x0B,0x00,0x40,0x42,0x30,0x45,  /* 00000A48    ".p..@B0E" */
+    0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,  /* 00000A50    "J..._SUN" */
+    0x0A,0x0E,0x5B,0x82,0x27,0x53,0x31,0x35,  /* 00000A58    "..[.'S15" */
+    0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,  /* 00000A60    "_._ADR.." */
+    0x00,0x0F,0x00,0x14,0x10,0x5F,0x45,0x4A,  /* 00000A68    "....._EJ" */
+    0x30,0x01,0x70,0x0B,0x00,0x80,0x42,0x30,  /* 00000A70    "0.p...B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000A78    "EJ..._SU" */
+    0x4E,0x0A,0x0F,0x5B,0x82,0x29,0x53,0x31,  /* 00000A80    "N..[.)S1" */
+    0x36,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00000A88    "6_._ADR." */
+    0x00,0x00,0x10,0x00,0x14,0x12,0x5F,0x45,  /* 00000A90    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0C,0x00,0x00,0x01,  /* 00000A98    "J0.p...." */
+    0x00,0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,  /* 00000AA0    ".B0EJ..." */
+    0x5F,0x53,0x55,0x4E,0x0A,0x10,0x5B,0x82,  /* 00000AA8    "_SUN..[." */
+    0x29,0x53,0x31,0x37,0x5F,0x08,0x5F,0x41,  /* 00000AB0    ")S17_._A" */
+    0x44,0x52,0x0C,0x00,0x00,0x11,0x00,0x14,  /* 00000AB8    "DR......" */
+    0x12,0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C,  /* 00000AC0    "._EJ0.p." */
+    0x00,0x00,0x02,0x00,0x42,0x30,0x45,0x4A,  /* 00000AC8    "....B0EJ" */
+    0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,  /* 00000AD0    "..._SUN." */
+    0x11,0x5B,0x82,0x29,0x53,0x31,0x38,0x5F,  /* 00000AD8    ".[.)S18_" */
+    0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,  /* 00000AE0    "._ADR..." */
+    0x12,0x00,0x14,0x12,0x5F,0x45,0x4A,0x30,  /* 00000AE8    "...._EJ0" */
+    0x01,0x70,0x0C,0x00,0x00,0x04,0x00,0x42,  /* 00000AF0    ".p.....B" */
+    0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,  /* 00000AF8    "0EJ..._S" */
+    0x55,0x4E,0x0A,0x12,0x5B,0x82,0x29,0x53,  /* 00000B00    "UN..[.)S" */
+    0x31,0x39,0x5F,0x08,0x5F,0x41,0x44,0x52,  /* 00000B08    "19_._ADR" */
+    0x0C,0x00,0x00,0x13,0x00,0x14,0x12,0x5F,  /* 00000B10    "......._" */
+    0x45,0x4A,0x30,0x01,0x70,0x0C,0x00,0x00,  /* 00000B18    "EJ0.p..." */
+    0x08,0x00,0x42,0x30,0x45,0x4A,0xA4,0x00,  /* 00000B20    "..B0EJ.." */
+    0x08,0x5F,0x53,0x55,0x4E,0x0A,0x13,0x5B,  /* 00000B28    "._SUN..[" */
+    0x82,0x29,0x53,0x32,0x30,0x5F,0x08,0x5F,  /* 00000B30    ".)S20_._" */
+    0x41,0x44,0x52,0x0C,0x00,0x00,0x14,0x00,  /* 00000B38    "ADR....." */
+    0x14,0x12,0x5F,0x45,0x4A,0x30,0x01,0x70,  /* 00000B40    ".._EJ0.p" */
+    0x0C,0x00,0x00,0x10,0x00,0x42,0x30,0x45,  /* 00000B48    ".....B0E" */
+    0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,  /* 00000B50    "J..._SUN" */
+    0x0A,0x14,0x5B,0x82,0x29,0x53,0x32,0x31,  /* 00000B58    "..[.)S21" */
+    0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,  /* 00000B60    "_._ADR.." */
+    0x00,0x15,0x00,0x14,0x12,0x5F,0x45,0x4A,  /* 00000B68    "....._EJ" */
+    0x30,0x01,0x70,0x0C,0x00,0x00,0x20,0x00,  /* 00000B70    "0.p... ." */
+    0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,  /* 00000B78    "B0EJ..._" */
+    0x53,0x55,0x4E,0x0A,0x15,0x5B,0x82,0x29,  /* 00000B80    "SUN..[.)" */
+    0x53,0x32,0x32,0x5F,0x08,0x5F,0x41,0x44,  /* 00000B88    "S22_._AD" */
+    0x52,0x0C,0x00,0x00,0x16,0x00,0x14,0x12,  /* 00000B90    "R......." */
+    0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C,0x00,  /* 00000B98    "_EJ0.p.." */
+    0x00,0x40,0x00,0x42,0x30,0x45,0x4A,0xA4,  /* 00000BA0    ".@.B0EJ." */
+    0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x16,  /* 00000BA8    ".._SUN.." */
+    0x5B,0x82,0x29,0x53,0x32,0x33,0x5F,0x08,  /* 00000BB0    "[.)S23_." */
+    0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x17,  /* 00000BB8    "_ADR...." */
+    0x00,0x14,0x12,0x5F,0x45,0x4A,0x30,0x01,  /* 00000BC0    "..._EJ0." */
+    0x70,0x0C,0x00,0x00,0x80,0x00,0x42,0x30,  /* 00000BC8    "p.....B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000BD0    "EJ..._SU" */
+    0x4E,0x0A,0x17,0x5B,0x82,0x29,0x53,0x32,  /* 00000BD8    "N..[.)S2" */
+    0x34,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 00000BE0    "4_._ADR." */
+    0x00,0x00,0x18,0x00,0x14,0x12,0x5F,0x45,  /* 00000BE8    "......_E" */
+    0x4A,0x30,0x01,0x70,0x0C,0x00,0x00,0x00,  /* 00000BF0    "J0.p...." */
+    0x01,0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,  /* 00000BF8    ".B0EJ..." */
+    0x5F,0x53,0x55,0x4E,0x0A,0x18,0x5B,0x82,  /* 00000C00    "_SUN..[." */
+    0x29,0x53,0x32,0x35,0x5F,0x08,0x5F,0x41,  /* 00000C08    ")S25_._A" */
+    0x44,0x52,0x0C,0x00,0x00,0x19,0x00,0x14,  /* 00000C10    "DR......" */
+    0x12,0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C,  /* 00000C18    "._EJ0.p." */
+    0x00,0x00,0x00,0x02,0x42,0x30,0x45,0x4A,  /* 00000C20    "....B0EJ" */
+    0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,  /* 00000C28    "..._SUN." */
+    0x19,0x5B,0x82,0x29,0x53,0x32,0x36,0x5F,  /* 00000C30    ".[.)S26_" */
+    0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,  /* 00000C38    "._ADR..." */
+    0x1A,0x00,0x14,0x12,0x5F,0x45,0x4A,0x30,  /* 00000C40    "...._EJ0" */
+    0x01,0x70,0x0C,0x00,0x00,0x00,0x04,0x42,  /* 00000C48    ".p.....B" */
+    0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,  /* 00000C50    "0EJ..._S" */
+    0x55,0x4E,0x0A,0x1A,0x5B,0x82,0x29,0x53,  /* 00000C58    "UN..[.)S" */
+    0x32,0x37,0x5F,0x08,0x5F,0x41,0x44,0x52,  /* 00000C60    "27_._ADR" */
+    0x0C,0x00,0x00,0x1B,0x00,0x14,0x12,0x5F,  /* 00000C68    "......._" */
+    0x45,0x4A,0x30,0x01,0x70,0x0C,0x00,0x00,  /* 00000C70    "EJ0.p..." */
+    0x00,0x08,0x42,0x30,0x45,0x4A,0xA4,0x00,  /* 00000C78    "..B0EJ.." */
+    0x08,0x5F,0x53,0x55,0x4E,0x0A,0x1B,0x5B,  /* 00000C80    "._SUN..[" */
+    0x82,0x29,0x53,0x32,0x38,0x5F,0x08,0x5F,  /* 00000C88    ".)S28_._" */
+    0x41,0x44,0x52,0x0C,0x00,0x00,0x1C,0x00,  /* 00000C90    "ADR....." */
+    0x14,0x12,0x5F,0x45,0x4A,0x30,0x01,0x70,  /* 00000C98    ".._EJ0.p" */
+    0x0C,0x00,0x00,0x00,0x10,0x42,0x30,0x45,  /* 00000CA0    ".....B0E" */
+    0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,  /* 00000CA8    "J..._SUN" */
+    0x0A,0x1C,0x5B,0x82,0x29,0x53,0x32,0x39,  /* 00000CB0    "..[.)S29" */
+    0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,  /* 00000CB8    "_._ADR.." */
+    0x00,0x1D,0x00,0x14,0x12,0x5F,0x45,0x4A,  /* 00000CC0    "....._EJ" */
+    0x30,0x01,0x70,0x0C,0x00,0x00,0x00,0x20,  /* 00000CC8    "0.p.... " */
+    0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,  /* 00000CD0    "B0EJ..._" */
+    0x53,0x55,0x4E,0x0A,0x1D,0x5B,0x82,0x29,  /* 00000CD8    "SUN..[.)" */
+    0x53,0x33,0x30,0x5F,0x08,0x5F,0x41,0x44,  /* 00000CE0    "S30_._AD" */
+    0x52,0x0C,0x00,0x00,0x1E,0x00,0x14,0x12,  /* 00000CE8    "R......." */
+    0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C,0x00,  /* 00000CF0    "_EJ0.p.." */
+    0x00,0x00,0x40,0x42,0x30,0x45,0x4A,0xA4,  /* 00000CF8    "..@B0EJ." */
+    0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x1E,  /* 00000D00    ".._SUN.." */
+    0x5B,0x82,0x29,0x53,0x33,0x31,0x5F,0x08,  /* 00000D08    "[.)S31_." */
+    0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x1F,  /* 00000D10    "_ADR...." */
+    0x00,0x14,0x12,0x5F,0x45,0x4A,0x30,0x01,  /* 00000D18    "..._EJ0." */
+    0x70,0x0C,0x00,0x00,0x00,0x80,0x42,0x30,  /* 00000D20    "p.....B0" */
+    0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,  /* 00000D28    "EJ..._SU" */
+    0x4E,0x0A,0x1F,0x08,0x5F,0x43,0x52,0x53,  /* 00000D30    "N..._CRS" */
+    0x11,0x42,0x07,0x0A,0x6E,0x88,0x0D,0x00,  /* 00000D38    ".B..n..." */
+    0x02,0x0C,0x00,0x00,0x00,0x00,0x00,0xFF,  /* 00000D40    "........" */
+    0x00,0x00,0x00,0x00,0x01,0x47,0x01,0xF8,  /* 00000D48    ".....G.." */
+    0x0C,0xF8,0x0C,0x01,0x08,0x88,0x0D,0x00,  /* 00000D50    "........" */
+    0x01,0x0C,0x03,0x00,0x00,0x00,0x00,0xF7,  /* 00000D58    "........" */
+    0x0C,0x00,0x00,0xF8,0x0C,0x88,0x0D,0x00,  /* 00000D60    "........" */
+    0x01,0x0C,0x03,0x00,0x00,0x00,0x0D,0xFF,  /* 00000D68    "........" */
+    0xFF,0x00,0x00,0x00,0xF3,0x87,0x17,0x00,  /* 00000D70    "........" */
+    0x00,0x0C,0x03,0x00,0x00,0x00,0x00,0x00,  /* 00000D78    "........" */
+    0x00,0x0A,0x00,0xFF,0xFF,0x0B,0x00,0x00,  /* 00000D80    "........" */
+    0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x87,  /* 00000D88    "........" */
+    0x17,0x00,0x00,0x0C,0x01,0x00,0x00,0x00,  /* 00000D90    "........" */
+    0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0xBF,  /* 00000D98    "........" */
+    0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,  /* 00000DA0    "........" */
+    0x1E,0x79,0x00,0x5B,0x82,0x45,0x04,0x48,  /* 00000DA8    ".y.[.E.H" */
+    0x50,0x45,0x54,0x08,0x5F,0x48,0x49,0x44,  /* 00000DB0    "PET._HID" */
+    0x0C,0x41,0xD0,0x01,0x03,0x08,0x5F,0x55,  /* 00000DB8    ".A...._U" */
+    0x49,0x44,0x00,0x14,0x09,0x5F,0x53,0x54,  /* 00000DC0    "ID..._ST" */
+    0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43,  /* 00000DC8    "A....._C" */
+    0x52,0x53,0x11,0x1F,0x0A,0x1C,0x87,0x17,  /* 00000DD0    "RS......" */
+    0x00,0x00,0x0D,0x01,0x00,0x00,0x00,0x00,  /* 00000DD8    "........" */
+    0x00,0x00,0xD0,0xFE,0xFF,0x03,0xD0,0xFE,  /* 00000DE0    "........" */
+    0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,  /* 00000DE8    "........" */
+    0x79,0x00,0x10,0x49,0x84,0x2E,0x5F,0x53,  /* 00000DF0    "y..I.._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x5B,0x82,  /* 00000DF8    "B_PCI0[." */
+    0x4C,0x05,0x56,0x47,0x41,0x5F,0x08,0x5F,  /* 00000E00    "L.VGA_._" */
+    0x41,0x44,0x52,0x0C,0x00,0x00,0x02,0x00,  /* 00000E08    "ADR....." */
+    0x5B,0x80,0x50,0x43,0x49,0x43,0x02,0x00,  /* 00000E10    "[.PCIC.." */
+    0x0A,0x04,0x5B,0x81,0x0B,0x50,0x43,0x49,  /* 00000E18    "..[..PCI" */
+    0x43,0x03,0x56,0x45,0x4E,0x44,0x20,0x14,  /* 00000E20    "C.VEND ." */
+    0x08,0x5F,0x53,0x31,0x44,0x00,0xA4,0x00,  /* 00000E28    "._S1D..." */
+    0x14,0x08,0x5F,0x53,0x32,0x44,0x00,0xA4,  /* 00000E30    ".._S2D.." */
+    0x00,0x14,0x19,0x5F,0x53,0x33,0x44,0x00,  /* 00000E38    "..._S3D." */
+    0xA0,0x0E,0x93,0x56,0x45,0x4E,0x44,0x0C,  /* 00000E40    "...VEND." */
+    0x36,0x1B,0x00,0x01,0xA4,0x0A,0x03,0xA1,  /* 00000E48    "6......." */
+    0x03,0xA4,0x00,0x14,0x08,0x5F,0x52,0x4D,  /* 00000E50    "....._RM" */
+    0x56,0x00,0xA4,0x00,0x5B,0x82,0x4B,0x23,  /* 00000E58    "V...[.K#" */
+    0x49,0x53,0x41,0x5F,0x08,0x5F,0x41,0x44,  /* 00000E60    "ISA_._AD" */
+    0x52,0x0C,0x00,0x00,0x01,0x00,0x14,0x08,  /* 00000E68    "R......." */
+    0x5F,0x52,0x4D,0x56,0x00,0xA4,0x00,0x5B,  /* 00000E70    "_RMV...[" */
+    0x80,0x50,0x34,0x30,0x43,0x02,0x0A,0x60,  /* 00000E78    ".P40C..`" */
+    0x0A,0x04,0x5B,0x82,0x2D,0x52,0x54,0x43,  /* 00000E80    "..[.-RTC" */
+    0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,  /* 00000E88    "_._HID.A" */
+    0xD0,0x0B,0x00,0x08,0x5F,0x43,0x52,0x53,  /* 00000E90    "...._CRS" */
+    0x11,0x18,0x0A,0x15,0x47,0x01,0x70,0x00,  /* 00000E98    "....G.p." */
+    0x70,0x00,0x10,0x02,0x22,0x00,0x01,0x47,  /* 00000EA0    "p..."..G" */
+    0x01,0x72,0x00,0x72,0x00,0x02,0x06,0x79,  /* 00000EA8    ".r.r...y" */
+    0x00,0x5B,0x82,0x44,0x04,0x4B,0x42,0x44,  /* 00000EB0    ".[.D.KBD" */
+    0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,  /* 00000EB8    "_._HID.A" */
+    0xD0,0x03,0x03,0x14,0x09,0x5F,0x53,0x54,  /* 00000EC0    "....._ST" */
+    0x41,0x00,0xA4,0x0A,0x0F,0x14,0x29,0x5F,  /* 00000EC8    "A.....)_" */
+    0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50,  /* 00000ED0    "CRS..TMP" */
+    0x5F,0x11,0x18,0x0A,0x15,0x47,0x01,0x60,  /* 00000ED8    "_....G.`" */
+    0x00,0x60,0x00,0x01,0x01,0x47,0x01,0x64,  /* 00000EE0    ".`...G.d" */
+    0x00,0x64,0x00,0x01,0x01,0x22,0x02,0x00,  /* 00000EE8    ".d...".." */
+    0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B,  /* 00000EF0    "y..TMP_[" */
+    0x82,0x33,0x4D,0x4F,0x55,0x5F,0x08,0x5F,  /* 00000EF8    ".3MOU_._" */
+    0x48,0x49,0x44,0x0C,0x41,0xD0,0x0F,0x13,  /* 00000F00    "HID.A..." */
+    0x14,0x09,0x5F,0x53,0x54,0x41,0x00,0xA4,  /* 00000F08    ".._STA.." */
+    0x0A,0x0F,0x14,0x19,0x5F,0x43,0x52,0x53,  /* 00000F10    "...._CRS" */
+    0x00,0x08,0x54,0x4D,0x50,0x5F,0x11,0x08,  /* 00000F18    "..TMP_.." */
+    0x0A,0x05,0x22,0x00,0x10,0x79,0x00,0xA4,  /* 00000F20    ".."..y.." */
+    0x54,0x4D,0x50,0x5F,0x5B,0x82,0x47,0x04,  /* 00000F28    "TMP_[.G." */
+    0x46,0x44,0x43,0x30,0x08,0x5F,0x48,0x49,  /* 00000F30    "FDC0._HI" */
+    0x44,0x0C,0x41,0xD0,0x07,0x00,0x14,0x09,  /* 00000F38    "D.A....." */
+    0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F,  /* 00000F40    "_STA...." */
+    0x14,0x2C,0x5F,0x43,0x52,0x53,0x00,0x08,  /* 00000F48    ".,_CRS.." */
+    0x42,0x55,0x46,0x30,0x11,0x1B,0x0A,0x18,  /* 00000F50    "BUF0...." */
+    0x47,0x01,0xF2,0x03,0xF2,0x03,0x00,0x04,  /* 00000F58    "G......." */
+    0x47,0x01,0xF7,0x03,0xF7,0x03,0x00,0x01,  /* 00000F60    "G......." */
+    0x22,0x40,0x00,0x2A,0x04,0x00,0x79,0x00,  /* 00000F68    ""@.*..y." */
+    0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x4B,  /* 00000F70    ".BUF0[.K" */
+    0x05,0x4C,0x50,0x54,0x5F,0x08,0x5F,0x48,  /* 00000F78    ".LPT_._H" */
+    0x49,0x44,0x0C,0x41,0xD0,0x04,0x00,0x14,  /* 00000F80    "ID.A...." */
+    0x28,0x5F,0x53,0x54,0x41,0x00,0x70,0x5E,  /* 00000F88    "(_STA.p^" */
+    0x5E,0x5E,0x2E,0x50,0x58,0x31,0x33,0x44,  /* 00000F90    "^^.PX13D" */
+    0x52,0x53,0x41,0x60,0x7B,0x60,0x0C,0x00,  /* 00000F98    "RSA`{`.." */
+    0x00,0x00,0x80,0x60,0xA0,0x06,0x93,0x60,  /* 00000FA0    "...`...`" */
+    0x00,0xA4,0x00,0xA1,0x04,0xA4,0x0A,0x0F,  /* 00000FA8    "........" */
+    0x14,0x21,0x5F,0x43,0x52,0x53,0x00,0x08,  /* 00000FB0    ".!_CRS.." */
+    0x42,0x55,0x46,0x30,0x11,0x10,0x0A,0x0D,  /* 00000FB8    "BUF0...." */
+    0x47,0x01,0x78,0x03,0x78,0x03,0x08,0x08,  /* 00000FC0    "G.x.x..." */
+    0x22,0x80,0x00,0x79,0x00,0xA4,0x42,0x55,  /* 00000FC8    ""..y..BU" */
+    0x46,0x30,0x5B,0x82,0x41,0x06,0x43,0x4F,  /* 00000FD0    "F0[.A.CO" */
+    0x4D,0x31,0x08,0x5F,0x48,0x49,0x44,0x0C,  /* 00000FD8    "M1._HID." */
+    0x41,0xD0,0x05,0x01,0x08,0x5F,0x55,0x49,  /* 00000FE0    "A...._UI" */
+    0x44,0x01,0x14,0x28,0x5F,0x53,0x54,0x41,  /* 00000FE8    "D..(_STA" */
+    0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58,  /* 00000FF0    ".p^^^.PX" */
+    0x31,0x33,0x44,0x52,0x53,0x43,0x60,0x7B,  /* 00000FF8    "13DRSC`{" */
+    0x60,0x0C,0x00,0x00,0x00,0x08,0x60,0xA0,  /* 00001000    "`.....`." */
+    0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04,  /* 00001008    "..`....." */
+    0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52,  /* 00001010    "....!_CR" */
+    0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11,  /* 00001018    "S..BUF0." */
+    0x10,0x0A,0x0D,0x47,0x01,0xF8,0x03,0xF8,  /* 00001020    "...G...." */
+    0x03,0x00,0x08,0x22,0x10,0x00,0x79,0x00,  /* 00001028    "..."..y." */
+    0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x42,  /* 00001030    ".BUF0[.B" */
+    0x06,0x43,0x4F,0x4D,0x32,0x08,0x5F,0x48,  /* 00001038    ".COM2._H" */
+    0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08,  /* 00001040    "ID.A...." */
+    0x5F,0x55,0x49,0x44,0x0A,0x02,0x14,0x28,  /* 00001048    "_UID...(" */
+    0x5F,0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,  /* 00001050    "_STA.p^^" */
+    0x5E,0x2E,0x50,0x58,0x31,0x33,0x44,0x52,  /* 00001058    "^.PX13DR" */
+    0x53,0x43,0x60,0x7B,0x60,0x0C,0x00,0x00,  /* 00001060    "SC`{`..." */
+    0x00,0x80,0x60,0xA0,0x06,0x93,0x60,0x00,  /* 00001068    "..`...`." */
+    0xA4,0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,  /* 00001070    "........" */
+    0x21,0x5F,0x43,0x52,0x53,0x00,0x08,0x42,  /* 00001078    "!_CRS..B" */
+    0x55,0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,  /* 00001080    "UF0....G" */
+    0x01,0xF8,0x02,0xF8,0x02,0x00,0x08,0x22,  /* 00001088    "......."" */
+    0x08,0x00,0x79,0x00,0xA4,0x42,0x55,0x46,  /* 00001090    "..y..BUF" */
+    0x30,0x5B,0x82,0x40,0x05,0x50,0x58,0x31,  /* 00001098    "0[.@.PX1" */
+    0x33,0x08,0x5F,0x41,0x44,0x52,0x0C,0x03,  /* 000010A0    "3._ADR.." */
+    0x00,0x01,0x00,0x5B,0x80,0x50,0x31,0x33,  /* 000010A8    "...[.P13" */
+    0x43,0x02,0x0A,0x5C,0x0A,0x24,0x5B,0x81,  /* 000010B0    "C..\.$[." */
+    0x33,0x50,0x31,0x33,0x43,0x03,0x44,0x52,  /* 000010B8    "3P13C.DR" */
+    0x53,0x41,0x20,0x44,0x52,0x53,0x42,0x20,  /* 000010C0    "SA DRSB " */
+    0x44,0x52,0x53,0x43,0x20,0x44,0x52,0x53,  /* 000010C8    "DRSC DRS" */
+    0x45,0x20,0x44,0x52,0x53,0x46,0x20,0x44,  /* 000010D0    "E DRSF D" */
+    0x52,0x53,0x47,0x20,0x44,0x52,0x53,0x48,  /* 000010D8    "RSG DRSH" */
+    0x20,0x44,0x52,0x53,0x49,0x20,0x44,0x52,  /* 000010E0    " DRSI DR" */
+    0x53,0x4A,0x20,0x5B,0x82,0x2B,0x53,0x4C,  /* 000010E8    "SJ [.+SL" */
+    0x33,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,  /* 000010F0    "3_._ADR." */
+    0x00,0x00,0x03,0x00,0x14,0x14,0x5F,0x52,  /* 000010F8    "......_R" */
+    0x4D,0x56,0x00,0xA0,0x0B,0x7B,0x50,0x43,  /* 00001100    "MV...{PC" */
+    0x52,0x4D,0x0A,0x08,0x00,0xA4,0x01,0xA4,  /* 00001108    "RM......" */
+    0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x03,  /* 00001110    ".._SUN.." */
+    0x5B,0x82,0x2B,0x53,0x4C,0x34,0x5F,0x08,  /* 00001118    "[.+SL4_." */
+    0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x04,  /* 00001120    "_ADR...." */
+    0x00,0x14,0x14,0x5F,0x52,0x4D,0x56,0x00,  /* 00001128    "..._RMV." */
+    0xA0,0x0B,0x7B,0x50,0x43,0x52,0x4D,0x0A,  /* 00001130    "..{PCRM." */
+    0x10,0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,  /* 00001138    "......._" */
+    0x53,0x55,0x4E,0x0A,0x04,0x5B,0x82,0x2B,  /* 00001140    "SUN..[.+" */
+    0x53,0x4C,0x35,0x5F,0x08,0x5F,0x41,0x44,  /* 00001148    "SL5_._AD" */
+    0x52,0x0C,0x00,0x00,0x05,0x00,0x14,0x14,  /* 00001150    "R......." */
+    0x5F,0x52,0x4D,0x56,0x00,0xA0,0x0B,0x7B,  /* 00001158    "_RMV...{" */
+    0x50,0x43,0x52,0x4D,0x0A,0x20,0x00,0xA4,  /* 00001160    "PCRM. .." */
+    0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,  /* 00001168    "...._SUN" */
+    0x0A,0x05,0x5B,0x82,0x2B,0x53,0x4C,0x36,  /* 00001170    "..[.+SL6" */
+    0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,  /* 00001178    "_._ADR.." */
+    0x00,0x06,0x00,0x14,0x14,0x5F,0x52,0x4D,  /* 00001180    "....._RM" */
+    0x56,0x00,0xA0,0x0B,0x7B,0x50,0x43,0x52,  /* 00001188    "V...{PCR" */
+    0x4D,0x0A,0x40,0x00,0xA4,0x01,0xA4,0x00,  /* 00001190    "M.@....." */
+    0x08,0x5F,0x53,0x55,0x4E,0x0A,0x06,0x5B,  /* 00001198    "._SUN..[" */
+    0x82,0x2B,0x53,0x4C,0x37,0x5F,0x08,0x5F,  /* 000011A0    ".+SL7_._" */
+    0x41,0x44,0x52,0x0C,0x00,0x00,0x07,0x00,  /* 000011A8    "ADR....." */
+    0x14,0x14,0x5F,0x52,0x4D,0x56,0x00,0xA0,  /* 000011B0    ".._RMV.." */
+    0x0B,0x7B,0x50,0x43,0x52,0x4D,0x0A,0x80,  /* 000011B8    ".{PCRM.." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 000011C0    "......_S" */
+    0x55,0x4E,0x0A,0x07,0x5B,0x82,0x2C,0x53,  /* 000011C8    "UN..[.,S" */
+    0x4C,0x38,0x5F,0x08,0x5F,0x41,0x44,0x52,  /* 000011D0    "L8_._ADR" */
+    0x0C,0x00,0x00,0x08,0x00,0x14,0x15,0x5F,  /* 000011D8    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0C,0x7B,0x50,  /* 000011E0    "RMV...{P" */
+    0x43,0x52,0x4D,0x0B,0x00,0x01,0x00,0xA4,  /* 000011E8    "CRM....." */
+    0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,  /* 000011F0    "...._SUN" */
+    0x0A,0x08,0x5B,0x82,0x2C,0x53,0x4C,0x39,  /* 000011F8    "..[.,SL9" */
+    0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,  /* 00001200    "_._ADR.." */
+    0x00,0x09,0x00,0x14,0x15,0x5F,0x52,0x4D,  /* 00001208    "....._RM" */
+    0x56,0x00,0xA0,0x0C,0x7B,0x50,0x43,0x52,  /* 00001210    "V...{PCR" */
+    0x4D,0x0B,0x00,0x02,0x00,0xA4,0x01,0xA4,  /* 00001218    "M......." */
+    0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x09,  /* 00001220    ".._SUN.." */
+    0x5B,0x82,0x2C,0x53,0x4C,0x31,0x30,0x08,  /* 00001228    "[.,SL10." */
+    0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x0A,  /* 00001230    "_ADR...." */
+    0x00,0x14,0x15,0x5F,0x52,0x4D,0x56,0x00,  /* 00001238    "..._RMV." */
+    0xA0,0x0C,0x7B,0x50,0x43,0x52,0x4D,0x0B,  /* 00001240    "..{PCRM." */
+    0x00,0x04,0x00,0xA4,0x01,0xA4,0x00,0x08,  /* 00001248    "........" */
+    0x5F,0x53,0x55,0x4E,0x0A,0x0A,0x5B,0x82,  /* 00001250    "_SUN..[." */
+    0x2C,0x53,0x4C,0x31,0x31,0x08,0x5F,0x41,  /* 00001258    ",SL11._A" */
+    0x44,0x52,0x0C,0x00,0x00,0x0B,0x00,0x14,  /* 00001260    "DR......" */
+    0x15,0x5F,0x52,0x4D,0x56,0x00,0xA0,0x0C,  /* 00001268    "._RMV..." */
+    0x7B,0x50,0x43,0x52,0x4D,0x0B,0x00,0x08,  /* 00001270    "{PCRM..." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 00001278    "......_S" */
+    0x55,0x4E,0x0A,0x0B,0x5B,0x82,0x2C,0x53,  /* 00001280    "UN..[.,S" */
+    0x4C,0x31,0x32,0x08,0x5F,0x41,0x44,0x52,  /* 00001288    "L12._ADR" */
+    0x0C,0x00,0x00,0x0C,0x00,0x14,0x15,0x5F,  /* 00001290    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0C,0x7B,0x50,  /* 00001298    "RMV...{P" */
+    0x43,0x52,0x4D,0x0B,0x00,0x10,0x00,0xA4,  /* 000012A0    "CRM....." */
+    0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,  /* 000012A8    "...._SUN" */
+    0x0A,0x0C,0x5B,0x82,0x2C,0x53,0x4C,0x31,  /* 000012B0    "..[.,SL1" */
+    0x33,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,  /* 000012B8    "3._ADR.." */
+    0x00,0x0D,0x00,0x14,0x15,0x5F,0x52,0x4D,  /* 000012C0    "....._RM" */
+    0x56,0x00,0xA0,0x0C,0x7B,0x50,0x43,0x52,  /* 000012C8    "V...{PCR" */
+    0x4D,0x0B,0x00,0x20,0x00,0xA4,0x01,0xA4,  /* 000012D0    "M.. ...." */
+    0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x0D,  /* 000012D8    ".._SUN.." */
+    0x5B,0x82,0x2C,0x53,0x4C,0x31,0x34,0x08,  /* 000012E0    "[.,SL14." */
+    0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x0E,  /* 000012E8    "_ADR...." */
+    0x00,0x14,0x15,0x5F,0x52,0x4D,0x56,0x00,  /* 000012F0    "..._RMV." */
+    0xA0,0x0C,0x7B,0x50,0x43,0x52,0x4D,0x0B,  /* 000012F8    "..{PCRM." */
+    0x00,0x40,0x00,0xA4,0x01,0xA4,0x00,0x08,  /* 00001300    ".@......" */
+    0x5F,0x53,0x55,0x4E,0x0A,0x0E,0x5B,0x82,  /* 00001308    "_SUN..[." */
+    0x2C,0x53,0x4C,0x31,0x35,0x08,0x5F,0x41,  /* 00001310    ",SL15._A" */
+    0x44,0x52,0x0C,0x00,0x00,0x0F,0x00,0x14,  /* 00001318    "DR......" */
+    0x15,0x5F,0x52,0x4D,0x56,0x00,0xA0,0x0C,  /* 00001320    "._RMV..." */
+    0x7B,0x50,0x43,0x52,0x4D,0x0B,0x00,0x80,  /* 00001328    "{PCRM..." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 00001330    "......_S" */
+    0x55,0x4E,0x0A,0x0F,0x5B,0x82,0x2E,0x53,  /* 00001338    "UN..[..S" */
+    0x4C,0x31,0x36,0x08,0x5F,0x41,0x44,0x52,  /* 00001340    "L16._ADR" */
+    0x0C,0x00,0x00,0x10,0x00,0x14,0x17,0x5F,  /* 00001348    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 00001350    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x01,0x00,  /* 00001358    "CRM....." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 00001360    "......_S" */
+    0x55,0x4E,0x0A,0x10,0x5B,0x82,0x2E,0x53,  /* 00001368    "UN..[..S" */
+    0x4C,0x31,0x37,0x08,0x5F,0x41,0x44,0x52,  /* 00001370    "L17._ADR" */
+    0x0C,0x00,0x00,0x11,0x00,0x14,0x17,0x5F,  /* 00001378    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 00001380    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x02,0x00,  /* 00001388    "CRM....." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 00001390    "......_S" */
+    0x55,0x4E,0x0A,0x11,0x5B,0x82,0x2E,0x53,  /* 00001398    "UN..[..S" */
+    0x4C,0x31,0x38,0x08,0x5F,0x41,0x44,0x52,  /* 000013A0    "L18._ADR" */
+    0x0C,0x00,0x00,0x12,0x00,0x14,0x17,0x5F,  /* 000013A8    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 000013B0    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x04,0x00,  /* 000013B8    "CRM....." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 000013C0    "......_S" */
+    0x55,0x4E,0x0A,0x12,0x5B,0x82,0x2E,0x53,  /* 000013C8    "UN..[..S" */
+    0x4C,0x31,0x39,0x08,0x5F,0x41,0x44,0x52,  /* 000013D0    "L19._ADR" */
+    0x0C,0x00,0x00,0x13,0x00,0x14,0x17,0x5F,  /* 000013D8    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 000013E0    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x08,0x00,  /* 000013E8    "CRM....." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 000013F0    "......_S" */
+    0x55,0x4E,0x0A,0x13,0x5B,0x82,0x2E,0x53,  /* 000013F8    "UN..[..S" */
+    0x4C,0x32,0x30,0x08,0x5F,0x41,0x44,0x52,  /* 00001400    "L20._ADR" */
+    0x0C,0x00,0x00,0x14,0x00,0x14,0x17,0x5F,  /* 00001408    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 00001410    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x10,0x00,  /* 00001418    "CRM....." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 00001420    "......_S" */
+    0x55,0x4E,0x0A,0x14,0x5B,0x82,0x2E,0x53,  /* 00001428    "UN..[..S" */
+    0x4C,0x32,0x31,0x08,0x5F,0x41,0x44,0x52,  /* 00001430    "L21._ADR" */
+    0x0C,0x00,0x00,0x15,0x00,0x14,0x17,0x5F,  /* 00001438    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 00001440    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x20,0x00,  /* 00001448    "CRM... ." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 00001450    "......_S" */
+    0x55,0x4E,0x0A,0x15,0x5B,0x82,0x2E,0x53,  /* 00001458    "UN..[..S" */
+    0x4C,0x32,0x32,0x08,0x5F,0x41,0x44,0x52,  /* 00001460    "L22._ADR" */
+    0x0C,0x00,0x00,0x16,0x00,0x14,0x17,0x5F,  /* 00001468    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 00001470    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x40,0x00,  /* 00001478    "CRM...@." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 00001480    "......_S" */
+    0x55,0x4E,0x0A,0x16,0x5B,0x82,0x2E,0x53,  /* 00001488    "UN..[..S" */
+    0x4C,0x32,0x33,0x08,0x5F,0x41,0x44,0x52,  /* 00001490    "L23._ADR" */
+    0x0C,0x00,0x00,0x17,0x00,0x14,0x17,0x5F,  /* 00001498    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 000014A0    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x80,0x00,  /* 000014A8    "CRM....." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 000014B0    "......_S" */
+    0x55,0x4E,0x0A,0x17,0x5B,0x82,0x2E,0x53,  /* 000014B8    "UN..[..S" */
+    0x4C,0x32,0x34,0x08,0x5F,0x41,0x44,0x52,  /* 000014C0    "L24._ADR" */
+    0x0C,0x00,0x00,0x18,0x00,0x14,0x17,0x5F,  /* 000014C8    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 000014D0    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x01,  /* 000014D8    "CRM....." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 000014E0    "......_S" */
+    0x55,0x4E,0x0A,0x18,0x5B,0x82,0x2E,0x53,  /* 000014E8    "UN..[..S" */
+    0x4C,0x32,0x35,0x08,0x5F,0x41,0x44,0x52,  /* 000014F0    "L25._ADR" */
+    0x0C,0x00,0x00,0x19,0x00,0x14,0x17,0x5F,  /* 000014F8    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 00001500    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x02,  /* 00001508    "CRM....." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 00001510    "......_S" */
+    0x55,0x4E,0x0A,0x19,0x5B,0x82,0x2E,0x53,  /* 00001518    "UN..[..S" */
+    0x4C,0x32,0x36,0x08,0x5F,0x41,0x44,0x52,  /* 00001520    "L26._ADR" */
+    0x0C,0x00,0x00,0x1A,0x00,0x14,0x17,0x5F,  /* 00001528    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 00001530    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x04,  /* 00001538    "CRM....." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 00001540    "......_S" */
+    0x55,0x4E,0x0A,0x1A,0x5B,0x82,0x2E,0x53,  /* 00001548    "UN..[..S" */
+    0x4C,0x32,0x37,0x08,0x5F,0x41,0x44,0x52,  /* 00001550    "L27._ADR" */
+    0x0C,0x00,0x00,0x1B,0x00,0x14,0x17,0x5F,  /* 00001558    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 00001560    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x08,  /* 00001568    "CRM....." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 00001570    "......_S" */
+    0x55,0x4E,0x0A,0x1B,0x5B,0x82,0x2E,0x53,  /* 00001578    "UN..[..S" */
+    0x4C,0x32,0x38,0x08,0x5F,0x41,0x44,0x52,  /* 00001580    "L28._ADR" */
+    0x0C,0x00,0x00,0x1C,0x00,0x14,0x17,0x5F,  /* 00001588    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 00001590    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x10,  /* 00001598    "CRM....." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 000015A0    "......_S" */
+    0x55,0x4E,0x0A,0x1C,0x5B,0x82,0x2E,0x53,  /* 000015A8    "UN..[..S" */
+    0x4C,0x32,0x39,0x08,0x5F,0x41,0x44,0x52,  /* 000015B0    "L29._ADR" */
+    0x0C,0x00,0x00,0x1D,0x00,0x14,0x17,0x5F,  /* 000015B8    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 000015C0    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x20,  /* 000015C8    "CRM.... " */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 000015D0    "......_S" */
+    0x55,0x4E,0x0A,0x1D,0x5B,0x82,0x2E,0x53,  /* 000015D8    "UN..[..S" */
+    0x4C,0x33,0x30,0x08,0x5F,0x41,0x44,0x52,  /* 000015E0    "L30._ADR" */
+    0x0C,0x00,0x00,0x1E,0x00,0x14,0x17,0x5F,  /* 000015E8    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 000015F0    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x40,  /* 000015F8    "CRM....@" */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 00001600    "......_S" */
+    0x55,0x4E,0x0A,0x1E,0x5B,0x82,0x2E,0x53,  /* 00001608    "UN..[..S" */
+    0x4C,0x33,0x31,0x08,0x5F,0x41,0x44,0x52,  /* 00001610    "L31._ADR" */
+    0x0C,0x00,0x00,0x1F,0x00,0x14,0x17,0x5F,  /* 00001618    "......._" */
+    0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50,  /* 00001620    "RMV...{P" */
+    0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x80,  /* 00001628    "CRM....." */
+    0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53,  /* 00001630    "......_S" */
+    0x55,0x4E,0x0A,0x1F,0x10,0x4B,0x3C,0x5F,  /* 00001638    "UN...K<_" */
+    0x53,0x42,0x5F,0x5B,0x81,0x24,0x2F,0x03,  /* 00001640    "SB_[.$/." */
+    0x50,0x43,0x49,0x30,0x49,0x53,0x41,0x5F,  /* 00001648    "PCI0ISA_" */
+    0x50,0x34,0x30,0x43,0x01,0x50,0x52,0x51,  /* 00001650    "P40C.PRQ" */
+    0x30,0x08,0x50,0x52,0x51,0x31,0x08,0x50,  /* 00001658    "0.PRQ1.P" */
+    0x52,0x51,0x32,0x08,0x50,0x52,0x51,0x33,  /* 00001660    "RQ2.PRQ3" */
+    0x08,0x5B,0x82,0x4D,0x0B,0x4C,0x4E,0x4B,  /* 00001668    ".[.M.LNK" */
+    0x41,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,  /* 00001670    "A._HID.A" */
+    0xD0,0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,  /* 00001678    "...._UID" */
+    0x01,0x08,0x5F,0x50,0x52,0x53,0x11,0x16,  /* 00001680    ".._PRS.." */
+    0x0A,0x13,0x89,0x0E,0x00,0x09,0x03,0x05,  /* 00001688    "........" */
+    0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x0B,  /* 00001690    "........" */
+    0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F,  /* 00001698    "...y..._" */
+    0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,  /* 000016A0    "STA.p..`" */
+    0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,  /* 000016A8    "..{..PRQ" */
+    0x30,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,  /* 000016B0    "0ap..`.`" */
+    0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,  /* 000016B8    ".._DIS.}" */
+    0x50,0x52,0x51,0x30,0x0A,0x80,0x50,0x52,  /* 000016C0    "PRQ0..PR" */
+    0x51,0x30,0x14,0x45,0x04,0x5F,0x43,0x52,  /* 000016C8    "Q0.E._CR" */
+    0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11,  /* 000016D0    "S..PRR0." */
+    0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01,  /* 000016D8    "........" */
+    0x01,0x00,0x00,0x00,0x79,0x00,0x8A,0x50,  /* 000016E0    "....y..P" */
+    0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50,  /* 000016E8    "RR0..TMP" */
+    0x5F,0x70,0x50,0x52,0x51,0x30,0x60,0xA0,  /* 000016F0    "_pPRQ0`." */
+    0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54,  /* 000016F8    "..`..p`T" */
+    0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,  /* 00001700    "MP_..p.T" */
+    0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,  /* 00001708    "MP_.PRR0" */
+    0x14,0x17,0x5F,0x53,0x52,0x53,0x01,0x8A,  /* 00001710    ".._SRS.." */
+    0x68,0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70,  /* 00001718    "h..TMP_p" */
+    0x54,0x4D,0x50,0x5F,0x50,0x52,0x51,0x30,  /* 00001720    "TMP_PRQ0" */
+    0x5B,0x82,0x4E,0x0B,0x4C,0x4E,0x4B,0x42,  /* 00001728    "[.N.LNKB" */
+    0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,  /* 00001730    "._HID.A." */
+    0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A,  /* 00001738    "..._UID." */
+    0x02,0x08,0x5F,0x50,0x52,0x53,0x11,0x16,  /* 00001740    ".._PRS.." */
+    0x0A,0x13,0x89,0x0E,0x00,0x09,0x03,0x05,  /* 00001748    "........" */
+    0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x0B,  /* 00001750    "........" */
+    0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F,  /* 00001758    "...y..._" */
+    0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,  /* 00001760    "STA.p..`" */
+    0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,  /* 00001768    "..{..PRQ" */
+    0x31,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,  /* 00001770    "1ap..`.`" */
+    0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,  /* 00001778    ".._DIS.}" */
+    0x50,0x52,0x51,0x31,0x0A,0x80,0x50,0x52,  /* 00001780    "PRQ1..PR" */
+    0x51,0x31,0x14,0x45,0x04,0x5F,0x43,0x52,  /* 00001788    "Q1.E._CR" */
+    0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11,  /* 00001790    "S..PRR0." */
+    0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01,  /* 00001798    "........" */
+    0x01,0x00,0x00,0x00,0x79,0x00,0x8A,0x50,  /* 000017A0    "....y..P" */
+    0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50,  /* 000017A8    "RR0..TMP" */
+    0x5F,0x70,0x50,0x52,0x51,0x31,0x60,0xA0,  /* 000017B0    "_pPRQ1`." */
+    0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54,  /* 000017B8    "..`..p`T" */
+    0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,  /* 000017C0    "MP_..p.T" */
+    0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,  /* 000017C8    "MP_.PRR0" */
+    0x14,0x17,0x5F,0x53,0x52,0x53,0x01,0x8A,  /* 000017D0    ".._SRS.." */
+    0x68,0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70,  /* 000017D8    "h..TMP_p" */
+    0x54,0x4D,0x50,0x5F,0x50,0x52,0x51,0x31,  /* 000017E0    "TMP_PRQ1" */
+    0x5B,0x82,0x4E,0x0B,0x4C,0x4E,0x4B,0x43,  /* 000017E8    "[.N.LNKC" */
+    0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,  /* 000017F0    "._HID.A." */
+    0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A,  /* 000017F8    "..._UID." */
+    0x03,0x08,0x5F,0x50,0x52,0x53,0x11,0x16,  /* 00001800    ".._PRS.." */
+    0x0A,0x13,0x89,0x0E,0x00,0x09,0x03,0x05,  /* 00001808    "........" */
+    0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x0B,  /* 00001810    "........" */
+    0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F,  /* 00001818    "...y..._" */
+    0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,  /* 00001820    "STA.p..`" */
+    0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,  /* 00001828    "..{..PRQ" */
+    0x32,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,  /* 00001830    "2ap..`.`" */
+    0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,  /* 00001838    ".._DIS.}" */
+    0x50,0x52,0x51,0x32,0x0A,0x80,0x50,0x52,  /* 00001840    "PRQ2..PR" */
+    0x51,0x32,0x14,0x45,0x04,0x5F,0x43,0x52,  /* 00001848    "Q2.E._CR" */
+    0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11,  /* 00001850    "S..PRR0." */
+    0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01,  /* 00001858    "........" */
+    0x01,0x00,0x00,0x00,0x79,0x00,0x8A,0x50,  /* 00001860    "....y..P" */
+    0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50,  /* 00001868    "RR0..TMP" */
+    0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0,  /* 00001870    "_pPRQ2`." */
+    0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54,  /* 00001878    "..`..p`T" */
+    0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,  /* 00001880    "MP_..p.T" */
+    0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,  /* 00001888    "MP_.PRR0" */
+    0x14,0x17,0x5F,0x53,0x52,0x53,0x01,0x8A,  /* 00001890    ".._SRS.." */
+    0x68,0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70,  /* 00001898    "h..TMP_p" */
+    0x54,0x4D,0x50,0x5F,0x50,0x52,0x51,0x32,  /* 000018A0    "TMP_PRQ2" */
+    0x5B,0x82,0x4E,0x0B,0x4C,0x4E,0x4B,0x44,  /* 000018A8    "[.N.LNKD" */
+    0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,  /* 000018B0    "._HID.A." */
+    0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A,  /* 000018B8    "..._UID." */
+    0x04,0x08,0x5F,0x50,0x52,0x53,0x11,0x16,  /* 000018C0    ".._PRS.." */
+    0x0A,0x13,0x89,0x0E,0x00,0x09,0x03,0x05,  /* 000018C8    "........" */
+    0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x0B,  /* 000018D0    "........" */
+    0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F,  /* 000018D8    "...y..._" */
+    0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,  /* 000018E0    "STA.p..`" */
+    0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,  /* 000018E8    "..{..PRQ" */
+    0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,  /* 000018F0    "3ap..`.`" */
+    0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,  /* 000018F8    ".._DIS.}" */
+    0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52,  /* 00001900    "PRQ3..PR" */
+    0x51,0x33,0x14,0x45,0x04,0x5F,0x43,0x52,  /* 00001908    "Q3.E._CR" */
+    0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11,  /* 00001910    "S..PRR0." */
+    0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01,  /* 00001918    "........" */
+    0x01,0x00,0x00,0x00,0x79,0x00,0x8A,0x50,  /* 00001920    "....y..P" */
+    0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50,  /* 00001928    "RR0..TMP" */
+    0x5F,0x70,0x50,0x52,0x51,0x33,0x60,0xA0,  /* 00001930    "_pPRQ3`." */
+    0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54,  /* 00001938    "..`..p`T" */
+    0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,  /* 00001940    "MP_..p.T" */
+    0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,  /* 00001948    "MP_.PRR0" */
+    0x14,0x17,0x5F,0x53,0x52,0x53,0x01,0x8A,  /* 00001950    ".._SRS.." */
+    0x68,0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70,  /* 00001958    "h..TMP_p" */
+    0x54,0x4D,0x50,0x5F,0x50,0x52,0x51,0x33,  /* 00001960    "TMP_PRQ3" */
+    0x5B,0x82,0x4E,0x09,0x4C,0x4E,0x4B,0x53,  /* 00001968    "[.N.LNKS" */
+    0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,  /* 00001970    "._HID.A." */
+    0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A,  /* 00001978    "..._UID." */
+    0x05,0x08,0x5F,0x50,0x52,0x53,0x11,0x0E,  /* 00001980    ".._PRS.." */
+    0x0A,0x0B,0x89,0x06,0x00,0x09,0x01,0x09,  /* 00001988    "........" */
+    0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F,  /* 00001990    "...y..._" */
+    0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,  /* 00001998    "STA.p..`" */
+    0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,  /* 000019A0    "..{..PRQ" */
+    0x30,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,  /* 000019A8    "0ap..`.`" */
+    0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,  /* 000019B0    ".._DIS.}" */
+    0x50,0x52,0x51,0x30,0x0A,0x80,0x50,0x52,  /* 000019B8    "PRQ0..PR" */
+    0x51,0x30,0x14,0x45,0x04,0x5F,0x43,0x52,  /* 000019C0    "Q0.E._CR" */
+    0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11,  /* 000019C8    "S..PRR0." */
+    0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01,  /* 000019D0    "........" */
+    0x09,0x00,0x00,0x00,0x79,0x00,0x8A,0x50,  /* 000019D8    "....y..P" */
+    0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50,  /* 000019E0    "RR0..TMP" */
+    0x5F,0x70,0x50,0x52,0x51,0x30,0x60,0xA0,  /* 000019E8    "_pPRQ0`." */
+    0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54,  /* 000019F0    "..`..p`T" */
+    0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,  /* 000019F8    "MP_..p.T" */
+    0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,  /* 00001A00    "MP_.PRR0" */
+    0x08,0x5F,0x53,0x33,0x5F,0x12,0x06,0x04,  /* 00001A08    "._S3_..." */
+    0x01,0x01,0x00,0x00,0x08,0x5F,0x53,0x34,  /* 00001A10    "....._S4" */
+    0x5F,0x12,0x06,0x04,0x00,0x00,0x00,0x00,  /* 00001A18    "_......." */
+    0x08,0x5F,0x53,0x35,0x5F,0x12,0x06,0x04,  /* 00001A20    "._S5_..." */
+    0x00,0x00,0x00,0x00,0x10,0x49,0x0E,0x5F,  /* 00001A28    ".....I._" */
+    0x53,0x42,0x5F,0x14,0x35,0x43,0x50,0x4D,  /* 00001A30    "SB_.5CPM" */
+    0x41,0x01,0x70,0x83,0x88,0x43,0x50,0x4F,  /* 00001A38    "A.p..CPO" */
+    0x4E,0x68,0x00,0x60,0x70,0x11,0x0B,0x0A,  /* 00001A40    "Nh.`p..." */
+    0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,  /* 00001A48    "........" */
+    0x00,0x61,0x70,0x68,0x88,0x61,0x0A,0x02,  /* 00001A50    ".aph.a.." */
+    0x00,0x70,0x68,0x88,0x61,0x0A,0x03,0x00,  /* 00001A58    ".ph.a..." */
+    0x70,0x60,0x88,0x61,0x0A,0x04,0x00,0xA4,  /* 00001A60    "p`.a...." */
+    0x61,0x14,0x1A,0x43,0x50,0x53,0x54,0x01,  /* 00001A68    "a..CPST." */
+    0x70,0x83,0x88,0x43,0x50,0x4F,0x4E,0x68,  /* 00001A70    "p..CPONh" */
+    0x00,0x60,0xA0,0x05,0x60,0xA4,0x0A,0x0F,  /* 00001A78    ".`..`..." */
+    0xA1,0x03,0xA4,0x00,0x14,0x0A,0x43,0x50,  /* 00001A80    "......CP" */
+    0x45,0x4A,0x02,0x5B,0x22,0x0A,0xC8,0x5B,  /* 00001A88    "EJ.["..[" */
+    0x80,0x50,0x52,0x53,0x54,0x01,0x0B,0x00,  /* 00001A90    ".PRST..." */
+    0xAF,0x0A,0x20,0x5B,0x81,0x0C,0x50,0x52,  /* 00001A98    ".. [..PR" */
+    0x53,0x54,0x01,0x50,0x52,0x53,0x5F,0x40,  /* 00001AA0    "ST.PRS_@" */
+    0x10,0x14,0x4C,0x06,0x50,0x52,0x53,0x43,  /* 00001AA8    "..L.PRSC" */
+    0x00,0x70,0x50,0x52,0x53,0x5F,0x65,0x70,  /* 00001AB0    ".pPRS_ep" */
+    0x00,0x62,0x70,0x00,0x60,0xA2,0x46,0x05,  /* 00001AB8    ".bp.`.F." */
+    0x95,0x60,0x87,0x43,0x50,0x4F,0x4E,0x70,  /* 00001AC0    ".`.CPONp" */
+    0x83,0x88,0x43,0x50,0x4F,0x4E,0x60,0x00,  /* 00001AC8    "..CPON`." */
+    0x61,0xA0,0x0A,0x7B,0x60,0x0A,0x07,0x00,  /* 00001AD0    "a..{`..." */
+    0x7A,0x62,0x01,0x62,0xA1,0x0C,0x70,0x83,  /* 00001AD8    "zb.b..p." */
+    0x88,0x65,0x7A,0x60,0x0A,0x03,0x00,0x00,  /* 00001AE0    ".ez`...." */
+    0x62,0x70,0x7B,0x62,0x01,0x00,0x63,0xA0,  /* 00001AE8    "bp{b..c." */
+    0x22,0x92,0x93,0x61,0x63,0x70,0x63,0x88,  /* 00001AF0    ""..acpc." */
+    0x43,0x50,0x4F,0x4E,0x60,0x00,0xA0,0x0A,  /* 00001AF8    "CPON`..." */
+    0x93,0x63,0x01,0x4E,0x54,0x46,0x59,0x60,  /* 00001B00    ".c.NTFY`" */
+    0x01,0xA1,0x08,0x4E,0x54,0x46,0x59,0x60,  /* 00001B08    "...NTFY`" */
+    0x0A,0x03,0x75,0x60,0xA4,0x01,0x10,0x42,  /* 00001B10    "..u`...B" */
+    0xA7,0x5F,0x47,0x50,0x45,0x08,0x5F,0x48,  /* 00001B18    "._GPE._H" */
+    0x49,0x44,0x0D,0x41,0x43,0x50,0x49,0x30,  /* 00001B20    "ID.ACPI0" */
+    0x30,0x30,0x36,0x00,0x14,0x08,0x5F,0x4C,  /* 00001B28    "006..._L" */
+    0x30,0x30,0x00,0xA4,0x01,0x14,0x4C,0x9C,  /* 00001B30    "00....L." */
+    0x5F,0x4C,0x30,0x31,0x00,0xA0,0x25,0x7B,  /* 00001B38    "_L01..%{" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001B40    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0A,  /* 00001B48    "CI0PCIU." */
+    0x02,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001B50    "...\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31,  /* 00001B58    "B_PCI0S1" */
+    0x5F,0x5F,0x01,0xA0,0x26,0x7B,0x5C,0x2F,  /* 00001B60    "__..&{\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001B68    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x44,0x0A,0x02,0x00,  /* 00001B70    "0PCID..." */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001B78    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x31,0x5F,0x5F,  /* 00001B80    "PCI0S1__" */
+    0x0A,0x03,0xA0,0x25,0x7B,0x5C,0x2F,0x03,  /* 00001B88    "...%{\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001B90    "_SB_PCI0" */
+    0x50,0x43,0x49,0x55,0x0A,0x04,0x00,0x86,  /* 00001B98    "PCIU...." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001BA0    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x32,0x5F,0x5F,0x01,  /* 00001BA8    "CI0S2__." */
+    0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001BB0    ".&{\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 00001BB8    "B_PCI0PC" */
+    0x49,0x44,0x0A,0x04,0x00,0x86,0x5C,0x2F,  /* 00001BC0    "ID....\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001BC8    "._SB_PCI" */
+    0x30,0x53,0x32,0x5F,0x5F,0x0A,0x03,0xA0,  /* 00001BD0    "0S2__..." */
+    0x25,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001BD8    "%{\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00001BE0    "_PCI0PCI" */
+    0x55,0x0A,0x08,0x00,0x86,0x5C,0x2F,0x03,  /* 00001BE8    "U....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001BF0    "_SB_PCI0" */
+    0x53,0x33,0x5F,0x5F,0x01,0xA0,0x26,0x7B,  /* 00001BF8    "S3__..&{" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001C00    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0A,  /* 00001C08    "CI0PCID." */
+    0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001C10    "...\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x33,  /* 00001C18    "B_PCI0S3" */
+    0x5F,0x5F,0x0A,0x03,0xA0,0x25,0x7B,0x5C,  /* 00001C20    "__...%{\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001C28    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x55,0x0A,0x10,  /* 00001C30    "I0PCIU.." */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001C38    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x34,0x5F,  /* 00001C40    "_PCI0S4_" */
+    0x5F,0x01,0xA0,0x26,0x7B,0x5C,0x2F,0x03,  /* 00001C48    "_..&{\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001C50    "_SB_PCI0" */
+    0x50,0x43,0x49,0x44,0x0A,0x10,0x00,0x86,  /* 00001C58    "PCID...." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001C60    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x34,0x5F,0x5F,0x0A,  /* 00001C68    "CI0S4__." */
+    0x03,0xA0,0x25,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00001C70    "..%{\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 00001C78    "SB_PCI0P" */
+    0x43,0x49,0x55,0x0A,0x20,0x00,0x86,0x5C,  /* 00001C80    "CIU. ..\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001C88    "/._SB_PC" */
+    0x49,0x30,0x53,0x35,0x5F,0x5F,0x01,0xA0,  /* 00001C90    "I0S5__.." */
+    0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001C98    "&{\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00001CA0    "_PCI0PCI" */
+    0x44,0x0A,0x20,0x00,0x86,0x5C,0x2F,0x03,  /* 00001CA8    "D. ..\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001CB0    "_SB_PCI0" */
+    0x53,0x35,0x5F,0x5F,0x0A,0x03,0xA0,0x25,  /* 00001CB8    "S5__...%" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001CC0    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55,  /* 00001CC8    "PCI0PCIU" */
+    0x0A,0x40,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 00001CD0    ".@..\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 00001CD8    "SB_PCI0S" */
+    0x36,0x5F,0x5F,0x01,0xA0,0x26,0x7B,0x5C,  /* 00001CE0    "6__..&{\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001CE8    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x44,0x0A,0x40,  /* 00001CF0    "I0PCID.@" */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001CF8    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x36,0x5F,  /* 00001D00    "_PCI0S6_" */
+    0x5F,0x0A,0x03,0xA0,0x25,0x7B,0x5C,0x2F,  /* 00001D08    "_...%{\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001D10    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x55,0x0A,0x80,0x00,  /* 00001D18    "0PCIU..." */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001D20    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x37,0x5F,0x5F,  /* 00001D28    "PCI0S7__" */
+    0x01,0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00001D30    "..&{\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 00001D38    "SB_PCI0P" */
+    0x43,0x49,0x44,0x0A,0x80,0x00,0x86,0x5C,  /* 00001D40    "CID....\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001D48    "/._SB_PC" */
+    0x49,0x30,0x53,0x37,0x5F,0x5F,0x0A,0x03,  /* 00001D50    "I0S7__.." */
+    0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001D58    ".&{\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 00001D60    "B_PCI0PC" */
+    0x49,0x55,0x0B,0x00,0x01,0x00,0x86,0x5C,  /* 00001D68    "IU.....\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001D70    "/._SB_PC" */
+    0x49,0x30,0x53,0x38,0x5F,0x5F,0x01,0xA0,  /* 00001D78    "I0S8__.." */
+    0x27,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001D80    "'{\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00001D88    "_PCI0PCI" */
+    0x44,0x0B,0x00,0x01,0x00,0x86,0x5C,0x2F,  /* 00001D90    "D.....\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001D98    "._SB_PCI" */
+    0x30,0x53,0x38,0x5F,0x5F,0x0A,0x03,0xA0,  /* 00001DA0    "0S8__..." */
+    0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001DA8    "&{\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00001DB0    "_PCI0PCI" */
+    0x55,0x0B,0x00,0x02,0x00,0x86,0x5C,0x2F,  /* 00001DB8    "U.....\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001DC0    "._SB_PCI" */
+    0x30,0x53,0x39,0x5F,0x5F,0x01,0xA0,0x27,  /* 00001DC8    "0S9__..'" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001DD0    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x44,  /* 00001DD8    "PCI0PCID" */
+    0x0B,0x00,0x02,0x00,0x86,0x5C,0x2F,0x03,  /* 00001DE0    ".....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001DE8    "_SB_PCI0" */
+    0x53,0x39,0x5F,0x5F,0x0A,0x03,0xA0,0x26,  /* 00001DF0    "S9__...&" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001DF8    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55,  /* 00001E00    "PCI0PCIU" */
+    0x0B,0x00,0x04,0x00,0x86,0x5C,0x2F,0x03,  /* 00001E08    ".....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001E10    "_SB_PCI0" */
+    0x53,0x31,0x30,0x5F,0x01,0xA0,0x27,0x7B,  /* 00001E18    "S10_..'{" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001E20    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0B,  /* 00001E28    "CI0PCID." */
+    0x00,0x04,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 00001E30    "....\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 00001E38    "SB_PCI0S" */
+    0x31,0x30,0x5F,0x0A,0x03,0xA0,0x26,0x7B,  /* 00001E40    "10_...&{" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001E48    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0B,  /* 00001E50    "CI0PCIU." */
+    0x00,0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 00001E58    "....\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 00001E60    "SB_PCI0S" */
+    0x31,0x31,0x5F,0x01,0xA0,0x27,0x7B,0x5C,  /* 00001E68    "11_..'{\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001E70    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x44,0x0B,0x00,  /* 00001E78    "I0PCID.." */
+    0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001E80    "...\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31,  /* 00001E88    "B_PCI0S1" */
+    0x31,0x5F,0x0A,0x03,0xA0,0x26,0x7B,0x5C,  /* 00001E90    "1_...&{\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001E98    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x55,0x0B,0x00,  /* 00001EA0    "I0PCIU.." */
+    0x10,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001EA8    "...\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31,  /* 00001EB0    "B_PCI0S1" */
+    0x32,0x5F,0x01,0xA0,0x27,0x7B,0x5C,0x2F,  /* 00001EB8    "2_..'{\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001EC0    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x44,0x0B,0x00,0x10,  /* 00001EC8    "0PCID..." */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001ED0    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x32,  /* 00001ED8    "_PCI0S12" */
+    0x5F,0x0A,0x03,0xA0,0x26,0x7B,0x5C,0x2F,  /* 00001EE0    "_...&{\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00001EE8    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x55,0x0B,0x00,0x20,  /* 00001EF0    "0PCIU.. " */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00001EF8    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x33,  /* 00001F00    "_PCI0S13" */
+    0x5F,0x01,0xA0,0x27,0x7B,0x5C,0x2F,0x03,  /* 00001F08    "_..'{\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001F10    "_SB_PCI0" */
+    0x50,0x43,0x49,0x44,0x0B,0x00,0x20,0x00,  /* 00001F18    "PCID.. ." */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001F20    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x31,0x33,0x5F,  /* 00001F28    "PCI0S13_" */
+    0x0A,0x03,0xA0,0x26,0x7B,0x5C,0x2F,0x03,  /* 00001F30    "...&{\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00001F38    "_SB_PCI0" */
+    0x50,0x43,0x49,0x55,0x0B,0x00,0x40,0x00,  /* 00001F40    "PCIU..@." */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001F48    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x31,0x34,0x5F,  /* 00001F50    "PCI0S14_" */
+    0x01,0xA0,0x27,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00001F58    "..'{\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 00001F60    "SB_PCI0P" */
+    0x43,0x49,0x44,0x0B,0x00,0x40,0x00,0x86,  /* 00001F68    "CID..@.." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001F70    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x31,0x34,0x5F,0x0A,  /* 00001F78    "CI0S14_." */
+    0x03,0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00001F80    "..&{\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 00001F88    "SB_PCI0P" */
+    0x43,0x49,0x55,0x0B,0x00,0x80,0x00,0x86,  /* 00001F90    "CIU....." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001F98    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x31,0x35,0x5F,0x01,  /* 00001FA0    "CI0S15_." */
+    0xA0,0x27,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001FA8    ".'{\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 00001FB0    "B_PCI0PC" */
+    0x49,0x44,0x0B,0x00,0x80,0x00,0x86,0x5C,  /* 00001FB8    "ID.....\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001FC0    "/._SB_PC" */
+    0x49,0x30,0x53,0x31,0x35,0x5F,0x0A,0x03,  /* 00001FC8    "I0S15_.." */
+    0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00001FD0    ".({\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 00001FD8    "B_PCI0PC" */
+    0x49,0x55,0x0C,0x00,0x00,0x01,0x00,0x00,  /* 00001FE0    "IU......" */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00001FE8    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x31,0x36,0x5F,  /* 00001FF0    "PCI0S16_" */
+    0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00001FF8    "..){\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 00002000    "SB_PCI0P" */
+    0x43,0x49,0x44,0x0C,0x00,0x00,0x01,0x00,  /* 00002008    "CID....." */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00002010    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x36,  /* 00002018    "_PCI0S16" */
+    0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F,  /* 00002020    "_...({\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00002028    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x55,0x0C,0x00,0x00,  /* 00002030    "0PCIU..." */
+    0x02,0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 00002038    "....\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 00002040    "SB_PCI0S" */
+    0x31,0x37,0x5F,0x01,0xA0,0x29,0x7B,0x5C,  /* 00002048    "17_..){\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00002050    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x44,0x0C,0x00,  /* 00002058    "I0PCID.." */
+    0x00,0x02,0x00,0x00,0x86,0x5C,0x2F,0x03,  /* 00002060    ".....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00002068    "_SB_PCI0" */
+    0x53,0x31,0x37,0x5F,0x0A,0x03,0xA0,0x28,  /* 00002070    "S17_...(" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00002078    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55,  /* 00002080    "PCI0PCIU" */
+    0x0C,0x00,0x00,0x04,0x00,0x00,0x86,0x5C,  /* 00002088    ".......\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00002090    "/._SB_PC" */
+    0x49,0x30,0x53,0x31,0x38,0x5F,0x01,0xA0,  /* 00002098    "I0S18_.." */
+    0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 000020A0    "){\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 000020A8    "_PCI0PCI" */
+    0x44,0x0C,0x00,0x00,0x04,0x00,0x00,0x86,  /* 000020B0    "D......." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 000020B8    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x31,0x38,0x5F,0x0A,  /* 000020C0    "CI0S18_." */
+    0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F,  /* 000020C8    "..({\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 000020D0    "SB_PCI0P" */
+    0x43,0x49,0x55,0x0C,0x00,0x00,0x08,0x00,  /* 000020D8    "CIU....." */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 000020E0    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x39,  /* 000020E8    "_PCI0S19" */
+    0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03,  /* 000020F0    "_..){\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 000020F8    "_SB_PCI0" */
+    0x50,0x43,0x49,0x44,0x0C,0x00,0x00,0x08,  /* 00002100    "PCID...." */
+    0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 00002108    "...\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31,  /* 00002110    "B_PCI0S1" */
+    0x39,0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C,  /* 00002118    "9_...({\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00002120    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x55,0x0C,0x00,  /* 00002128    "I0PCIU.." */
+    0x00,0x10,0x00,0x00,0x86,0x5C,0x2F,0x03,  /* 00002130    ".....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00002138    "_SB_PCI0" */
+    0x53,0x32,0x30,0x5F,0x01,0xA0,0x29,0x7B,  /* 00002140    "S20_..){" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00002148    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0C,  /* 00002150    "CI0PCID." */
+    0x00,0x00,0x10,0x00,0x00,0x86,0x5C,0x2F,  /* 00002158    "......\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00002160    "._SB_PCI" */
+    0x30,0x53,0x32,0x30,0x5F,0x0A,0x03,0xA0,  /* 00002168    "0S20_..." */
+    0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00002170    "({\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00002178    "_PCI0PCI" */
+    0x55,0x0C,0x00,0x00,0x20,0x00,0x00,0x86,  /* 00002180    "U... ..." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00002188    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x32,0x31,0x5F,0x01,  /* 00002190    "CI0S21_." */
+    0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00002198    ".){\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 000021A0    "B_PCI0PC" */
+    0x49,0x44,0x0C,0x00,0x00,0x20,0x00,0x00,  /* 000021A8    "ID... .." */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 000021B0    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x32,0x31,0x5F,  /* 000021B8    "PCI0S21_" */
+    0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03,  /* 000021C0    "...({\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 000021C8    "_SB_PCI0" */
+    0x50,0x43,0x49,0x55,0x0C,0x00,0x00,0x40,  /* 000021D0    "PCIU...@" */
+    0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 000021D8    "...\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x32,  /* 000021E0    "B_PCI0S2" */
+    0x32,0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F,  /* 000021E8    "2_..){\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 000021F0    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x44,0x0C,0x00,0x00,  /* 000021F8    "0PCID..." */
+    0x40,0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 00002200    "@...\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 00002208    "SB_PCI0S" */
+    0x32,0x32,0x5F,0x0A,0x03,0xA0,0x28,0x7B,  /* 00002210    "22_...({" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00002218    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0C,  /* 00002220    "CI0PCIU." */
+    0x00,0x00,0x80,0x00,0x00,0x86,0x5C,0x2F,  /* 00002228    "......\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00002230    "._SB_PCI" */
+    0x30,0x53,0x32,0x33,0x5F,0x01,0xA0,0x29,  /* 00002238    "0S23_..)" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00002240    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x44,  /* 00002248    "PCI0PCID" */
+    0x0C,0x00,0x00,0x80,0x00,0x00,0x86,0x5C,  /* 00002250    ".......\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00002258    "/._SB_PC" */
+    0x49,0x30,0x53,0x32,0x33,0x5F,0x0A,0x03,  /* 00002260    "I0S23_.." */
+    0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00002268    ".({\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 00002270    "B_PCI0PC" */
+    0x49,0x55,0x0C,0x00,0x00,0x00,0x01,0x00,  /* 00002278    "IU......" */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00002280    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x32,0x34,0x5F,  /* 00002288    "PCI0S24_" */
+    0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00002290    "..){\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 00002298    "SB_PCI0P" */
+    0x43,0x49,0x44,0x0C,0x00,0x00,0x00,0x01,  /* 000022A0    "CID....." */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 000022A8    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x32,0x34,  /* 000022B0    "_PCI0S24" */
+    0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F,  /* 000022B8    "_...({\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 000022C0    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x55,0x0C,0x00,0x00,  /* 000022C8    "0PCIU..." */
+    0x00,0x02,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 000022D0    "....\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 000022D8    "SB_PCI0S" */
+    0x32,0x35,0x5F,0x01,0xA0,0x29,0x7B,0x5C,  /* 000022E0    "25_..){\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 000022E8    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x44,0x0C,0x00,  /* 000022F0    "I0PCID.." */
+    0x00,0x00,0x02,0x00,0x86,0x5C,0x2F,0x03,  /* 000022F8    ".....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00002300    "_SB_PCI0" */
+    0x53,0x32,0x35,0x5F,0x0A,0x03,0xA0,0x28,  /* 00002308    "S25_...(" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00002310    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55,  /* 00002318    "PCI0PCIU" */
+    0x0C,0x00,0x00,0x00,0x04,0x00,0x86,0x5C,  /* 00002320    ".......\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00002328    "/._SB_PC" */
+    0x49,0x30,0x53,0x32,0x36,0x5F,0x01,0xA0,  /* 00002330    "I0S26_.." */
+    0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00002338    "){\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00002340    "_PCI0PCI" */
+    0x44,0x0C,0x00,0x00,0x00,0x04,0x00,0x86,  /* 00002348    "D......." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00002350    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x32,0x36,0x5F,0x0A,  /* 00002358    "CI0S26_." */
+    0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F,  /* 00002360    "..({\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50,  /* 00002368    "SB_PCI0P" */
+    0x43,0x49,0x55,0x0C,0x00,0x00,0x00,0x08,  /* 00002370    "CIU....." */
+    0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00002378    "..\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x53,0x32,0x37,  /* 00002380    "_PCI0S27" */
+    0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03,  /* 00002388    "_..){\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00002390    "_SB_PCI0" */
+    0x50,0x43,0x49,0x44,0x0C,0x00,0x00,0x00,  /* 00002398    "PCID...." */
+    0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 000023A0    "...\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x32,  /* 000023A8    "B_PCI0S2" */
+    0x37,0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C,  /* 000023B0    "7_...({\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 000023B8    "/._SB_PC" */
+    0x49,0x30,0x50,0x43,0x49,0x55,0x0C,0x00,  /* 000023C0    "I0PCIU.." */
+    0x00,0x00,0x10,0x00,0x86,0x5C,0x2F,0x03,  /* 000023C8    ".....\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 000023D0    "_SB_PCI0" */
+    0x53,0x32,0x38,0x5F,0x01,0xA0,0x29,0x7B,  /* 000023D8    "S28_..){" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 000023E0    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0C,  /* 000023E8    "CI0PCID." */
+    0x00,0x00,0x00,0x10,0x00,0x86,0x5C,0x2F,  /* 000023F0    "......\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 000023F8    "._SB_PCI" */
+    0x30,0x53,0x32,0x38,0x5F,0x0A,0x03,0xA0,  /* 00002400    "0S28_..." */
+    0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,  /* 00002408    "({\/._SB" */
+    0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49,  /* 00002410    "_PCI0PCI" */
+    0x55,0x0C,0x00,0x00,0x00,0x20,0x00,0x86,  /* 00002418    "U.... .." */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00002420    "\/._SB_P" */
+    0x43,0x49,0x30,0x53,0x32,0x39,0x5F,0x01,  /* 00002428    "CI0S29_." */
+    0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53,  /* 00002430    ".){\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43,  /* 00002438    "B_PCI0PC" */
+    0x49,0x44,0x0C,0x00,0x00,0x00,0x20,0x00,  /* 00002440    "ID.... ." */
+    0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 00002448    ".\/._SB_" */
+    0x50,0x43,0x49,0x30,0x53,0x32,0x39,0x5F,  /* 00002450    "PCI0S29_" */
+    0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03,  /* 00002458    "...({\/." */
+    0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30,  /* 00002460    "_SB_PCI0" */
+    0x50,0x43,0x49,0x55,0x0C,0x00,0x00,0x00,  /* 00002468    "PCIU...." */
+    0x40,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,  /* 00002470    "@..\/._S" */
+    0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x33,  /* 00002478    "B_PCI0S3" */
+    0x30,0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F,  /* 00002480    "0_..){\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 00002488    "._SB_PCI" */
+    0x30,0x50,0x43,0x49,0x44,0x0C,0x00,0x00,  /* 00002490    "0PCID..." */
+    0x00,0x40,0x00,0x86,0x5C,0x2F,0x03,0x5F,  /* 00002498    ".@..\/._" */
+    0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53,  /* 000024A0    "SB_PCI0S" */
+    0x33,0x30,0x5F,0x0A,0x03,0xA0,0x28,0x7B,  /* 000024A8    "30_...({" */
+    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 000024B0    "\/._SB_P" */
+    0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0C,  /* 000024B8    "CI0PCIU." */
+    0x00,0x00,0x00,0x80,0x00,0x86,0x5C,0x2F,  /* 000024C0    "......\/" */
+    0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,  /* 000024C8    "._SB_PCI" */
+    0x30,0x53,0x33,0x31,0x5F,0x01,0xA0,0x29,  /* 000024D0    "0S31_..)" */
+    0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,  /* 000024D8    "{\/._SB_" */
+    0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x44,  /* 000024E0    "PCI0PCID" */
+    0x0C,0x00,0x00,0x00,0x80,0x00,0x86,0x5C,  /* 000024E8    ".......\" */
+    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 000024F0    "/._SB_PC" */
+    0x49,0x30,0x53,0x33,0x31,0x5F,0x0A,0x03,  /* 000024F8    "I0S31_.." */
+    0xA4,0x01,0x14,0x11,0x5F,0x4C,0x30,0x32,  /* 00002500    "...._L02" */
+    0x00,0xA4,0x5C,0x2E,0x5F,0x53,0x42,0x5F,  /* 00002508    "..\._SB_" */
+    0x50,0x52,0x53,0x43,0x14,0x08,0x5F,0x4C,  /* 00002510    "PRSC.._L" */
+    0x30,0x33,0x00,0xA4,0x01,0x14,0x08,0x5F,  /* 00002518    "03....._" */
+    0x4C,0x30,0x34,0x00,0xA4,0x01,0x14,0x08,  /* 00002520    "L04....." */
+    0x5F,0x4C,0x30,0x35,0x00,0xA4,0x01,0x14,  /* 00002528    "_L05...." */
+    0x08,0x5F,0x4C,0x30,0x36,0x00,0xA4,0x01,  /* 00002530    "._L06..." */
+    0x14,0x08,0x5F,0x4C,0x30,0x37,0x00,0xA4,  /* 00002538    ".._L07.." */
+    0x01,0x14,0x08,0x5F,0x4C,0x30,0x38,0x00,  /* 00002540    "..._L08." */
+    0xA4,0x01,0x14,0x08,0x5F,0x4C,0x30,0x39,  /* 00002548    "...._L09" */
+    0x00,0xA4,0x01,0x14,0x08,0x5F,0x4C,0x30,  /* 00002550    "....._L0" */
+    0x41,0x00,0xA4,0x01,0x14,0x08,0x5F,0x4C,  /* 00002558    "A....._L" */
+    0x30,0x42,0x00,0xA4,0x01,0x14,0x08,0x5F,  /* 00002560    "0B....._" */
+    0x4C,0x30,0x43,0x00,0xA4,0x01,0x14,0x08,  /* 00002568    "L0C....." */
+    0x5F,0x4C,0x30,0x44,0x00,0xA4,0x01,0x14,  /* 00002570    "_L0D...." */
+    0x08,0x5F,0x4C,0x30,0x45,0x00,0xA4,0x01,  /* 00002578    "._L0E..." */
+    0x14,0x08,0x5F,0x4C,0x30,0x46,0x00,0xA4,  /* 00002580    ".._L0F.." */
+    0x01                                      /* 00002588    "."        */
+};
diff --git a/bios/seabios/src/acpi.c b/bios/seabios/src/acpi.c
new file mode 100644 (file)
index 0000000..95575a1
--- /dev/null
@@ -0,0 +1,750 @@
+// Support for generating ACPI tables (on emulators)
+//
+// 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 "acpi.h" // struct rsdp_descriptor
+#include "util.h" // memcpy
+#include "pci.h" // pci_find_init_device
+#include "biosvar.h" // GET_EBDA
+#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "pci_regs.h" // PCI_INTERRUPT_LINE
+#include "paravirt.h"
+
+/****************************************************/
+/* ACPI tables init */
+
+/* Table structure from Linux kernel (the ACPI tables are under the
+   BSD license) */
+
+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 S4bios_f        : 1;    /* Indicates if S4BIOS support is present */
+    u32 reserved1       : 31;   /* Must be 0 */
+    u8  resverved3 [40];        /* Reserved - must be zero */
+} PACKED;
+
+
+/*
+ * 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 */
+#if 0
+    u32 PCATcompat      : 1;    /* A one indicates system also has dual 8259s */
+    u32 reserved1       : 31;
+#else
+    u32 flags;
+#endif
+} 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 */
+#if 0
+    u32 processor_enabled: 1;   /* Processor is usable if set */
+    u32 reserved2       : 31;   /* Reserved, must be zero */
+#else
+    u32 flags;
+#endif
+} 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;
+
+/* IRQs 5,9,10,11 */
+#define PCI_ISA_IRQ_MASK    0x0e20
+
+struct madt_intsrcovr {
+    ACPI_SUB_HEADER_DEF
+    u8  bus;
+    u8  source;
+    u32 gsi;
+    u16 flags;
+} PACKED;
+
+/*
+ * 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;
+
+/*
+ * HPET Description Table
+ */
+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;
+
+#define HPET_ID         0x000
+#define HPET_PERIOD     0x004
+
+/*
+ * SRAT (NUMA topology description) table
+ */
+
+#define SRAT_PROCESSOR          0
+#define SRAT_MEMORY             1
+
+struct system_resource_affinity_table
+{
+    ACPI_TABLE_HEADER_DEF
+    u32    reserved1;
+    u32    reserved2[2];
+} PACKED;
+
+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;
+    u32    base_addr_low,base_addr_high;
+    u32    length_low,length_high;
+    u32    reserved2;
+    u32    flags;
+    u32    reserved3[2];
+} PACKED;
+
+#include "acpi-dsdt.hex"
+
+static void
+build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev)
+{
+    h->signature = sig;
+    h->length = cpu_to_le32(len);
+    h->revision = rev;
+    memcpy(h->oem_id, CONFIG_APPNAME6, 6);
+    memcpy(h->oem_table_id, CONFIG_APPNAME4, 4);
+    memcpy(h->oem_table_id + 4, (void*)&sig, 4);
+    h->oem_revision = cpu_to_le32(1);
+    memcpy(h->asl_compiler_id, CONFIG_APPNAME4, 4);
+    h->asl_compiler_revision = cpu_to_le32(1);
+    h->checksum -= checksum(h, len);
+}
+
+#define PIIX4_ACPI_ENABLE       0xf1
+#define PIIX4_ACPI_DISABLE      0xf0
+#define PIIX4_GPE0_BLK          0xafe0
+#define PIIX4_GPE0_BLK_LEN      4
+
+static void piix4_fadt_init(struct pci_device *pci, void *arg)
+{
+    struct fadt_descriptor_rev1 *fadt = arg;
+    fadt->acpi_enable = PIIX4_ACPI_ENABLE;
+    fadt->acpi_disable = PIIX4_ACPI_DISABLE;
+    fadt->gpe0_blk = cpu_to_le32(PIIX4_GPE0_BLK);
+    fadt->gpe0_blk_len = PIIX4_GPE0_BLK_LEN;
+}
+
+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_init),
+
+    PCI_DEVICE_END
+};
+
+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));
+    void *dsdt = malloc_high(sizeof(AmlCode));
+
+    if (!fadt || !facs || !dsdt) {
+        warn_noalloc();
+        return NULL;
+    }
+
+    /* FACS */
+    memset(facs, 0, sizeof(*facs));
+    facs->signature = FACS_SIGNATURE;
+    facs->length = cpu_to_le32(sizeof(*facs));
+
+    /* DSDT */
+    memcpy(dsdt, AmlCode, sizeof(AmlCode));
+
+    /* FADT */
+    memset(fadt, 0, sizeof(*fadt));
+    fadt->firmware_ctrl = cpu_to_le32((u32)facs);
+    fadt->dsdt = cpu_to_le32((u32)dsdt);
+    fadt->model = 1;
+    fadt->reserved1 = 0;
+
+    if (pci) {
+       int pm_sci_int = pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE);
+
+       fadt->sci_int = cpu_to_le16(pm_sci_int);
+       fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
+       fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE);
+       fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04);
+       fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08);
+       fadt->pm1_evt_len = 4;
+       fadt->pm1_cnt_len = 2;
+       fadt->pm_tmr_len = 4;
+
+
+       fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+       fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+       pci_init_device(fadt_init_tbl, pci, fadt);
+    } else {
+
+       fadt->sci_int = 0;
+       fadt->smi_cmd = 0;
+       fadt->pm1a_evt_blk = 0;
+       fadt->pm1a_cnt_blk = 0;
+       fadt->pm_tmr_blk = 0;
+       fadt->pm1_evt_len = 0;
+       fadt->pm1_cnt_len = 0;
+       fadt->pm_tmr_len = 0;
+
+
+       fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+       fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+       
+       // No PIIX4 to init
+       //      pci_init_device(fadt_init_tbl, pci, fadt);
+
+    }
+
+    /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC + RTC_S4 */
+    fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6) | (1 << 7));
+
+    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);
+    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 (i < CountCPUs)
+            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 = CountCPUs;
+    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 (qemu_cfg_irq0_override()) {
+        memset(intsrcovr, 0, sizeof(*intsrcovr));
+        intsrcovr->type   = APIC_XRUPT_OVERRIDE;
+        intsrcovr->length = sizeof(*intsrcovr);
+        intsrcovr->source = 0;
+        intsrcovr->gsi    = 2;
+        intsrcovr->flags  = 0; /* conforms to bus specifications */
+        intsrcovr++;
+    }
+    for (i = 1; i < 16; i++) {
+        if (!(PCI_ISA_IRQ_MASK & (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    = i;
+        intsrcovr->flags  = 0xd; /* active high, level triggered */
+        intsrcovr++;
+    }
+
+    build_header((void*)madt, APIC_SIGNATURE, (void*)intsrcovr - (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;
+}
+
+// AML Processor() object.  See src/ssdt-proc.dsl for info.
+static unsigned char ssdt_proc[] = {
+    0x5b,0x83,0x42,0x05,0x43,0x50,0x41,0x41,
+    0xaa,0x10,0xb0,0x00,0x00,0x06,0x08,0x49,
+    0x44,0x5f,0x5f,0x0a,0xaa,0x08,0x5f,0x48,
+    0x49,0x44,0x0d,0x41,0x43,0x50,0x49,0x30,
+    0x30,0x30,0x37,0x00,0x14,0x0f,0x5f,0x4d,
+    0x41,0x54,0x00,0xa4,0x43,0x50,0x4d,0x41,
+    0x49,0x44,0x5f,0x5f,0x14,0x0f,0x5f,0x53,
+    0x54,0x41,0x00,0xa4,0x43,0x50,0x53,0x54,
+    0x49,0x44,0x5f,0x5f,0x14,0x0f,0x5f,0x45,
+    0x4a,0x30,0x01,0x43,0x50,0x45,0x4a,0x49,
+    0x44,0x5f,0x5f,0x68
+};
+#define SD_OFFSET_CPUHEX 6
+#define SD_OFFSET_CPUID1 8
+#define SD_OFFSET_CPUID2 20
+
+#define SSDT_SIGNATURE 0x54445353 // SSDT
+static void*
+build_ssdt(void)
+{
+    int acpi_cpus = MaxCountCPUs > 0xff ? 0xff : MaxCountCPUs;
+    // length = ScopeOp + procs + NTYF method + CPON package
+    int length = ((1+3+4)
+                  + (acpi_cpus * sizeof(ssdt_proc))
+                  + (1+2+5+(12*acpi_cpus))
+                  + (6+2+1+(1*acpi_cpus)));
+    u8 *ssdt = malloc_high(sizeof(struct acpi_table_header) + length);
+    if (! ssdt) {
+        warn_noalloc();
+        return NULL;
+    }
+    u8 *ssdt_ptr = ssdt + sizeof(struct acpi_table_header);
+
+    // build Scope(_SB_) header
+    *(ssdt_ptr++) = 0x10; // ScopeOp
+    ssdt_ptr = encodeLen(ssdt_ptr, length-1, 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, ssdt_proc, sizeof(ssdt_proc));
+        ssdt_ptr[SD_OFFSET_CPUHEX] = getHex(i >> 4);
+        ssdt_ptr[SD_OFFSET_CPUHEX+1] = getHex(i);
+        ssdt_ptr[SD_OFFSET_CPUID1] = i;
+        ssdt_ptr[SD_OFFSET_CPUID2] = i;
+        ssdt_ptr += sizeof(ssdt_proc);
+    }
+
+    // build "Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...}"
+    *(ssdt_ptr++) = 0x14; // MethodOp
+    ssdt_ptr = encodeLen(ssdt_ptr, 2+5+(12*acpi_cpus), 2);
+    *(ssdt_ptr++) = 'N';
+    *(ssdt_ptr++) = 'T';
+    *(ssdt_ptr++) = 'F';
+    *(ssdt_ptr++) = 'Y';
+    *(ssdt_ptr++) = 0x02;
+    for (i=0; i<acpi_cpus; 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
+        *(ssdt_ptr++) = 'C';
+        *(ssdt_ptr++) = 'P';
+        *(ssdt_ptr++) = getHex(i >> 4);
+        *(ssdt_ptr++) = getHex(i);
+        *(ssdt_ptr++) = 0x69; // Arg1Op
+    }
+
+    // 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++) = (i < CountCPUs) ? 0x01 : 0x00;
+
+    build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
+
+    //hexdump(ssdt, ssdt_ptr - ssdt);
+
+    return ssdt;
+}
+
+#define HPET_SIGNATURE 0x54455048 // HPET
+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_le32(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_low = base & 0xFFFFFFFF;
+    numamem->base_addr_high = base >> 32;
+    numamem->length_low = len & 0xFFFFFFFF;
+    numamem->length_high = len >> 32;
+}
+
+#define SRAT_SIGNATURE 0x54415253 // SRAT
+static void *
+build_srat(void)
+{
+    int nb_numa_nodes = qemu_cfg_get_numa_nodes();
+
+    if (nb_numa_nodes == 0)
+        return NULL;
+
+    u64 *numadata = malloc_tmphigh(sizeof(u64) * (MaxCountCPUs + nb_numa_nodes));
+    if (!numadata) {
+        warn_noalloc();
+        return NULL;
+    }
+
+    qemu_cfg_get_numa_data(numadata, MaxCountCPUs + nb_numa_nodes);
+
+    struct system_resource_affinity_table *srat;
+    int srat_size = sizeof(*srat) +
+        sizeof(struct srat_processor_affinity) * MaxCountCPUs +
+        sizeof(struct srat_memory_affinity) * (nb_numa_nodes + 2);
+
+    srat = malloc_high(srat_size);
+    if (!srat) {
+        warn_noalloc();
+        free(numadata);
+        return NULL;
+    }
+
+    memset(srat, 0, srat_size);
+    srat->reserved1=1;
+    struct srat_processor_affinity *core = (void*)(srat + 1);
+    int i;
+    u64 curnode;
+
+    for (i = 0; i < MaxCountCPUs; ++i) {
+        core->type = SRAT_PROCESSOR;
+        core->length = sizeof(*core);
+        core->local_apic_id = i;
+        curnode = *numadata++;
+        core->proximity_lo = curnode;
+        memset(core->proximity_hi, 0, 3);
+        core->local_sapic_eid = 0;
+        if (i < CountCPUs)
+            core->flags = cpu_to_le32(1);
+        else
+            core->flags = 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);
+    return srat;
+}
+
+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_END,
+};
+
+struct rsdp_descriptor *RsdpAddr;
+
+#define MAX_ACPI_TABLES 20
+void
+acpi_bios_init(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;
+    */
+    if (!pci) {
+       /* JRL: No PIIX4: Disable power management ACPI functions */
+       dprintf(1, "No PIIX4 (v3vee): Disabling ACPI power management functions\n");
+    }
+
+
+    // Build ACPI tables
+    u32 tables[MAX_ACPI_TABLES], tbl_idx = 0;
+
+#define ACPI_INIT_TABLE(X)                                   \
+    do {                                                     \
+        tables[tbl_idx] = (u32)(X);                          \
+        if (tables[tbl_idx])                                 \
+            tbl_idx++;                                       \
+    } while(0)
+
+    ACPI_INIT_TABLE(build_fadt(pci));
+    ACPI_INIT_TABLE(build_ssdt());
+    ACPI_INIT_TABLE(build_madt());
+    if (pci) {
+       ACPI_INIT_TABLE(build_hpet());
+    }
+    ACPI_INIT_TABLE(build_srat());
+
+    u16 i, external_tables = qemu_cfg_acpi_additional_tables();
+
+    for (i = 0; i < external_tables; i++) {
+        u16 len = qemu_cfg_next_acpi_table_len();
+        void *addr = malloc_high(len);
+        if (!addr) {
+            warn_noalloc();
+            continue;
+        }
+        ACPI_INIT_TABLE(qemu_cfg_next_acpi_table_load(addr, len));
+        if (tbl_idx == MAX_ACPI_TABLES) {
+            warn_noalloc();
+            break;
+        }
+    }
+
+    // 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 = malloc_fseg(sizeof(*rsdp));
+    if (!rsdp) {
+        warn_noalloc();
+        return;
+    }
+    memset(rsdp, 0, sizeof(*rsdp));
+    rsdp->signature = RSDP_SIGNATURE;
+    memcpy(rsdp->oem_id, CONFIG_APPNAME6, 6);
+    rsdp->rsdt_physical_address = cpu_to_le32((u32)rsdt);
+    rsdp->checksum -= checksum(rsdp, 20);
+    RsdpAddr = rsdp;
+    dprintf(1, "ACPI tables: RSDP=%p RSDT=%p\n", rsdp, rsdt);
+}
+
+u32
+find_resume_vector(void)
+{
+    dprintf(4, "rsdp=%p\n", RsdpAddr);
+    if (!RsdpAddr || RsdpAddr->signature != RSDP_SIGNATURE)
+        return 0;
+    struct rsdt_descriptor_rev1 *rsdt = (void*)RsdpAddr->rsdt_physical_address;
+    dprintf(4, "rsdt=%p\n", rsdt);
+    if (!rsdt || rsdt->signature != RSDT_SIGNATURE)
+        return 0;
+    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);
+        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;
+    }
+    return 0;
+}
diff --git a/bios/seabios/src/acpi.h b/bios/seabios/src/acpi.h
new file mode 100644 (file)
index 0000000..e01315a
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef __ACPI_H
+#define __ACPI_H
+
+#include "types.h" // u32
+
+void acpi_bios_init(void);
+u32 find_resume_vector(void);
+
+#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 */
+};
+
+extern struct rsdp_descriptor *RsdpAddr;
+
+/* 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 */
+
+
+/*
+ * 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 */
+#if 0
+    u32 wb_invd         : 1;    /* The wbinvd instruction works properly */
+    u32 wb_invd_flush   : 1;    /* The wbinvd flushes but does not invalidate */
+    u32 proc_c1         : 1;    /* All processors support C1 state */
+    u32 plvl2_up        : 1;    /* C2 state works on MP system */
+    u32 pwr_button      : 1;    /* Power button is handled as a generic feature */
+    u32 sleep_button    : 1;    /* Sleep button is handled as a generic feature, or not present */
+    u32 fixed_rTC       : 1;    /* RTC wakeup stat not in fixed register space */
+    u32 rtcs4           : 1;    /* RTC wakeup stat not possible from S4 */
+    u32 tmr_val_ext     : 1;    /* The tmr_val width is 32 bits (0 = 24 bits) */
+    u32 reserved5       : 23;   /* Reserved - must be zero */
+#else
+    u32 flags;
+#endif
+} PACKED;
+
+#endif // acpi.h
diff --git a/bios/seabios/src/ahci.c b/bios/seabios/src/ahci.c
new file mode 100644 (file)
index 0000000..9b3ce2f
--- /dev/null
@@ -0,0 +1,666 @@
+// 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 "types.h" // u8
+#include "ioport.h" // inb
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "pci.h" // foreachpci
+#include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER
+#include "pci_regs.h" // PCI_INTERRUPT_LINE
+#include "boot.h" // add_bcv_hd
+#include "disk.h" // struct ata_s
+#include "ata.h" // ATA_CB_STAT
+#include "ahci.h" // CDB_CMD_READ_10
+#include "blockcmd.h" // CDB_CMD_READ_10
+
+#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
+
+/****************************************************************
+ * these bits must run in both 16bit and 32bit modes
+ ****************************************************************/
+
+// prepare sata command fis
+static void sata_prep_simple(struct sata_cmd_fis *fis, u8 command)
+{
+    memset_fl(fis, 0, sizeof(*fis));
+    SET_FLATPTR(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)) {
+        SET_FLATPTR(fis->sector_count2, op->count >> 8);
+        SET_FLATPTR(fis->lba_low2,      lba >> 24);
+        SET_FLATPTR(fis->lba_mid2,      lba >> 32);
+        SET_FLATPTR(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);
+    }
+    SET_FLATPTR(fis->feature,      1); /* dma */
+    SET_FLATPTR(fis->command,      command);
+    SET_FLATPTR(fis->sector_count, op->count);
+    SET_FLATPTR(fis->lba_low,      lba);
+    SET_FLATPTR(fis->lba_mid,      lba >> 8);
+    SET_FLATPTR(fis->lba_high,     lba >> 16);
+    SET_FLATPTR(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));
+    SET_FLATPTR(fis->command,  ATA_CMD_PACKET);
+    SET_FLATPTR(fis->feature,  1); /* dma */
+    SET_FLATPTR(fis->lba_mid,  blocksize);
+    SET_FLATPTR(fis->lba_high, blocksize >> 8);
+}
+
+// ahci register access helpers
+static u32 ahci_ctrl_readl(struct ahci_ctrl_s *ctrl, u32 reg)
+{
+    u32 addr = GET_GLOBALFLAT(ctrl->iobase) + reg;
+    return pci_readl(addr);
+}
+
+static void ahci_ctrl_writel(struct ahci_ctrl_s *ctrl, u32 reg, u32 val)
+{
+    u32 addr = GET_GLOBALFLAT(ctrl->iobase) + reg;
+    pci_writel(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, int iswrite, int isatapi,
+                        void *buffer, u32 bsize)
+{
+    u32 val, status, success, flags, intbits, error;
+    struct ahci_ctrl_s *ctrl = GET_GLOBAL(port->ctrl);
+    struct ahci_cmd_s  *cmd  = GET_GLOBAL(port->cmd);
+    struct ahci_fis_s  *fis  = GET_GLOBAL(port->fis);
+    struct ahci_list_s *list = GET_GLOBAL(port->list);
+    u32 pnr                  = GET_GLOBAL(port->pnr);
+    u64 end;
+
+    SET_FLATPTR(cmd->fis.reg,       0x27);
+    SET_FLATPTR(cmd->fis.pmp_type,  (1 << 7)); /* cmd fis */
+    SET_FLATPTR(cmd->prdt[0].base,  ((u32)buffer));
+    SET_FLATPTR(cmd->prdt[0].baseu, 0);
+    SET_FLATPTR(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) */
+    SET_FLATPTR(list[0].flags,  flags);
+    SET_FLATPTR(list[0].bytes,  0);
+    SET_FLATPTR(list[0].base,   ((u32)(cmd)));
+    SET_FLATPTR(list[0].baseu,  0);
+
+    dprintf(2, "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);
+
+    end = calc_future_tsc(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_FLATPTR(fis->psfis[2]);
+                    error  = GET_FLATPTR(fis->psfis[3]);
+                    break;
+                }
+                if (intbits & 0x01) {
+                    status = GET_FLATPTR(fis->rfis[2]);
+                    error  = GET_FLATPTR(fis->rfis[3]);
+                    break;
+                }
+            }
+            if (check_tsc(end)) {
+                warn_timeout();
+                return -1;
+            }
+            yield();
+        }
+        dprintf(2, "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(2, "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 = container_of(
+        op->drive_g, struct ahci_port_s, drive);
+    struct ahci_cmd_s *cmd = GET_GLOBAL(port->cmd);
+    u8 *atapi = cdbcmd;
+    int i, rc;
+
+    sata_prep_atapi(&cmd->fis, blocksize);
+    for (i = 0; i < CDROM_CDB_SIZE; i++) {
+        SET_FLATPTR(cmd->atapi[i], atapi[i]);
+    }
+    rc = ahci_command(port, 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 = container_of(
+        op->drive_g, struct ahci_port_s, drive);
+    struct ahci_cmd_s *cmd = GET_GLOBAL(port->cmd);
+    int rc;
+
+    sata_prep_readwrite(&cmd->fis, op, iswrite);
+    rc = ahci_command(port, iswrite, 0, op->buf_fl,
+                      op->count * DISK_SECTOR_SIZE);
+    dprintf(2, "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 = GET_GLOBAL(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 process_ahci_op(struct disk_op_s *op)
+{
+    struct ahci_port_s *port;
+    u32 atapi;
+
+    if (!CONFIG_AHCI)
+        return 0;
+
+    port = container_of(op->drive_g, struct ahci_port_s, drive);
+    atapi = GET_GLOBAL(port->atapi);
+
+    if (atapi) {
+        switch (op->command) {
+        case CMD_READ:
+            return cdb_read(op);
+        case CMD_WRITE:
+        case CMD_FORMAT:
+            return DISK_RET_EWRITEPROTECT;
+        case CMD_RESET:
+            /* FIXME: what should we do here? */
+        case CMD_VERIFY:
+        case CMD_SEEK:
+            return DISK_RET_SUCCESS;
+        default:
+            dprintf(1, "AHCI: unknown cdrom command %d\n", op->command);
+            op->count = 0;
+            return DISK_RET_EPARAM;
+        }
+    } else {
+        switch (op->command) {
+        case CMD_READ:
+            return ahci_disk_readwrite(op, 0);
+        case CMD_WRITE:
+            return ahci_disk_readwrite(op, 1);
+        case CMD_RESET:
+            /* FIXME: what should we do here? */
+        case CMD_FORMAT:
+        case CMD_VERIFY:
+        case CMD_SEEK:
+            return DISK_RET_SUCCESS;
+        default:
+            dprintf(1, "AHCI: unknown disk command %d\n", op->command);
+            op->count = 0;
+            return DISK_RET_EPARAM;
+        }
+    }
+}
+
+/****************************************************************
+ * everything below is pure 32bit code
+ ****************************************************************/
+
+static void
+ahci_port_reset(struct ahci_ctrl_s *ctrl, u32 pnr)
+{
+    u32 val;
+    u64 end;
+
+    /* disable FIS + CMD */
+    end = calc_future_tsc(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 (check_tsc(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 struct ahci_port_s* ahci_port_realloc(struct ahci_port_s *port)
+{
+    struct ahci_port_s *tmp;
+    u32 cmd;
+
+    tmp = malloc_fseg(sizeof(*port));
+    *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_low(1024, 1024);
+    port->fis = memalign_low(256, 256);
+    port->cmd = memalign_low(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;
+}
+
+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);
+}
+
+#define MAXMODEL 40
+
+/* See ahci spec chapter 10.1 "Software Initialization of HBA" */
+static int ahci_port_init(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;
+    u64 end;
+    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);
+    end = calc_future_tsc(AHCI_LINK_TIMEOUT);
+    for (;;) {
+        stat = ahci_port_readl(ctrl, pnr, PORT_SCR_STAT);
+        if ((stat & 0x07) == 0x03) {
+            dprintf(1, "AHCI/%d: link up\n", port->pnr);
+            break;
+        }
+        if (check_tsc(end)) {
+            dprintf(1, "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 = calc_future_tsc(AHCI_REQUEST_TIMEOUT);
+    for (;;) {
+        tf = ahci_port_readl(ctrl, pnr, PORT_TFDATA);
+        if (!(tf & (ATA_CB_STAT_BSY |
+                    ATA_CB_STAT_DRQ)))
+            break;
+        if (check_tsc(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.type = DTYPE_AHCI;
+    port->drive.cntl_id = pnr;
+    port->drive.removable = (buffer[0] & 0x80) ? 1 : 0;
+
+    if (!port->atapi) {
+        // found disk (ata)
+        port->drive.blksize = DISK_SECTOR_SIZE;
+        port->drive.pchs.cylinders = buffer[1];
+        port->drive.pchs.heads = buffer[3];
+        port->drive.pchs.spt = 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.blksize = CDROM_SECTOR_SIZE;
+        port->drive.sectors = (u64)-1;
+        u8 iscd = ((buffer[0] >> 8) & 0x1f) == 0x05;
+        if (!iscd) {
+            dprintf(1, "AHCI/%d: atapi device is'nt 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_init(port);
+    if (rc < 0)
+        ahci_port_release(port);
+    else {
+        port = ahci_port_realloc(port);
+        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_init_controller(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 (bounce_buf_init() < 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 = ctrl->caps & 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_init(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_init_controller(pci);
+    }
+}
+
+void
+ahci_setup(void)
+{
+    ASSERT32FLAT();
+    if (!CONFIG_AHCI)
+        return;
+
+    dprintf(3, "init ahci\n");
+    ahci_init();
+}
diff --git a/bios/seabios/src/ahci.h b/bios/seabios/src/ahci.h
new file mode 100644 (file)
index 0000000..c3d3a70
--- /dev/null
@@ -0,0 +1,199 @@
+#ifndef __AHCI_H
+#define __AHCI_H
+
+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/bios/seabios/src/apm.c b/bios/seabios/src/apm.c
new file mode 100644 (file)
index 0000000..c497dbe
--- /dev/null
@@ -0,0 +1,238 @@
+// 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 "farptr.h" // GET_VAR
+#include "bregs.h" // struct bregs
+#include "ioport.h" // outb
+#include "util.h" // wait_irq
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+
+static void
+out_str(const char *str_cs)
+{
+    if (CONFIG_COREBOOT) {
+        dprintf(1, "APM request '%s'\n", str_cs);
+        return;
+    }
+
+    u8 *s = (u8*)str_cs;
+    for (;;) {
+        u8 c = GET_GLOBAL(*s);
+        if (!c)
+            break;
+        outb(c, PORT_BIOS_APM);
+        s++;
+    }
+}
+
+// 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);
+}
+
+// Assembler entry points defined in romlayout.S
+extern void entry_apm16(void);
+extern void entry_apm32(void);
+
+// APM 16 bit protected mode interface connect
+static void
+handle_155302(struct bregs *regs)
+{
+    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)
+{
+    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)
+{
+    wait_irq();
+    set_success(regs);
+}
+
+// APM cpu busy
+static void
+handle_155306(struct bregs *regs)
+{
+    set_success(regs);
+}
+
+void
+apm_shutdown(void)
+{
+    irq_disable();
+    out_str("Shutdown");
+    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:
+        out_str("Standby");
+        break;
+    case 2:
+        out_str("Suspend");
+        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
+handle_apm16(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_apm);
+    handle_1553(regs);
+}
+
+void VISIBLE32SEG
+handle_apm32(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_apm);
+    handle_1553(regs);
+}
diff --git a/bios/seabios/src/asm-offsets.c b/bios/seabios/src/asm-offsets.c
new file mode 100644 (file)
index 0000000..5035cef
--- /dev/null
@@ -0,0 +1,31 @@
+// Generate assembler offsets.
+
+#include "gen-defs.h" // OFFSET
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // struct bios_data_area_s
+
+/* 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);
+
+    COMMENT("BDA");
+    OFFSET(BDA_ebda_seg, bios_data_area_s, ebda_seg);
+
+    COMMENT("EBDA");
+    DEFINE(EBDA_OFFSET_TOP_STACK, EBDA_OFFSET_TOP_STACK);
+    DEFINE(EBDA_SEGMENT_START, EBDA_SEGMENT_START);
+}
diff --git a/bios/seabios/src/ata.c b/bios/seabios/src/ata.c
new file mode 100644 (file)
index 0000000..76e4f20
--- /dev/null
@@ -0,0 +1,1071 @@
+// 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 "types.h" // u8
+#include "ioport.h" // inb
+#include "util.h" // dprintf
+#include "cmos.h" // inb_cmos
+#include "pic.h" // enable_hwirq
+#include "biosvar.h" // GET_EBDA
+#include "pci.h" // foreachpci
+#include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER
+#include "pci_regs.h" // PCI_INTERRUPT_LINE
+#include "boot.h" // boot_add_hd
+#include "disk.h" // struct ata_s
+#include "ata.h" // ATA_CB_STAT
+#include "blockcmd.h" // CDB_CMD_READ_10
+
+#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)
+{
+    u64 end = calc_future_tsc(timeout);
+    for (;;) {
+        u8 status = inb(base+ATA_CB_STAT);
+        if ((status & mask) == flags)
+            return status;
+        if (check_tsc(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_g)
+{
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+    u8 slave = GET_GLOBAL(adrive_g->slave);
+    u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+    u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+
+    dprintf(6, "ata_reset drive=%p\n", &adrive_g->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.
+        u64 end = calc_future_tsc(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 (check_tsc(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_GLOBAL(adrive_g->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_g)
+{
+    // Read the status from controller
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->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;
+}
+
+// Default 16bit command demuxer for ATA and ATAPI devices.
+static int
+process_ata_misc_op(struct disk_op_s *op)
+{
+    if (!CONFIG_ATA)
+        return 0;
+
+    struct atadrive_s *adrive_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    switch (op->command) {
+    case CMD_RESET:
+        ata_reset(adrive_g);
+        return DISK_RET_SUCCESS;
+    case CMD_ISREADY:
+        return isready(adrive_g);
+    case CMD_FORMAT:
+    case CMD_VERIFY:
+    case CMD_SEEK:
+        return DISK_RET_SUCCESS;
+    default:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
+
+
+/****************************************************************
+ * 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_g, struct ata_pio_command *cmd)
+{
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+    u8 slave = GET_GLOBAL(adrive_g->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_g, struct ata_pio_command *cmd)
+{
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->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_g, 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_g'.
+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_g, iswrite, op->count, blocksize, op->buf_fl);
+
+    struct atadrive_s *adrive_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->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_g, 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_g, buf_fl);
+            if (CONFIG_ATA_PIO32)
+                insl_fl(iobase1, buf_fl, blocksize / 4);
+            else
+                insw_fl(iobase1, buf_fl, blocksize / 2);
+        }
+        buf_fl += blocksize;
+
+        status = pause_await_not_bsy(iobase1, iobase2);
+        if (status < 0) {
+            // Error
+            op->count -= count;
+            return status;
+        }
+
+        count--;
+        if (!count)
+            break;
+        status &= (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR);
+        if (status != ATA_CB_STAT_DRQ) {
+            dprintf(6, "ata_pio_transfer : more sectors left (status %02x)\n"
+                    , status);
+            op->count -= count;
+            return -6;
+        }
+    }
+
+    status &= (ATA_CB_STAT_BSY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ
+               | ATA_CB_STAT_ERR);
+    if (!iswrite)
+        status &= ~ATA_CB_STAT_DF;
+    if (status != 0) {
+        dprintf(6, "ata_pio_transfer : no sectors left (status %02x)\n", status);
+        return -7;
+    }
+
+    return 0;
+}
+
+
+/****************************************************************
+ * ATA DMA transfers
+ ****************************************************************/
+
+#define BM_CMD    0
+#define  BM_CMD_MEMWRITE  0x08
+#define  BM_CMD_START     0x01
+#define BM_STATUS 2
+#define  BM_STATUS_IRQ    0x04
+#define  BM_STATUS_ERROR  0x02
+#define  BM_STATUS_ACTIVE 0x01
+#define BM_TABLE  4
+
+struct sff_dma_prd {
+    u32 buf_fl;
+    u32 count;
+};
+
+// Check if DMA available and setup transfer if so.
+static int
+ata_try_dma(struct disk_op_s *op, int iswrite, int blocksize)
+{
+    if (! CONFIG_ATA_DMA)
+        return -1;
+    u32 dest = (u32)op->buf_fl;
+    if (dest & 1)
+        // Need minimum alignment of 1.
+        return -1;
+    struct atadrive_s *adrive_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->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(
+        get_ebda_seg()
+        , (void*)offsetof(struct extended_bios_data_area_s, extra_stack));
+    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_FLATPTR(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_FLATPTR(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_g, op->buf_fl);
+
+    struct atadrive_s *adrive_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->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);
+
+    u64 end = calc_future_tsc(IDE_TIMEOUT);
+    u8 status;
+    for (;;) {
+        status = inb(iomaster + BM_STATUS);
+        if (status & BM_STATUS_IRQ)
+            break;
+        // Transfer in progress
+        if (check_tsc(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));
+    op->count = 0;
+    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_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->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_g, 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_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    int ret = send_cmd(adrive_g, 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;
+
+    switch (op->command) {
+    case CMD_READ:
+        return ata_readwrite(op, 0);
+    case CMD_WRITE:
+        return ata_readwrite(op, 1);
+    default:
+        return process_ata_misc_op(op);
+    }
+}
+
+
+/****************************************************************
+ * 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_g = container_of(
+        op->drive_g, struct atadrive_s, drive);
+    struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->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_g, &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 (!(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;
+}
+
+// 16bit command demuxer for ATAPI cdroms.
+int
+process_atapi_op(struct disk_op_s *op)
+{
+    if (!CONFIG_ATA)
+        return 0;
+    switch (op->command) {
+    case CMD_READ:
+        return cdb_read(op);
+    case CMD_FORMAT:
+    case CMD_WRITE:
+        return DISK_RET_EWRITEPROTECT;
+    default:
+        return process_ata_misc_op(op);
+    }
+}
+
+
+/****************************************************************
+ * ATA detect and init
+ ****************************************************************/
+
+// Send an identify device or identify device packet command.
+static int
+send_ata_identity(struct atadrive_s *adrive_g, u16 *buffer, int command)
+{
+    memset(buffer, 0, DISK_SECTOR_SIZE);
+
+    struct disk_op_s dop;
+    memset(&dop, 0, sizeof(dop));
+    dop.drive_g = &adrive_g->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] = ntohs(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_g = malloc_fseg(sizeof(*adrive_g));
+    if (!adrive_g) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(adrive_g, 0, sizeof(*adrive_g));
+    adrive_g->chan_gf = dummy->chan_gf;
+    adrive_g->slave = dummy->slave;
+    adrive_g->drive.cntl_id = adrive_g->chan_gf->chanid * 2 + dummy->slave;
+    adrive_g->drive.removable = (buffer[0] & 0x80) ? 1 : 0;
+    return adrive_g;
+}
+
+// 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_g = init_atadrive(dummy, buffer);
+    if (!adrive_g)
+        return NULL;
+    adrive_g->drive.type = DTYPE_ATAPI;
+    adrive_g->drive.blksize = CDROM_SECTOR_SIZE;
+    adrive_g->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_g->chan_gf->chanid, adrive_g->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_g->chan_gf->pci_tmp,
+                                            adrive_g->chan_gf->chanid,
+                                            adrive_g->slave);
+        boot_add_cd(&adrive_g->drive, desc, prio);
+    }
+
+    return adrive_g;
+}
+
+// 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_g = init_atadrive(dummy, buffer);
+    if (!adrive_g)
+        return NULL;
+    adrive_g->drive.type = DTYPE_ATA;
+    adrive_g->drive.blksize = DISK_SECTOR_SIZE;
+
+    adrive_g->drive.pchs.cylinders = buffer[1];
+    adrive_g->drive.pchs.heads = buffer[3];
+    adrive_g->drive.pchs.spt = 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_g->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_g->chan_gf->chanid, adrive_g->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_g->chan_gf->pci_tmp,
+                                        adrive_g->chan_gf->chanid,
+                                        adrive_g->slave);
+    // Register with bcv system.
+    boot_add_hd(&adrive_g->drive, desc, prio);
+
+    return adrive_g;
+}
+
+static u64 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 (check_tsc(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_g = init_drive_atapi(&dummy, buffer);
+        if (!adrive_g) {
+            // 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_g = init_drive_ata(&dummy, buffer);
+            if (!adrive_g)
+                // 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_init(void)
+{
+    if (!CONFIG_COREBOOT && !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 = calc_future_tsc(IDE_TIMEOUT);
+    ata_init();
+
+    SET_BDA(disk_control_byte, 0xc0);
+
+    enable_hwirq(14, FUNC16(entry_76));
+}
diff --git a/bios/seabios/src/ata.h b/bios/seabios/src/ata.h
new file mode 100644 (file)
index 0000000..cfc6108
--- /dev/null
@@ -0,0 +1,154 @@
+#ifndef __ATA_H
+#define __ATA_H
+
+#include "types.h" // u8
+#include "config.h" // CONFIG_MAX_ATA_INTERFACES
+#include "disk.h" // struct drive_s
+
+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);
+int process_atapi_op(struct disk_op_s *op);
+
+// 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/bios/seabios/src/biostables.c b/bios/seabios/src/biostables.c
new file mode 100644 (file)
index 0000000..57a5c57
--- /dev/null
@@ -0,0 +1,108 @@
+// 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 "config.h" // CONFIG_*
+#include "util.h" // dprintf
+#include "pci.h" // struct pir_header
+#include "acpi.h" // struct rsdp_descriptor
+#include "mptable.h" // MPTABLE_SIGNATURE
+#include "smbios.h" // struct smbios_entry_point
+
+void
+copy_pir(void *pos)
+{
+    struct pir_header *p = pos;
+    if (p->signature != PIR_SIGNATURE)
+        return;
+    if (PirOffset)
+        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);
+    PirOffset = (u32)newpos - BUILD_BIOS_ADDR;
+}
+
+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;
+    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);
+}
+
+void
+copy_acpi_rsdp(void *pos)
+{
+    if (RsdpAddr)
+        return;
+    struct rsdp_descriptor *p = pos;
+    if (p->signature != RSDP_SIGNATURE)
+        return;
+    u32 length = 20;
+    if (checksum(pos, length) != 0)
+        return;
+    if (p->revision > 1) {
+        length = p->length;
+        if (checksum(pos, 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
+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;
+}
diff --git a/bios/seabios/src/biosvar.h b/bios/seabios/src/biosvar.h
new file mode 100644 (file)
index 0000000..2b755e3
--- /dev/null
@@ -0,0 +1,332 @@
+// Variable layouts of bios.
+//
+// Copyright (C) 2008-2010  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 "types.h" // u8
+#include "farptr.h" // GET_FARVAR
+#include "config.h" // CONFIG_*
+#include "disk.h" // struct chs_s
+
+
+/****************************************************************
+ * Interupt vector table
+ ****************************************************************/
+
+struct rmode_IVT {
+    struct segoff_s ivec[256];
+};
+
+#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)
+ ****************************************************************/
+
+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[10];
+    u16 vbe_mode;
+} PACKED;
+
+// BDA floppy_recalibration_status bitdefs
+#define FRS_TIMEOUT (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)
+
+// 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))
+#define CLEARBITS_BDA(var, val) do {                                    \
+        typeof(((struct bios_data_area_s *)0)->var) __val = GET_BDA(var); \
+        SET_BDA(var, (__val & ~(val)));                                 \
+    } while (0)
+#define SETBITS_BDA(var, val) do {                                      \
+        typeof(((struct bios_data_area_s *)0)->var) __val = GET_BDA(var); \
+        SET_BDA(var, (__val | (val)));                                  \
+    } while (0)
+
+
+/****************************************************************
+ * Extended Bios Data Area (EBDA)
+ ****************************************************************/
+
+// 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;
+};
+
+// ElTorito Device Emulation data
+struct cdemu_s {
+    struct drive_s *emulated_drive_gf;
+    u32 ilba;
+    u16 buffer_segment;
+    u16 load_segment;
+    u16 sector_count;
+    u8  active;
+    u8  media;
+    u8  emulated_extdrive;
+
+    // Virtual device
+    struct chs_s lchs;
+};
+
+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;
+
+struct usbkeyinfo {
+    union {
+        struct {
+            u8 modifiers;
+            u8 repeatcount;
+            u8 keys[6];
+        };
+        u64 data;
+    };
+};
+
+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.
+    u8 ps2ctr;
+    struct usbkeyinfo usbkey_last;
+
+    int RTCusers;
+
+    // El Torito Emulation data
+    struct cdemu_s cdemu;
+
+    // Buffer for disk DPTE table
+    struct dpte_s dpte;
+
+    // Locks for removable devices
+    u8 cdrom_locks[CONFIG_MAX_EXTDRIVE];
+
+    u16 boot_sequence;
+
+    // Stack space available for code that needs it.
+    u8 extra_stack[512] __aligned(8);
+} PACKED;
+
+// 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_EBDA2(eseg, var)                                            \
+    GET_FARVAR(eseg, ((struct extended_bios_data_area_s *)0)->var)
+#define SET_EBDA2(eseg, var, val)                                       \
+    SET_FARVAR(eseg, ((struct extended_bios_data_area_s *)0)->var, (val))
+#define GET_EBDA(var)                           \
+    GET_EBDA2(get_ebda_seg(), var)
+#define SET_EBDA(var, val)                      \
+    SET_EBDA2(get_ebda_seg(), var, (val))
+
+#define EBDA_OFFSET_TOP_STACK                                   \
+    offsetof(struct extended_bios_data_area_s, extra_stack[     \
+                 FIELD_SIZEOF(struct extended_bios_data_area_s  \
+                              , extra_stack)])
+
+
+/****************************************************************
+ * 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()))
+#define SET_GLOBAL(var, val) do {               \
+        ASSERT32FLAT();                         \
+        (var) = (val);                          \
+    } while (0)
+#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)))
+
+
+/****************************************************************
+ * Bios Config Table
+ ****************************************************************/
+
+struct bios_config_table_s {
+    u16 size;
+    u8 model;
+    u8 submodel;
+    u8 biosrev;
+    u8 feature1, feature2, feature3, feature4, feature5;
+} PACKED;
+
+extern struct bios_config_table_s BIOS_CONFIG_TABLE __aligned(1);
+
+#endif // __BIOSVAR_H
diff --git a/bios/seabios/src/block.c b/bios/seabios/src/block.c
new file mode 100644 (file)
index 0000000..f7e7851
--- /dev/null
@@ -0,0 +1,338 @@
+// 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 "disk.h" // struct ata_s
+#include "biosvar.h" // GET_GLOBAL
+#include "cmos.h" // inb_cmos
+#include "util.h" // dprintf
+#include "ata.h" // process_ata_op
+#include "ahci.h" // process_ahci_op
+#include "usb-msc.h" // process_usb_op
+#include "virtio-blk.h" // process_virtio_op
+
+u8 FloppyCount VAR16VISIBLE;
+u8 CDCount;
+struct drive_s *IDMap[3][CONFIG_MAX_EXTDRIVE] VAR16VISIBLE;
+u8 *bounce_buf_fl VAR16VISIBLE;
+
+struct drive_s *
+getDrive(u8 exttype, u8 extdriveoffset)
+{
+    if (extdriveoffset >= ARRAY_SIZE(IDMap[0]))
+        return NULL;
+    struct drive_s *drive_gf = GET_GLOBAL(IDMap[exttype][extdriveoffset]);
+    if (!drive_gf)
+        return NULL;
+    return GLOBALFLAT2GLOBAL(drive_gf);
+}
+
+int getDriveId(u8 exttype, struct drive_s *drive_g)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(IDMap[0]); i++)
+        if (getDrive(exttype, i) == drive_g)
+            return i;
+    return -1;
+}
+
+int bounce_buf_init(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_g)
+{
+    u8 type = GET_GLOBAL(drive_g->type);
+    if (! CONFIG_COREBOOT && type == DTYPE_ATA) {
+        // Emulators pass in the translation info via nvram.
+        u8 ataid = GET_GLOBAL(drive_g->cntl_id);
+        u8 channel = ataid / 2;
+        u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2);
+        translation >>= 2 * (ataid % 4);
+        translation &= 0x03;
+        return translation;
+    }
+
+    // Otherwise use a heuristic to determine translation type.
+    u16 heads = GET_GLOBAL(drive_g->pchs.heads);
+    u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders);
+    u16 spt = GET_GLOBAL(drive_g->pchs.spt);
+    u64 sectors = GET_GLOBAL(drive_g->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_g)
+{
+    u8 translation = get_translation(drive_g);
+    SET_GLOBAL(drive_g->translation, translation);
+
+    u16 heads = GET_GLOBAL(drive_g->pchs.heads);
+    u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders);
+    u16 spt = GET_GLOBAL(drive_g->pchs.spt);
+    u64 sectors = GET_GLOBAL(drive_g->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_g
+            , drive_g->pchs.cylinders, drive_g->pchs.heads, drive_g->pchs.spt
+            , desc
+            , cylinders, heads, spt
+            , (u32)sectors);
+
+    SET_GLOBAL(drive_g->lchs.heads, heads);
+    SET_GLOBAL(drive_g->lchs.cylinders, cylinders);
+    SET_GLOBAL(drive_g->lchs.spt, spt);
+}
+
+
+/****************************************************************
+ * Drive mapping
+ ****************************************************************/
+
+// Fill in Fixed Disk Parameter Table (located in ebda).
+static void
+fill_fdpt(struct drive_s *drive_g, int hdid)
+{
+    if (hdid > 1)
+        return;
+
+    u16 nlc   = GET_GLOBAL(drive_g->lchs.cylinders);
+    u16 nlh   = GET_GLOBAL(drive_g->lchs.heads);
+    u16 nlspt = GET_GLOBAL(drive_g->lchs.spt);
+
+    u16 npc   = GET_GLOBAL(drive_g->pchs.cylinders);
+    u16 nph   = GET_GLOBAL(drive_g->pchs.heads);
+    u16 npspt = GET_GLOBAL(drive_g->pchs.spt);
+
+    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 = nlspt;
+
+    if (nlc != npc || nlh != nph || nlspt != npspt) {
+        // 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 = npspt;
+        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_g)
+{
+    if (*count >= ARRAY_SIZE(IDMap[0])) {
+        warn_noalloc();
+        return;
+    }
+    idmap[*count] = drive_g;
+    *count = *count + 1;
+}
+
+// Map a hard drive
+void
+map_hd_drive(struct drive_s *drive_g)
+{
+    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_g, hdid);
+    add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive_g);
+
+    // Setup disk geometry translation.
+    setup_translation(drive_g);
+
+    // Fill "fdpt" structure.
+    fill_fdpt(drive_g, hdid);
+}
+
+// Map a cd
+void
+map_cd_drive(struct drive_s *drive_g)
+{
+    dprintf(3, "Mapping cd drive %p\n", drive_g);
+    add_drive(IDMap[EXTTYPE_CD], &CDCount, drive_g);
+}
+
+// Map a floppy
+void
+map_floppy_drive(struct drive_s *drive_g)
+{
+    dprintf(3, "Mapping floppy drive %p\n", drive_g);
+    add_drive(IDMap[EXTTYPE_FLOPPY], &FloppyCount, drive_g);
+
+    // Update equipment word bits for floppy
+    if (FloppyCount == 1) {
+        // 1 drive, ready for boot
+        SETBITS_BDA(equipment_list_flags, 0x01);
+        SET_BDA(floppy_harddisk_info, 0x07);
+    } else if (FloppyCount >= 2) {
+        // 2 drives, ready for boot
+        SETBITS_BDA(equipment_list_flags, 0x41);
+        SET_BDA(floppy_harddisk_info, 0x77);
+    }
+}
+
+
+/****************************************************************
+ * 16bit calling interface
+ ****************************************************************/
+
+// Execute a disk_op request.
+int
+process_op(struct disk_op_s *op)
+{
+    ASSERT16();
+    u8 type = GET_GLOBAL(op->drive_g->type);
+    switch (type) {
+    case DTYPE_FLOPPY:
+        return process_floppy_op(op);
+    case DTYPE_ATA:
+        return process_ata_op(op);
+    case DTYPE_ATAPI:
+        return process_atapi_op(op);
+    case DTYPE_RAMDISK:
+        return process_ramdisk_op(op);
+    case DTYPE_CDEMU:
+        return process_cdemu_op(op);
+    case DTYPE_USB:
+        return process_usb_op(op);
+    case DTYPE_VIRTIO:
+       return process_virtio_op(op);
+    case DTYPE_AHCI:
+       return process_ahci_op(op);
+    default:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
+
+// Execute a "disk_op_s" request - this runs on a stack in the ebda.
+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_g, (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 a stack in the ebda.
+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/bios/seabios/src/blockcmd.c b/bios/seabios/src/blockcmd.c
new file mode 100644 (file)
index 0000000..c9c6845
--- /dev/null
@@ -0,0 +1,81 @@
+// 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 "biosvar.h" // GET_GLOBAL
+#include "util.h" // htonl
+#include "disk.h" // struct disk_op_s
+#include "blockcmd.h" // struct cdb_request_sense
+#include "ata.h" // atapi_cmd_data
+#include "ahci.h" // atapi_cmd_data
+#include "usb-msc.h" // usb_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_GLOBAL(op->drive_g->type);
+    switch (type) {
+    case DTYPE_ATAPI:
+        return atapi_cmd_data(op, cdbcmd, blocksize);
+    case DTYPE_USB:
+        return usb_cmd_data(op, cdbcmd, blocksize);
+    case DTYPE_AHCI:
+        return ahci_cmd_data(op, cdbcmd, blocksize);
+    default:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
+
+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
+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));
+}
+
+// Request capacity
+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));
+}
+
+// Read sectors.
+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 = htonl(op->lba);
+    cmd.count = htons(op->count);
+    return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize));
+}
diff --git a/bios/seabios/src/blockcmd.h b/bios/seabios/src/blockcmd.h
new file mode 100644 (file)
index 0000000..903c435
--- /dev/null
@@ -0,0 +1,77 @@
+// 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_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;
+
+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;
+
+// blockcmd.c
+int cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data);
+int cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data);
+int cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data);
+int cdb_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data);
+int cdb_read(struct disk_op_s *op);
+
+#endif // blockcmd.h
diff --git a/bios/seabios/src/bmp.c b/bios/seabios/src/bmp.c
new file mode 100644 (file)
index 0000000..0d54efd
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+* 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 "util.h"
+#include "bmp.h"
+
+#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);
+    }
+}
+
+struct bmp_decdata *bmp_alloc(void)
+{
+    struct bmp_decdata *bmp = malloc_tmphigh(sizeof(*bmp));
+    return bmp;
+}
+
+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;
+}
+
+void bmp_get_size(struct bmp_decdata *bmp, int *width, int *height)
+{
+    *width = bmp->width;
+    *height = bmp->height;
+}
+
+
+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/bios/seabios/src/bmp.h b/bios/seabios/src/bmp.h
new file mode 100644 (file)
index 0000000..7ae8e87
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef BMP_H
+#define BMP_H
+#include "types.h"
+
+struct bmp_decdata {
+    struct tagRGBQUAD *quadp;
+    unsigned char *datap;
+    int width;
+    int height;
+    int bpp;
+};
+
+/* allocate decdata struct */
+struct bmp_decdata *bmp_alloc(void);
+
+/* extract information from bmp file data */
+int bmp_decode(struct bmp_decdata *bmp, unsigned char *data, int data_size);
+
+/* get bmp properties */
+void bmp_get_size(struct bmp_decdata *bmp, int *width, int *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);
+#endif
diff --git a/bios/seabios/src/boot.c b/bios/seabios/src/boot.c
new file mode 100644 (file)
index 0000000..119f290
--- /dev/null
@@ -0,0 +1,662 @@
+// Code to load disk image and start system boot.
+//
+// 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 "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "config.h" // CONFIG_*
+#include "disk.h" // cdrom_boot
+#include "bregs.h" // struct bregs
+#include "boot.h" // func defs
+#include "cmos.h" // inb_cmos
+#include "paravirt.h" // romfile_loadfile
+#include "pci.h" //pci_bdf_to_*
+
+
+/****************************************************************
+ * Boot priority ordering
+ ****************************************************************/
+
+static char **Bootorder;
+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(3, "boot order:\n");
+    i = 0;
+    do {
+        Bootorder[i] = f;
+        f = strchr(f, '\n');
+        if (f)
+            *(f++) = '\0';
+        nullTrailingSpace(Bootorder[i]);
+        dprintf(3, "%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_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_ata_device(struct pci_device *pci, int chanid, int 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_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%d", 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%d", instance);
+    return find_prio(desc);
+}
+
+int bootprio_find_usb(struct pci_device *pci, u64 path)
+{
+    if (!CONFIG_BOOTORDER)
+        return -1;
+    // Find usb - for example: /pci@i0cf8/usb@1,2/hub@1/network@0/ethernet@0
+    int i;
+    char desc[256], *p;
+    p = build_pci_path(desc, sizeof(desc), "usb", pci);
+    for (i=56; i>0; i-=8) {
+        int port = (path >> i) & 0xff;
+        if (port != 0xff)
+            p += snprintf(p, desc+sizeof(desc)-p, "/hub@%x", port);
+    }
+    snprintf(p, desc+sizeof(desc)-p, "/*@%x", (u32)(path & 0xff));
+    return find_prio(desc);
+}
+
+
+/****************************************************************
+ * Boot setup
+ ****************************************************************/
+
+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_setup(void)
+{
+    if (! CONFIG_BOOT)
+        return;
+
+    SET_EBDA(boot_sequence, 0xffff);
+
+    if (!CONFIG_COREBOOT) {
+        // On emulators, get boot order from nvram.
+        if (inb_cmos(CMOS_BIOS_BOOTFLAG1) & 1)
+            CheckFloppySig = 0;
+        u32 bootorder = (inb_cmos(CMOS_BIOS_BOOTFLAG2)
+                         | ((inb_cmos(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;
+            }
+        }
+    }
+
+    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 bootentry_s *next;
+};
+static struct bootentry_s *BootList;
+
+#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
+
+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 bootentry_s **pprev;
+    for (pprev = &BootList; *pprev; pprev = &(*pprev)->next) {
+        struct bootentry_s *pos = *pprev;
+        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;
+    }
+    be->next = *pprev;
+    *pprev = be;
+}
+
+// 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, DEFAULT_PRIO)
+                  , 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);
+}
+
+
+/****************************************************************
+ * Boot menu and BCV execution
+ ****************************************************************/
+
+#define DEFAULT_BOOTMENU_WAIT 2500
+
+// Show IPL option menu.
+static void
+interactive_bootmenu(void)
+{
+    if (! CONFIG_BOOTMENU || ! qemu_cfg_show_boot_menu())
+        return;
+
+    while (get_keystroke(0) >= 0)
+        ;
+
+    printf("Press F12 for boot menu.\n\n");
+
+    u32 menutime = romfile_loadint("etc/boot-menu-wait", DEFAULT_BOOTMENU_WAIT);
+    enable_bootsplash();
+    int scan_code = get_keystroke(menutime);
+    disable_bootsplash();
+    if (scan_code != 0x86)
+        /* not F12 */
+        return;
+
+    while (get_keystroke(0) >= 0)
+        ;
+
+    printf("Select boot device:\n\n");
+    wait_threads();
+
+    // Show menu items
+    struct bootentry_s *pos = BootList;
+    int maxmenu = 0;
+    while (pos) {
+        char desc[60];
+        maxmenu++;
+        printf("%d. %s\n", maxmenu
+               , strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
+        pos = pos->next;
+    }
+
+    // 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;
+    struct bootentry_s **pprev = &BootList;
+    while (--choice)
+        pprev = &(*pprev)->next;
+    pos = *pprev;
+    *pprev = pos->next;
+    pos->next = BootList;
+    BootList = pos;
+    pos->priority = 0;
+}
+
+// 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
+boot_prep(void)
+{
+    if (! CONFIG_BOOT) {
+        wait_threads();
+        return;
+    }
+
+    // XXX - show available drives?
+
+    // Allow user to modify BCV/IPL order.
+    interactive_bootmenu();
+    wait_threads();
+
+    // Map drives and populate BEV list
+    struct bootentry_s *pos = BootList;
+    while (pos) {
+        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;
+        }
+        pos = pos->next;
+    }
+
+    // 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;
+    call16(&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;
+    }
+
+    u16 ebda_seg = get_ebda_seg();
+    u8 bootdrv = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
+    u16 bootseg = GET_EBDA2(ebda_seg, 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 || !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);
+}
+
+// Determine next boot method and attempt a boot using it.
+static void
+do_boot(u16 seq_nr)
+{
+    if (! CONFIG_BOOT)
+        panic("Boot support not compiled in.\n");
+
+    if (seq_nr >= BEVCount) {
+        printf("No bootable device.\n");
+        // Loop with irqs enabled - this allows ctrl+alt+delete to work.
+        for (;;)
+            wait_irq();
+    }
+
+    // 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;
+    }
+
+    // Boot failed: invoke the boot recovery function
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.flags = F_IF;
+    call16_int(0x18, &br);
+}
+
+// Boot Failure recovery: try the next device.
+void VISIBLE32FLAT
+handle_18(void)
+{
+    debug_serial_setup();
+    debug_enter(NULL, DEBUG_HDL_18);
+    u16 ebda_seg = get_ebda_seg();
+    u16 seq = GET_EBDA2(ebda_seg, boot_sequence) + 1;
+    SET_EBDA2(ebda_seg, boot_sequence, seq);
+    do_boot(seq);
+}
+
+// INT 19h Boot Load Service Entry Point
+void VISIBLE32FLAT
+handle_19(void)
+{
+    debug_serial_setup();
+    debug_enter(NULL, DEBUG_HDL_19);
+    SET_EBDA(boot_sequence, 0);
+    do_boot(0);
+}
diff --git a/bios/seabios/src/boot.h b/bios/seabios/src/boot.h
new file mode 100644 (file)
index 0000000..d776aa1
--- /dev/null
@@ -0,0 +1,23 @@
+// Storage for boot definitions.
+#ifndef __BOOT_H
+#define __BOOT_H
+
+// boot.c
+void boot_setup(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 boot_prep(void);
+struct pci_device;
+int bootprio_find_pci_device(struct pci_device *pci);
+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);
+int bootprio_find_usb(struct pci_device *pci, u64 path);
+
+#endif // __BOOT_H
diff --git a/bios/seabios/src/bootsplash.c b/bios/seabios/src/bootsplash.c
new file mode 100644 (file)
index 0000000..9c33b80
--- /dev/null
@@ -0,0 +1,309 @@
+// Option rom scanning code.
+//
+// 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 "farptr.h" // FLATPTR_TO_SEG
+#include "config.h" // CONFIG_*
+#include "util.h" // dprintf
+#include "jpeg.h" // splash
+#include "biosvar.h" // SET_EBDA
+#include "paravirt.h" // romfile_find
+#include "bmp.h"
+
+/****************************************************************
+ * VESA structures
+ ****************************************************************/
+
+struct vesa_info {
+    u32 vesa_signature;
+    u16 vesa_version;
+    struct segoff_s oem_string_ptr;
+    u8 capabilities[4];
+    struct segoff_s video_mode_ptr;
+    u16 total_memory;
+    u16 oem_software_rev;
+    struct segoff_s oem_vendor_name_ptr;
+    struct segoff_s oem_product_name_ptr;
+    struct segoff_s oem_product_rev_ptr;
+    u8 reserved[222];
+    u8 oem_data[256];
+} PACKED;
+
+#define VESA_SIGNATURE 0x41534556 // VESA
+#define VBE2_SIGNATURE 0x32454256 // VBE2
+
+struct vesa_mode_info {
+    u16 mode_attributes;
+    u8 win_a_attributes;
+    u8 win_b_attributes;
+    u16 win_granularity;
+    u16 win_size;
+    u16 win_a_segment;
+    u16 win_b_segment;
+    u32 win_func_ptr;
+    u16 bytes_per_scanline;
+    u16 x_resolution;
+    u16 y_resolution;
+    u8 x_charsize;
+    u8 y_charsize;
+    u8 number_of_planes;
+    u8 bits_per_pixel;
+    u8 number_of_banks;
+    u8 memory_model;
+    u8 bank_size;
+    u8 number_of_image_pages;
+    u8 reserved_page;
+    u8 red_mask_size;
+    u8 red_mask_pos;
+    u8 green_mask_size;
+    u8 green_mask_pos;
+    u8 blue_mask_size;
+    u8 blue_mask_pos;
+    u8 reserved_mask_size;
+    u8 reserved_mask_pos;
+    u8 direct_color_mode_info;
+    void *phys_base_ptr;
+    u32 offscreen_mem_offset;
+    u16 offscreen_mem_size;
+    u8 reserved[206];
+} PACKED;
+
+
+/****************************************************************
+ * 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\n", VERSION);
+}
+
+static int
+find_videomode(struct vesa_info *vesa_info, struct vesa_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_ptr);
+    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 = (1 << 14) | 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->x_resolution != width
+            || mode_info->y_resolution != 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 vesa_info *vesa_info = malloc_tmplow(sizeof(*vesa_info));
+    struct vesa_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 vesa_info));
+    vesa_info->vesa_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->vesa_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_name_ptr);
+    char *product = SEGOFF_TO_FLATPTR(vesa_info->oem_product_name_ptr);
+    dprintf(3, "VESA %d.%d\nVENDOR: %s\nPRODUCT: %s\n",
+            vesa_info->vesa_version>>8, vesa_info->vesa_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 = mode_info->phys_base_ptr;
+    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 = (1 << 14) | videomode;
+    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/bios/seabios/src/bregs.h b/bios/seabios/src/bregs.h
new file mode 100644 (file)
index 0000000..f026fa8
--- /dev/null
@@ -0,0 +1,96 @@
+// Structure layout of cpu registers the 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
+
+// CPU flag bitdefs
+#define F_CF (1<<0)
+#define F_ZF (1<<6)
+#define F_IF (1<<9)
+
+// 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
+
+
+#ifndef __ASSEMBLY__
+
+#include "farptr.h" // struct segoff_s
+
+/****************************************************************
+ * Registers saved/restored in romlayout.S
+ ****************************************************************/
+
+#include "types.h" // u16
+
+#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 // !__ASSEMBLY__
+
+#endif // bregs.h
diff --git a/bios/seabios/src/cdrom.c b/bios/seabios/src/cdrom.c
new file mode 100644 (file)
index 0000000..6351fec
--- /dev/null
@@ -0,0 +1,377 @@
+// 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 "disk.h" // cdrom_13
+#include "util.h" // memset
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_EBDA
+#include "ata.h" // ATA_CMD_REQUEST_SENSE
+#include "blockcmd.h" // CDB_CMD_REQUEST_SENSE
+
+
+/****************************************************************
+ * CD emulation
+ ****************************************************************/
+
+struct drive_s *cdemu_drive_gf VAR16VISIBLE;
+
+static int
+cdemu_read(struct disk_op_s *op)
+{
+    u16 ebda_seg = get_ebda_seg();
+    struct drive_s *drive_g;
+    drive_g = GLOBALFLAT2GLOBAL(GET_EBDA2(ebda_seg, cdemu.emulated_drive_gf));
+    struct disk_op_s dop;
+    dop.drive_g = drive_g;
+    dop.command = op->command;
+    dop.lba = GET_EBDA2(ebda_seg, 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:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
+
+void
+cdemu_setup(void)
+{
+    if (!CONFIG_CDROM_EMU)
+        return;
+    if (!CDCount)
+        return;
+    if (bounce_buf_init() < 0)
+        return;
+
+    struct drive_s *drive_g = malloc_fseg(sizeof(*drive_g));
+    if (!drive_g) {
+        warn_noalloc();
+        free(drive_g);
+        return;
+    }
+    cdemu_drive_gf = drive_g;
+    memset(drive_g, 0, sizeof(*drive_g));
+    drive_g->type = DTYPE_CDEMU;
+    drive_g->blksize = DISK_SECTOR_SIZE;
+    drive_g->sectors = (u64)-1;
+}
+
+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;
+    u8 cylinders;
+    u8 sectors;
+    u8 heads;
+};
+
+#define SET_INT13ET(regs,var,val)                                      \
+    SET_FARVAR((regs)->ds, ((struct eltorito_s*)((regs)->si+0))->var, (val))
+
+// ElTorito - Terminate disk emu
+void
+cdemu_134b(struct bregs *regs)
+{
+    // FIXME ElTorito Hardcoded
+    u16 ebda_seg = get_ebda_seg();
+    SET_INT13ET(regs, size, 0x13);
+    SET_INT13ET(regs, media, GET_EBDA2(ebda_seg, cdemu.media));
+    SET_INT13ET(regs, emulated_drive
+                , GET_EBDA2(ebda_seg, cdemu.emulated_extdrive));
+    struct drive_s *drive_gf = GET_EBDA2(ebda_seg, cdemu.emulated_drive_gf);
+    u8 cntl_id = 0;
+    if (drive_gf)
+        cntl_id = GET_GLOBALFLAT(drive_gf->cntl_id);
+    SET_INT13ET(regs, controller_index, cntl_id / 2);
+    SET_INT13ET(regs, device_spec, cntl_id % 2);
+    SET_INT13ET(regs, ilba, GET_EBDA2(ebda_seg, cdemu.ilba));
+    SET_INT13ET(regs, buffer_segment, GET_EBDA2(ebda_seg, cdemu.buffer_segment));
+    SET_INT13ET(regs, load_segment, GET_EBDA2(ebda_seg, cdemu.load_segment));
+    SET_INT13ET(regs, sector_count, GET_EBDA2(ebda_seg, cdemu.sector_count));
+    SET_INT13ET(regs, cylinders, GET_EBDA2(ebda_seg, cdemu.lchs.cylinders));
+    SET_INT13ET(regs, sectors, GET_EBDA2(ebda_seg, cdemu.lchs.spt));
+    SET_INT13ET(regs, heads, GET_EBDA2(ebda_seg, cdemu.lchs.heads));
+
+    // If we have to terminate emulation
+    if (regs->al == 0x00) {
+        // FIXME ElTorito Various. Should be handled accordingly to spec
+        SET_EBDA2(ebda_seg, cdemu.active, 0x00); // bye bye
+
+        // XXX - update floppy/hd count.
+    }
+
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+
+/****************************************************************
+ * CD booting
+ ****************************************************************/
+
+static int
+atapi_is_ready(struct disk_op_s *op)
+{
+    dprintf(6, "atapi_is_ready (drive=%p)\n", op->drive_g);
+
+    /* Retry READ CAPACITY for 5 seconds unless MEDIUM NOT PRESENT is
+     * reported by the device.  If the device reports "IN PROGRESS",
+     * 30 seconds is added. */
+    struct cdbres_read_capacity info;
+    int in_progress = 0;
+    u64 end = calc_future_tsc(5000);
+    for (;;) {
+        if (check_tsc(end)) {
+            dprintf(1, "read capacity failed\n");
+            return -1;
+        }
+
+        int ret = cdb_read_capacity(op, &info);
+        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 = calc_future_tsc(30000);
+            in_progress = 1;
+        }
+    }
+
+    u32 blksize = ntohl(info.blksize), sectors = ntohl(info.sectors);
+    if (blksize != GET_GLOBAL(op->drive_g->blksize)) {
+        printf("Unsupported sector size %u\n", blksize);
+        return -1;
+    }
+
+    dprintf(6, "sectors=%u\n", sectors);
+    printf("%dMB medium detected\n", sectors>>(20-11));
+    return 0;
+}
+
+int
+cdrom_boot(struct drive_s *drive_g)
+{
+    struct disk_op_s dop;
+    int cdid = getDriveId(EXTTYPE_CD, drive_g);
+    memset(&dop, 0, sizeof(dop));
+    dop.drive_g = drive_g;
+    if (!dop.drive_g || cdid < 0)
+        return 1;
+
+    int ret = atapi_is_ready(&dop);
+    if (ret)
+        dprintf(1, "atapi_is_ready returned %d\n", ret);
+
+    // Read the Boot Record Volume Descriptor
+    u8 buffer[2048];
+    dop.lba = 0x11;
+    dop.count = 1;
+    dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer);
+    ret = cdb_read(&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 = cdb_read(&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
+
+    u16 ebda_seg = get_ebda_seg();
+    u8 media = buffer[0x21];
+    SET_EBDA2(ebda_seg, cdemu.media, media);
+
+    SET_EBDA2(ebda_seg, cdemu.emulated_drive_gf, dop.drive_g);
+
+    u16 boot_segment = *(u16*)&buffer[0x22];
+    if (!boot_segment)
+        boot_segment = 0x07C0;
+    SET_EBDA2(ebda_seg, cdemu.load_segment, boot_segment);
+    SET_EBDA2(ebda_seg, cdemu.buffer_segment, 0x0000);
+
+    u16 nbsectors = *(u16*)&buffer[0x26];
+    SET_EBDA2(ebda_seg, cdemu.sector_count, nbsectors);
+
+    lba = *(u32*)&buffer[0x28];
+    SET_EBDA2(ebda_seg, cdemu.ilba, lba);
+
+    // And we read the image in memory
+    dop.lba = lba;
+    dop.count = DIV_ROUND_UP(nbsectors, 4);
+    dop.buf_fl = MAKE_FLATPTR(boot_segment, 0);
+    ret = cdb_read(&dop);
+    if (ret)
+        return 12;
+
+    if (media == 0) {
+        // No emulation requested - return success.
+        SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 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
+        SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x00);
+        // XXX - get and set actual floppy count.
+        SETBITS_BDA(equipment_list_flags, 0x41);
+
+        switch (media) {
+        case 0x01:  // 1.2M floppy
+            SET_EBDA2(ebda_seg, cdemu.lchs.spt, 15);
+            SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+            SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
+            break;
+        case 0x02:  // 1.44M floppy
+            SET_EBDA2(ebda_seg, cdemu.lchs.spt, 18);
+            SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+            SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
+            break;
+        case 0x03:  // 2.88M floppy
+            SET_EBDA2(ebda_seg, cdemu.lchs.spt, 36);
+            SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+            SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
+            break;
+        }
+    } else {
+        // Harddrive emulation
+        SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x80);
+        SET_BDA(hdcount, GET_BDA(hdcount) + 1);
+
+        // Peak at partition table to get chs.
+        struct mbr_s *mbr = (void*)0;
+        u8 sptcyl = GET_FARVAR(boot_segment, mbr->partitions[0].last.sptcyl);
+        u8 cyllow = GET_FARVAR(boot_segment, mbr->partitions[0].last.cyllow);
+        u8 heads = GET_FARVAR(boot_segment, mbr->partitions[0].last.heads);
+
+        SET_EBDA2(ebda_seg, cdemu.lchs.spt, sptcyl & 0x3f);
+        SET_EBDA2(ebda_seg, cdemu.lchs.cylinders
+                  , ((sptcyl<<2)&0x300) + cyllow + 1);
+        SET_EBDA2(ebda_seg, cdemu.lchs.heads, heads + 1);
+    }
+
+    // everything is ok, so from now on, the emulation is active
+    SET_EBDA2(ebda_seg, cdemu.active, 0x01);
+    dprintf(6, "cdemu media=%d\n", media);
+
+    return 0;
+}
diff --git a/bios/seabios/src/clock.c b/bios/seabios/src/clock.c
new file mode 100644 (file)
index 0000000..fcdc698
--- /dev/null
@@ -0,0 +1,650 @@
+// 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 "util.h" // debug_enter
+#include "disk.h" // floppy_tick
+#include "cmos.h" // inb_cmos
+#include "pic.h" // eoi_pic1
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_GLOBAL
+#include "usb-hid.h" // usb_check_event
+
+// 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
+
+
+// Bits for PORT_PS2_CTRLB
+#define PPCB_T2GATE (1<<0)
+#define PPCB_SPKR   (1<<1)
+#define PPCB_T2OUT  (1<<5)
+
+// 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)
+
+
+/****************************************************************
+ * TSC timer
+ ****************************************************************/
+
+#define CALIBRATE_COUNT 0x800   // Approx 1.7ms
+
+u32 cpu_khz VAR16VISIBLE;
+
+static void
+calibrate_tsc(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);
+    u32 hz = diff * PIT_TICK_RATE / CALIBRATE_COUNT;
+    SET_GLOBAL(cpu_khz, hz / 1000);
+
+    dprintf(1, "CPU Mhz=%u\n", hz / 1000000);
+}
+
+static void
+tscdelay(u64 diff)
+{
+    u64 start = rdtscll();
+    u64 end = start + diff;
+    while (!check_tsc(end))
+        cpu_relax();
+}
+
+static void
+tscsleep(u64 diff)
+{
+    u64 start = rdtscll();
+    u64 end = start + diff;
+    while (!check_tsc(end))
+        yield();
+}
+
+void ndelay(u32 count) {
+    tscdelay(count * GET_GLOBAL(cpu_khz) / 1000000);
+}
+void udelay(u32 count) {
+    tscdelay(count * GET_GLOBAL(cpu_khz) / 1000);
+}
+void mdelay(u32 count) {
+    tscdelay(count * GET_GLOBAL(cpu_khz));
+}
+
+void nsleep(u32 count) {
+    tscsleep(count * GET_GLOBAL(cpu_khz) / 1000000);
+}
+void usleep(u32 count) {
+    tscsleep(count * GET_GLOBAL(cpu_khz) / 1000);
+}
+void msleep(u32 count) {
+    tscsleep(count * GET_GLOBAL(cpu_khz));
+}
+
+// Return the TSC value that is 'msecs' time in the future.
+u64
+calc_future_tsc(u32 msecs)
+{
+    u32 khz = GET_GLOBAL(cpu_khz);
+    return rdtscll() + ((u64)khz * msecs);
+}
+u64
+calc_future_tsc_usec(u32 usecs)
+{
+    u32 khz = GET_GLOBAL(cpu_khz);
+    return rdtscll() + ((u64)(khz/1000) * usecs);
+}
+
+
+/****************************************************************
+ * Init
+ ****************************************************************/
+
+static 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 ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0)
+        return 0;
+    u64 end = calc_future_tsc(15);
+    for (;;) {
+        if ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0)
+            return 0;
+        if (check_tsc(end))
+            // update-in-progress never transitioned to 0
+            return -1;
+        yield();
+    }
+}
+
+static 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);
+}
+
+static void
+init_rtc(void)
+{
+    outb_cmos(0x26, CMOS_STATUS_A);    // 32,768Khz src, 976.5625us updates
+    u8 regB = inb_cmos(CMOS_STATUS_B);
+    outb_cmos((regB & RTC_B_DSE) | RTC_B_24HR, CMOS_STATUS_B);
+    inb_cmos(CMOS_STATUS_C);
+    inb_cmos(CMOS_STATUS_D);
+}
+
+static u32
+bcd2bin(u8 val)
+{
+    return (val & 0xf) + ((val >> 4) * 10);
+}
+
+void
+timer_setup(void)
+{
+    dprintf(3, "init timer\n");
+    calibrate_tsc();
+    pit_setup();
+
+    init_rtc();
+    rtc_updating();
+    u32 seconds = bcd2bin(inb_cmos(CMOS_RTC_SECONDS));
+    u32 minutes = bcd2bin(inb_cmos(CMOS_RTC_MINUTES));
+    u32 hours = bcd2bin(inb_cmos(CMOS_RTC_HOURS));
+    u32 ticks = (hours * 60 + minutes) * 60 + seconds;
+    ticks = ((u64)ticks * PIT_TICK_RATE) / PIT_TICK_INTERVAL;
+    SET_BDA(timer_counter, ticks);
+
+    enable_hwirq(0, FUNC16(entry_08));
+    enable_hwirq(8, FUNC16(entry_70));
+}
+
+
+/****************************************************************
+ * Standard clock functions
+ ****************************************************************/
+
+#define TICKS_PER_DAY (u32)((u64)60*60*24*PIT_TICK_RATE / PIT_TICK_INTERVAL)
+
+// Calculate the timer value at 'count' number of full timer ticks in
+// the future.
+u32
+calc_future_timer_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
+calc_future_timer(u32 msecs)
+{
+    if (!msecs)
+        return GET_BDA(timer_counter);
+    u32 kticks = DIV_ROUND_UP((u64)msecs * PIT_TICK_RATE, PIT_TICK_INTERVAL);
+    u32 ticks = DIV_ROUND_UP(kticks, 1000);
+    return calc_future_timer_ticks(ticks);
+}
+
+// Check if the given timer value has passed.
+int
+check_timer(u32 end)
+{
+    return (((GET_BDA(timer_counter) + TICKS_PER_DAY - end) % TICKS_PER_DAY)
+            < (TICKS_PER_DAY/2));
+}
+
+// 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 = inb_cmos(CMOS_RTC_SECONDS);
+    regs->cl = inb_cmos(CMOS_RTC_MINUTES);
+    regs->ch = inb_cmos(CMOS_RTC_HOURS);
+    regs->dl = inb_cmos(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()) {
+        init_rtc();
+        // fall through as if an update were not in progress
+    }
+    outb_cmos(regs->dh, CMOS_RTC_SECONDS);
+    outb_cmos(regs->cl, CMOS_RTC_MINUTES);
+    outb_cmos(regs->ch, CMOS_RTC_HOURS);
+    // Set Daylight Savings time enabled bit to requested value
+    u8 val8 = ((inb_cmos(CMOS_STATUS_B) & (RTC_B_PIE|RTC_B_AIE))
+               | RTC_B_24HR | (regs->dl & RTC_B_DSE));
+    outb_cmos(val8, CMOS_STATUS_B);
+    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 = inb_cmos(CMOS_RTC_YEAR);
+    regs->dh = inb_cmos(CMOS_RTC_MONTH);
+    regs->dl = inb_cmos(CMOS_RTC_DAY_MONTH);
+    if (CONFIG_COREBOOT) {
+        if (regs->cl > 0x80)
+            regs->ch = 0x19;
+        else
+            regs->ch = 0x20;
+    } else {
+        regs->ch = inb_cmos(CMOS_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()) {
+        init_rtc();
+        set_invalid(regs);
+        return;
+    }
+    outb_cmos(regs->cl, CMOS_RTC_YEAR);
+    outb_cmos(regs->dh, CMOS_RTC_MONTH);
+    outb_cmos(regs->dl, CMOS_RTC_DAY_MONTH);
+    if (!CONFIG_COREBOOT)
+        outb_cmos(regs->ch, CMOS_CENTURY);
+    // clear halt-clock bit
+    u8 val8 = inb_cmos(CMOS_STATUS_B) & ~RTC_B_SET;
+    outb_cmos(val8, CMOS_STATUS_B);
+    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 = inb_cmos(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()) {
+        init_rtc();
+        // fall through as if an update were not in progress
+    }
+    outb_cmos(regs->dh, CMOS_RTC_SECONDS_ALARM);
+    outb_cmos(regs->cl, CMOS_RTC_MINUTES_ALARM);
+    outb_cmos(regs->ch, CMOS_RTC_HOURS_ALARM);
+    // enable Status Reg B alarm bit, clear halt clock bit
+    outb_cmos((val8 & ~RTC_B_SET) | RTC_B_AIE, CMOS_STATUS_B);
+    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 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B
+    // clear clock-halt bit, disable alarm bit
+    outb_cmos(val8 & ~(RTC_B_SET|RTC_B_AIE), CMOS_STATUS_B);
+    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;
+    case 0xb1: handle_1ab1(regs); break;
+    default:   handle_1aXX(regs); break;
+    }
+}
+
+// INT 08h System Timer ISR Entry Point
+void VISIBLE16
+handle_08(void)
+{
+    debug_isr(DEBUG_ISR_08);
+
+    floppy_tick();
+
+    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);
+
+    usb_check_event();
+
+    // chain to user timer tick INT #0x1c
+    u32 eax=0, flags;
+    call16_simpint(0x1c, &eax, &flags);
+
+    eoi_pic1();
+}
+
+
+/****************************************************************
+ * Periodic timer
+ ****************************************************************/
+
+void
+useRTC(void)
+{
+    u16 ebda_seg = get_ebda_seg();
+    int count = GET_EBDA2(ebda_seg, RTCusers);
+    SET_EBDA2(ebda_seg, RTCusers, count+1);
+    if (count)
+        return;
+    // Turn on the Periodic Interrupt timer
+    u8 bRegister = inb_cmos(CMOS_STATUS_B);
+    outb_cmos(bRegister | RTC_B_PIE, CMOS_STATUS_B);
+}
+
+void
+releaseRTC(void)
+{
+    u16 ebda_seg = get_ebda_seg();
+    int count = GET_EBDA2(ebda_seg, RTCusers);
+    SET_EBDA2(ebda_seg, RTCusers, count-1);
+    if (count != 1)
+        return;
+    // Clear the Periodic Interrupt.
+    u8 bRegister = inb_cmos(CMOS_STATUS_B);
+    outb_cmos(bRegister & ~RTC_B_PIE, CMOS_STATUS_B);
+}
+
+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);
+    useRTC();
+    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);
+    releaseRTC();
+}
+
+#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)
+        wait_irq();
+    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 = inb_cmos(CMOS_STATUS_B);
+    u8 registerC = inb_cmos(CMOS_STATUS_C);
+
+    if (!(registerB & (RTC_B_PIE|RTC_B_AIE)))
+        goto done;
+    if (registerC & RTC_B_AIE) {
+        // Handle Alarm Interrupt.
+        u32 eax=0, flags;
+        call16_simpint(0x4a, &eax, &flags);
+    }
+    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:
+    eoi_pic2();
+}
diff --git a/bios/seabios/src/cmos.h b/bios/seabios/src/cmos.h
new file mode 100644 (file)
index 0000000..e4b6462
--- /dev/null
@@ -0,0 +1,74 @@
+// Definitions for X86 CMOS non-volatile memory access.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __CMOS_H
+#define __CMOS_H
+
+#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
+#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
+
+// CMOS_FLOPPY_DRIVE_TYPE bitdefs
+#define CFD_NO_DRIVE 0
+#define CFD_360KB    1
+#define CFD_12MB     2
+#define CFD_720KB    3
+#define CFD_144MB    4
+#define CFD_288MB    5
+
+#ifndef __ASSEMBLY__
+
+#include "ioport.h" // inb, outb
+
+static inline u8
+inb_cmos(u8 reg)
+{
+    reg |= NMI_DISABLE_BIT;
+    outb(reg, PORT_CMOS_INDEX);
+    return inb(PORT_CMOS_DATA);
+}
+
+static inline void
+outb_cmos(u8 val, u8 reg)
+{
+    reg |= NMI_DISABLE_BIT;
+    outb(reg, PORT_CMOS_INDEX);
+    outb(val, PORT_CMOS_DATA);
+}
+
+#endif // !__ASSEMBLY__
+
+#endif // cmos.h
diff --git a/bios/seabios/src/config.h b/bios/seabios/src/config.h
new file mode 100644 (file)
index 0000000..b0187a4
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include "autoconf.h"
+
+// Configuration definitions.
+
+//#define CONFIG_APPNAME  "QEMU"
+//#define CONFIG_CPUNAME8 "QEMUCPU "
+//#define CONFIG_APPNAME6 "QEMU  "
+//#define CONFIG_APPNAME4 "QEMU"
+#define CONFIG_APPNAME  "Bochs"
+#define CONFIG_CPUNAME8 "BOCHSCPU"
+#define CONFIG_APPNAME6 "BOCHS "
+#define CONFIG_APPNAME4 "BXPC"
+
+// Maximum number of map entries in the e820 map
+#define CONFIG_MAX_E820 32
+// Space to reserve in f-segment for dynamic allocations
+#define CONFIG_MAX_BIOSTABLE 2048
+// Space to reserve in high-memory for tables
+#define CONFIG_MAX_HIGHTABLE (64*1024)
+// Largest supported externaly facing drive id
+#define CONFIG_MAX_EXTDRIVE 16
+// Number of bytes the smbios may be and still live in the f-segment
+#define BUILD_MAX_SMBIOS_FSEG     600
+
+#define CONFIG_MODEL_ID      0xFC
+#define CONFIG_SUBMODEL_ID   0x00
+#define CONFIG_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
+// 32KB for shadow ram copying (works around emulator deficiencies)
+#define BUILD_BIOS_TMP_ADDR       0x30000
+#define BUILD_SMM_INIT_ADDR       0x38000
+#define BUILD_SMM_ADDR            0xa8000
+#define BUILD_SMM_SIZE            0x8000
+#define BUILD_MAX_HIGHMEM         0xe0000000
+
+#define BUILD_PCIMEM_START        0xe0000000
+#define BUILD_PCIMEM_END          0xfec00000    /* IOAPIC is mapped at */
+
+#define BUILD_IOAPIC_ADDR         0xfec00000
+#define BUILD_HPET_ADDRESS        0xfed00000
+#define BUILD_APIC_ADDR           0xfee00000
+
+// 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_pnp 1
+#define DEBUG_HDL_pmm 1
+#define DEBUG_HDL_pcibios32 9
+#define DEBUG_HDL_apm 9
+
+#define DEBUG_unimplemented 2
+#define DEBUG_invalid 3
+#define DEBUG_thread 2
+
+#endif // config.h
diff --git a/bios/seabios/src/coreboot.c b/bios/seabios/src/coreboot.c
new file mode 100644 (file)
index 0000000..ee9dd8b
--- /dev/null
@@ -0,0 +1,542 @@
+// 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 "memmap.h" // add_e820
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "lzmadecode.h" // LzmaDecode
+#include "smbios.h" // smbios_init
+#include "boot.h" // boot_add_cbfs
+
+
+/****************************************************************
+ * 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
+
+static u16
+ipchksum(char *buf, int count)
+{
+    u16 *p = (u16*)buf;
+    u32 sum = 0;
+    while (count > 1) {
+        sum += *p++;
+        count -= 2;
+    }
+    if (count)
+        sum += *(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(char *addr, int len)
+{
+    char *end = addr + len;
+    for (; addr < end; addr += 16) {
+        struct cb_header *cbh = (struct cb_header *)addr;
+        if (cbh->signature != CB_SIGNATURE)
+            continue;
+        if (! cbh->table_bytes)
+            continue;
+        if (ipchksum(addr, sizeof(*cbh)) != 0)
+            continue;
+        if (ipchksum(addr + sizeof(*cbh), cbh->table_bytes)
+            != cbh->table_checksum)
+            continue;
+        return cbh;
+    }
+    return NULL;
+}
+
+// Try to find the coreboot memory table in the given coreboot table.
+static void *
+find_cb_subtable(struct cb_header *cbh, u32 tag)
+{
+    char *tbl = (char *)cbh + sizeof(*cbh);
+    int i;
+    for (i=0; i<cbh->table_entries; i++) {
+        struct cb_memory *cbm = (struct cb_memory *)tbl;
+        tbl += cbm->size;
+        if (cbm->tag == tag)
+            return cbm;
+    }
+    return NULL;
+}
+
+static struct cb_memory *CBMemTable;
+const char *CBvendor, *CBpart;
+
+// Populate max ram and e820 map info by scanning for a coreboot table.
+static void
+coreboot_fill_map(void)
+{
+    dprintf(3, "Attempting to find coreboot table\n");
+
+    // Find coreboot table.
+    struct cb_header *cbh = find_cb_header(0, 0x1000);
+    if (!cbh)
+        goto fail;
+    struct cb_forward *cbf = find_cb_subtable(cbh, CB_TAG_FORWARD);
+    if (cbf) {
+        dprintf(3, "Found coreboot table forwarder.\n");
+        cbh = find_cb_header((char *)((u32)cbf->forward), 0x100);
+        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;
+
+    u64 maxram = 0, maxram_over4G = 0;
+    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;
+        } else if (type == E820_ACPI || type == E820_RAM) {
+            u64 end = m->start + m->size;
+            if (end > 0x100000000ull) {
+                end -= 0x100000000ull;
+                if (end > maxram_over4G)
+                    maxram_over4G = end;
+            } else if (end > maxram)
+                maxram = end;
+        }
+        add_e820(m->start, m->size, type);
+    }
+
+    RamSize = maxram;
+    RamSizeOver4G = maxram_over4G;
+
+    // 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_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");
+    RamSize = 16*1024*1024;
+    RamSizeOver4G = 0;
+    add_e820(0, 16*1024*1024, E820_RAM);
+    return;
+}
+
+
+/****************************************************************
+ * 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_pir(p);
+        copy_mptable(p);
+        copy_acpi_rsdp(p);
+        copy_smbios(p);
+    }
+}
+
+void
+coreboot_copy_biostable(void)
+{
+    struct cb_memory *cbm = CBMemTable;
+    if (! CONFIG_COREBOOT || !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);
+    }
+
+    // XXX - create a dummy smbios table for now.
+    if (!SMBiosAddr)
+        smbios_init();
+}
+
+
+/****************************************************************
+ * 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_HEADPTR_ADDR 0xFFFFFFFc
+#define CBFS_VERSION1 0x31313131
+
+struct cbfs_header {
+    u32 magic;
+    u32 version;
+    u32 romsize;
+    u32 bootblocksize;
+    u32 align;
+    u32 offset;
+    u32 pad[2];
+} PACKED;
+
+static struct cbfs_header *CBHDR;
+
+static void
+cbfs_setup(void)
+{
+    if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
+        return;
+
+    CBHDR = *(void **)CBFS_HEADPTR_ADDR;
+    if (CBHDR->magic != htonl(CBFS_HEADER_MAGIC)) {
+        dprintf(1, "Unable to find CBFS (ptr=%p; got %x not %x)\n"
+                , CBHDR, CBHDR->magic, htonl(CBFS_HEADER_MAGIC));
+        CBHDR = NULL;
+        return;
+    }
+
+    dprintf(1, "Found CBFS header at %p\n", CBHDR);
+}
+
+#define CBFS_FILE_MAGIC 0x455649484352414cLL // LARCHIVE
+
+struct cbfs_file {
+    u64 magic;
+    u32 len;
+    u32 type;
+    u32 checksum;
+    u32 offset;
+    char filename[0];
+} PACKED;
+
+// Verify a cbfs entry looks valid.
+static struct cbfs_file *
+cbfs_verify(struct cbfs_file *file)
+{
+    if (file < (struct cbfs_file *)(0xFFFFFFFF - ntohl(CBHDR->romsize)))
+        return NULL;
+    u64 magic = file->magic;
+    if (magic == CBFS_FILE_MAGIC) {
+        dprintf(5, "Found CBFS file %s\n", file->filename);
+        return file;
+    }
+    return NULL;
+}
+
+// Return the first file in the CBFS archive
+static struct cbfs_file *
+cbfs_getfirst(void)
+{
+    if (! CBHDR)
+        return NULL;
+    return cbfs_verify((void *)(0 - ntohl(CBHDR->romsize) + ntohl(CBHDR->offset)));
+}
+
+// Return the file after the given file.
+static struct cbfs_file *
+cbfs_getnext(struct cbfs_file *file)
+{
+    file = (void*)file + ALIGN(ntohl(file->len) + ntohl(file->offset), ntohl(CBHDR->align));
+    return cbfs_verify(file);
+}
+
+// Find the file with the given filename.
+struct cbfs_file *
+cbfs_findfile(const char *fname)
+{
+    dprintf(3, "Searching CBFS for %s\n", fname);
+    struct cbfs_file *file;
+    for (file = cbfs_getfirst(); file; file = cbfs_getnext(file))
+        if (strcmp(fname, file->filename) == 0)
+            return file;
+    return NULL;
+}
+
+// Find next file with the given filename prefix.
+struct cbfs_file *
+cbfs_findprefix(const char *prefix, struct cbfs_file *last)
+{
+    if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
+        return NULL;
+
+    dprintf(3, "Searching CBFS for prefix %s\n", prefix);
+    int len = strlen(prefix);
+    struct cbfs_file *file;
+    if (! last)
+        file = cbfs_getfirst();
+    else
+        file = cbfs_getnext(last);
+    for (; file; file = cbfs_getnext(file))
+        if (memcmp(prefix, file->filename, len) == 0)
+            return file;
+    return NULL;
+}
+
+// Find a file with the given filename (possibly with ".lzma" extension).
+struct cbfs_file *
+cbfs_finddatafile(const char *fname)
+{
+    int fnlen = strlen(fname);
+    struct cbfs_file *file = NULL;
+    for (;;) {
+        file = cbfs_findprefix(fname, file);
+        if (!file)
+            return NULL;
+        if (file->filename[fnlen] == '\0'
+            || strcmp(&file->filename[fnlen], ".lzma") == 0)
+            return file;
+    }
+}
+
+// Determine whether the file has a ".lzma" extension.
+static int
+cbfs_iscomp(struct cbfs_file *file)
+{
+    int fnamelen = strlen(file->filename);
+    return fnamelen > 5 && strcmp(&file->filename[fnamelen-5], ".lzma") == 0;
+}
+
+// Return the filename of a given file.
+const char *
+cbfs_filename(struct cbfs_file *file)
+{
+    return file->filename;
+}
+
+// Determine the uncompressed size of a datafile.
+u32
+cbfs_datasize(struct cbfs_file *file)
+{
+    void *src = (void*)file + ntohl(file->offset);
+    if (cbfs_iscomp(file))
+        return *(u32*)(src + LZMA_PROPERTIES_SIZE);
+    return ntohl(file->len);
+}
+
+// Copy a file to memory (uncompressing if necessary)
+int
+cbfs_copyfile(struct cbfs_file *file, void *dst, u32 maxlen)
+{
+    if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !file)
+        return -1;
+
+    u32 size = ntohl(file->len);
+    void *src = (void*)file + ntohl(file->offset);
+    if (cbfs_iscomp(file)) {
+        // Compressed - copy to temp ram and uncompress it.
+        void *temp = malloc_tmphigh(size);
+        if (!temp)
+            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;
+}
+
+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 *file)
+{
+    if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !file)
+        return;
+    dprintf(1, "Run %s\n", file->filename);
+    struct cbfs_payload *pay = (void*)file + ntohl(file->offset);
+    struct cbfs_payload_segment *seg = pay->segments;
+    for (;;) {
+        void *src = (void*)pay + ntohl(seg->offset);
+        void *dest = (void*)ntohl((u32)seg->load_addr);
+        u32 src_len = ntohl(seg->len);
+        u32 dest_len = ntohl(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 == htonl(CBFS_COMPRESS_NONE)) {
+                if (src_len > dest_len)
+                    src_len = dest_len;
+                memcpy(dest, src, src_len);
+            } else if (CONFIG_LZMA
+                       && seg->compression == htonl(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)
+{
+    struct cbfs_file *file = NULL;
+    for (;;) {
+        file = cbfs_findprefix("img/", file);
+        if (!file)
+            break;
+        const char *filename = cbfs_filename(file);
+        char *desc = znprintf(MAXDESCSIZE, "Payload [%s]", &filename[4]);
+        boot_add_cbfs(file, desc, bootprio_find_named_rom(filename, 0));
+    }
+}
+
+void
+coreboot_setup(void)
+{
+    coreboot_fill_map();
+    cbfs_setup();
+}
diff --git a/bios/seabios/src/disk.c b/bios/seabios/src/disk.c
new file mode 100644 (file)
index 0000000..8f7c61f
--- /dev/null
@@ -0,0 +1,896 @@
+// 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 "disk.h" // floppy_13
+#include "biosvar.h" // SET_BDA
+#include "config.h" // CONFIG_*
+#include "util.h" // debug_enter
+#include "pic.h" // eoi_pic2
+#include "bregs.h" // struct bregs
+#include "pci.h" // pci_bdf_to_bus
+#include "ata.h" // ATA_CB_DC
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+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);
+}
+
+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_STUB(regs)                         \
+    __disk_stub((regs), __LINE__, __func__)
+
+// Get the cylinders/heads/sectors for the given drive.
+static void
+fillLCHS(struct drive_s *drive_g, u16 *nlc, u16 *nlh, u16 *nlspt)
+{
+    if (CONFIG_CDROM_EMU
+        && drive_g == GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf))) {
+        // Emulated drive - get info from ebda.  (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).
+        u16 ebda_seg = get_ebda_seg();
+        *nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders);
+        *nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads);
+        *nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt);
+        return;
+    }
+    *nlc = GET_GLOBAL(drive_g->lchs.cylinders);
+    *nlh = GET_GLOBAL(drive_g->lchs.heads);
+    *nlspt = GET_GLOBAL(drive_g->lchs.spt);
+}
+
+// Perform read/write/verify using old-style chs accesses
+static void
+basic_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
+{
+    struct disk_op_s dop;
+    dop.drive_g = drive_g;
+    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;
+
+    u16 nlc, nlh, nlspt;
+    fillLCHS(drive_g, &nlc, &nlh, &nlspt);
+
+    // sanity check on cyl heads, sec
+    if (cylinder >= nlc || head >= nlh || sector > nlspt) {
+        warn_invalid(regs);
+        disk_ret(regs, DISK_RET_EPARAM);
+        return;
+    }
+
+    // translate lchs to lba
+    dop.lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
+               + (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
+extended_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
+{
+    struct disk_op_s dop;
+    // Get lba and check.
+    dop.lba = GET_INT13EXT(regs, lba);
+    dop.command = command;
+    dop.drive_g = drive_g;
+    if (dop.lba >= GET_GLOBAL(drive_g->sectors)) {
+        warn_invalid(regs);
+        disk_ret(regs, DISK_RET_EPARAM);
+        return;
+    }
+
+    dop.buf_fl = SEGOFF_TO_FLATPTR(GET_INT13EXT(regs, data));
+    dop.count = GET_INT13EXT(regs, count);
+
+    int status = send_disk_op(&dop);
+
+    SET_INT13EXT(regs, count, dop.count);
+
+    disk_ret(regs, status);
+}
+
+
+/****************************************************************
+ * Hard Drive functions
+ ****************************************************************/
+
+// disk controller reset
+static void
+disk_1300(struct bregs *regs, struct drive_s *drive_g)
+{
+    struct disk_op_s dop;
+    dop.drive_g = drive_g;
+    dop.command = CMD_RESET;
+    int status = send_disk_op(&dop);
+    disk_ret(regs, status);
+}
+
+// read disk status
+static void
+disk_1301(struct bregs *regs, struct drive_s *drive_g)
+{
+    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_g)
+{
+    basic_access(regs, drive_g, CMD_READ);
+}
+
+// write disk sectors
+static void
+disk_1303(struct bregs *regs, struct drive_s *drive_g)
+{
+    basic_access(regs, drive_g, CMD_WRITE);
+}
+
+// verify disk sectors
+static void
+disk_1304(struct bregs *regs, struct drive_s *drive_g)
+{
+    basic_access(regs, drive_g, CMD_VERIFY);
+}
+
+// format disk track
+static void
+disk_1305(struct bregs *regs, struct drive_s *drive_g)
+{
+    debug_stub(regs);
+
+    u16 nlc, nlh, nlspt;
+    fillLCHS(drive_g, &nlc, &nlh, &nlspt);
+
+    u8 num_sectors = regs->al;
+    u8 head        = regs->dh;
+
+    if (head >= nlh || num_sectors == 0 || num_sectors > nlspt) {
+        disk_ret(regs, DISK_RET_EPARAM);
+        return;
+    }
+
+    struct disk_op_s dop;
+    dop.drive_g = drive_g;
+    dop.command = CMD_FORMAT;
+    dop.lba = head;
+    dop.count = num_sectors;
+    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
+disk_1308(struct bregs *regs, struct drive_s *drive_g)
+{
+    u16 ebda_seg = get_ebda_seg();
+    // Get logical geometry from table
+    u16 nlc, nlh, nlspt;
+    fillLCHS(drive_g, &nlc, &nlh, &nlspt);
+    nlc--;
+    nlh--;
+    u8 count;
+    if (regs->dl < EXTSTART_HD) {
+        // Floppy
+        count = GET_GLOBAL(FloppyCount);
+
+        if (CONFIG_CDROM_EMU
+            && drive_g == GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf)))
+            regs->bx = GET_EBDA2(ebda_seg, cdemu.media) * 2;
+        else
+            regs->bx = GET_GLOBAL(drive_g->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_EBDA2(ebda_seg, cdemu.active)) {
+        u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
+        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) | (nlspt & 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_g)
+{
+    DISK_STUB(regs);
+}
+
+// seek to specified cylinder
+static void
+disk_130c(struct bregs *regs, struct drive_s *drive_g)
+{
+    DISK_STUB(regs);
+}
+
+// alternate disk reset
+static void
+disk_130d(struct bregs *regs, struct drive_s *drive_g)
+{
+    DISK_STUB(regs);
+}
+
+// check drive ready
+static void
+disk_1310(struct bregs *regs, struct drive_s *drive_g)
+{
+    // should look at 40:8E also???
+
+    struct disk_op_s dop;
+    dop.drive_g = drive_g;
+    dop.command = CMD_ISREADY;
+    int status = send_disk_op(&dop);
+    disk_ret(regs, status);
+}
+
+// recalibrate
+static void
+disk_1311(struct bregs *regs, struct drive_s *drive_g)
+{
+    DISK_STUB(regs);
+}
+
+// controller internal diagnostic
+static void
+disk_1314(struct bregs *regs, struct drive_s *drive_g)
+{
+    DISK_STUB(regs);
+}
+
+// read disk drive size
+static void
+disk_1315(struct bregs *regs, struct drive_s *drive_g)
+{
+    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
+    u16 nlc, nlh, nlspt;
+    fillLCHS(drive_g, &nlc, &nlh, &nlspt);
+
+    // Compute sector count seen by int13
+    u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
+    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_g)
+{
+    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_g)
+{
+    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_g)
+{
+    extended_access(regs, drive_g, CMD_READ);
+}
+
+// IBM/MS extended write
+static void
+disk_1343(struct bregs *regs, struct drive_s *drive_g)
+{
+    extended_access(regs, drive_g, CMD_WRITE);
+}
+
+// IBM/MS verify
+static void
+disk_1344(struct bregs *regs, struct drive_s *drive_g)
+{
+    extended_access(regs, drive_g, CMD_VERIFY);
+}
+
+// lock
+static void
+disk_134500(struct bregs *regs, struct drive_s *drive_g)
+{
+    u16 ebda_seg = get_ebda_seg();
+    int cdid = regs->dl - EXTSTART_CD;
+    u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
+    if (locks == 0xff) {
+        regs->al = 1;
+        disk_ret(regs, DISK_RET_ETOOMANYLOCKS);
+        return;
+    }
+    SET_EBDA2(ebda_seg, 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_g)
+{
+    u16 ebda_seg = get_ebda_seg();
+    int cdid = regs->dl - EXTSTART_CD;
+    u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
+    if (locks == 0x00) {
+        regs->al = 0;
+        disk_ret(regs, DISK_RET_ENOTLOCKED);
+        return;
+    }
+    locks--;
+    SET_EBDA2(ebda_seg, 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_g)
+{
+    int cdid = regs->dl - EXTSTART_CD;
+    u8 locks = GET_EBDA(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_g)
+{
+    disk_ret_unimplemented(regs, DISK_RET_EPARAM);
+}
+
+// IBM/MS lock/unlock drive
+static void
+disk_1345(struct bregs *regs, struct drive_s *drive_g)
+{
+    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_g); break;
+    case 0x01: disk_134501(regs, drive_g); break;
+    case 0x02: disk_134502(regs, drive_g); break;
+    default:   disk_1345XX(regs, drive_g); break;
+    }
+}
+
+// IBM/MS eject media
+static void
+disk_1346(struct bregs *regs, struct drive_s *drive_g)
+{
+    if (regs->dl < EXTSTART_CD) {
+        // Volume Not Removable
+        disk_ret(regs, DISK_RET_ENOTREMOVABLE);
+        return;
+    }
+
+    int cdid = regs->dl - EXTSTART_CD;
+    u8 locks = GET_EBDA(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_g)
+{
+    extended_access(regs, drive_g, CMD_SEEK);
+}
+
+// IBM/MS get drive parameters
+static void
+disk_1348(struct bregs *regs, struct drive_s *drive_g)
+{
+    u16 size = GET_INT13DPT(regs, size);
+    u16 t13 = size == 74;
+
+    // Buffer is too small
+    if (size < 26) {
+        disk_ret(regs, DISK_RET_EPARAM);
+        return;
+    }
+
+    // EDD 1.x
+
+    u8  type    = GET_GLOBAL(drive_g->type);
+    u16 npc     = GET_GLOBAL(drive_g->pchs.cylinders);
+    u16 nph     = GET_GLOBAL(drive_g->pchs.heads);
+    u16 npspt   = GET_GLOBAL(drive_g->pchs.spt);
+    u64 lba     = GET_GLOBAL(drive_g->sectors);
+    u16 blksize = GET_GLOBAL(drive_g->blksize);
+
+    dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n"
+            , size, type, npc, nph, npspt, (u32)lba, blksize);
+
+    SET_INT13DPT(regs, size, 26);
+    if (type == DTYPE_ATAPI) {
+        // 0x74 = removable, media change, lockable, max values
+        SET_INT13DPT(regs, infos, 0x74);
+        SET_INT13DPT(regs, cylinders, 0xffffffff);
+        SET_INT13DPT(regs, heads, 0xffffffff);
+        SET_INT13DPT(regs, spt, 0xffffffff);
+        SET_INT13DPT(regs, sector_count, (u64)-1);
+    } else {
+        if (lba > (u64)npspt*nph*0x3fff) {
+            SET_INT13DPT(regs, infos, 0x00); // geometry is invalid
+            SET_INT13DPT(regs, cylinders, 0x3fff);
+        } else {
+            SET_INT13DPT(regs, infos, 0x02); // geometry is valid
+            SET_INT13DPT(regs, cylinders, (u32)npc);
+        }
+        SET_INT13DPT(regs, heads, (u32)nph);
+        SET_INT13DPT(regs, spt, (u32)npspt);
+        SET_INT13DPT(regs, sector_count, lba);
+    }
+    SET_INT13DPT(regs, blksize, blksize);
+
+    if (size < 30 ||
+        (type != DTYPE_ATA && type != DTYPE_ATAPI && type != DTYPE_VIRTIO)) {
+        disk_ret(regs, DISK_RET_SUCCESS);
+        return;
+    }
+
+    // EDD 2.x
+
+    int bdf;
+    u16 iobase1 = 0;
+    u64 device_path = 0;
+    u8 channel = 0;
+    SET_INT13DPT(regs, size, 30);
+    if (type == DTYPE_ATA || type == DTYPE_ATAPI) {
+        u16 ebda_seg = get_ebda_seg();
+
+        SET_INT13DPT(regs, dpte_segment, ebda_seg);
+        SET_INT13DPT(regs, dpte_offset
+                     , offsetof(struct extended_bios_data_area_s, dpte));
+
+        // Fill in dpte
+        struct atadrive_s *adrive_g = container_of(
+            drive_g, struct atadrive_s, drive);
+        struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+        u8 slave = GET_GLOBAL(adrive_g->slave);
+        u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+        u8 irq = GET_GLOBALFLAT(chan_gf->irq);
+        iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+        bdf = GET_GLOBALFLAT(chan_gf->pci_bdf);
+        device_path = slave;
+        channel = GET_GLOBALFLAT(chan_gf->chanid);
+
+        u16 options = 0;
+        if (type == DTYPE_ATA) {
+            u8 translation = GET_GLOBAL(drive_g->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_EBDA2(ebda_seg, dpte.iobase1, iobase1);
+        SET_EBDA2(ebda_seg, dpte.iobase2, iobase2 + ATA_CB_DC);
+        SET_EBDA2(ebda_seg, dpte.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
+                                          | ATA_CB_DH_LBA));
+        SET_EBDA2(ebda_seg, dpte.unused, 0xcb);
+        SET_EBDA2(ebda_seg, dpte.irq, irq);
+        SET_EBDA2(ebda_seg, dpte.blkcount, 1);
+        SET_EBDA2(ebda_seg, dpte.dma, 0);
+        SET_EBDA2(ebda_seg, dpte.pio, 0);
+        SET_EBDA2(ebda_seg, dpte.options, options);
+        SET_EBDA2(ebda_seg, dpte.reserved, 0);
+        SET_EBDA2(ebda_seg, dpte.revision, 0x11);
+
+        u8 sum = checksum_far(
+            ebda_seg, (void*)offsetof(struct extended_bios_data_area_s, dpte), 15);
+        SET_EBDA2(ebda_seg, dpte.checksum, -sum);
+    } else {
+        SET_INT13DPT(regs, dpte_segment, 0);
+        SET_INT13DPT(regs, dpte_offset, 0);
+        bdf = GET_GLOBAL(drive_g->cntl_id);
+    }
+
+    if (size < 66) {
+        disk_ret(regs, DISK_RET_SUCCESS);
+        return;
+    }
+
+    // EDD 3.x
+    SET_INT13DPT(regs, key, 0xbedd);
+    SET_INT13DPT(regs, dpi_length, t13 ? 44 : 36);
+    SET_INT13DPT(regs, reserved1, 0);
+    SET_INT13DPT(regs, reserved2, 0);
+
+    if (bdf != -1) {
+        SET_INT13DPT(regs, host_bus[0], 'P');
+        SET_INT13DPT(regs, host_bus[1], 'C');
+        SET_INT13DPT(regs, host_bus[2], 'I');
+        SET_INT13DPT(regs, 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_INT13DPT(regs, iface_path, path);
+    } else {
+        // ISA
+        SET_INT13DPT(regs, host_bus[0], 'I');
+        SET_INT13DPT(regs, host_bus[1], 'S');
+        SET_INT13DPT(regs, host_bus[2], 'A');
+        SET_INT13DPT(regs, host_bus[3], ' ');
+
+        SET_INT13DPT(regs, iface_path, iobase1);
+    }
+
+    if (type != DTYPE_VIRTIO) {
+        SET_INT13DPT(regs, iface_type[0], 'A');
+        SET_INT13DPT(regs, iface_type[1], 'T');
+        SET_INT13DPT(regs, iface_type[2], 'A');
+        SET_INT13DPT(regs, iface_type[3], ' ');
+    } else {
+        SET_INT13DPT(regs, iface_type[0], 'S');
+        SET_INT13DPT(regs, iface_type[1], 'C');
+        SET_INT13DPT(regs, iface_type[2], 'S');
+        SET_INT13DPT(regs, iface_type[3], 'I');
+    }
+    SET_INT13DPT(regs, iface_type[4], ' ');
+    SET_INT13DPT(regs, iface_type[5], ' ');
+    SET_INT13DPT(regs, iface_type[6], ' ');
+    SET_INT13DPT(regs, iface_type[7], ' ');
+
+    if (t13) {
+        SET_INT13DPT(regs, t13.device_path[0], device_path);
+        SET_INT13DPT(regs, t13.device_path[1], 0);
+
+        SET_INT13DPT(regs, t13.checksum
+                     , -checksum_far(regs->ds, (void*)(regs->si+30), 43));
+    } else {
+        SET_INT13DPT(regs, phoenix.device_path, device_path);
+
+        SET_INT13DPT(regs, phoenix.checksum
+                     , -checksum_far(regs->ds, (void*)(regs->si+30), 35));
+    }
+
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+// IBM/MS extended media change
+static void
+disk_1349(struct bregs *regs, struct drive_s *drive_g)
+{
+    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_g)
+{
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e03(struct bregs *regs, struct drive_s *drive_g)
+{
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e04(struct bregs *regs, struct drive_s *drive_g)
+{
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e06(struct bregs *regs, struct drive_s *drive_g)
+{
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134eXX(struct bregs *regs, struct drive_s *drive_g)
+{
+    disk_ret(regs, DISK_RET_EPARAM);
+}
+
+// IBM/MS set hardware configuration
+static void
+disk_134e(struct bregs *regs, struct drive_s *drive_g)
+{
+    switch (regs->al) {
+    case 0x01: disk_134e01(regs, drive_g); break;
+    case 0x03: disk_134e03(regs, drive_g); break;
+    case 0x04: disk_134e04(regs, drive_g); break;
+    case 0x06: disk_134e06(regs, drive_g); break;
+    default:   disk_134eXX(regs, drive_g); break;
+    }
+}
+
+static void
+disk_13XX(struct bregs *regs, struct drive_s *drive_g)
+{
+    disk_ret_unimplemented(regs, DISK_RET_EPARAM);
+}
+
+static void
+disk_13(struct bregs *regs, struct drive_s *drive_g)
+{
+    //debug_stub(regs);
+
+    // clear completion flag
+    SET_BDA(disk_interrupt_flag, 0);
+
+    switch (regs->ah) {
+    case 0x00: disk_1300(regs, drive_g); break;
+    case 0x01: disk_1301(regs, drive_g); break;
+    case 0x02: disk_1302(regs, drive_g); break;
+    case 0x03: disk_1303(regs, drive_g); break;
+    case 0x04: disk_1304(regs, drive_g); break;
+    case 0x05: disk_1305(regs, drive_g); break;
+    case 0x08: disk_1308(regs, drive_g); break;
+    case 0x09: disk_1309(regs, drive_g); break;
+    case 0x0c: disk_130c(regs, drive_g); break;
+    case 0x0d: disk_130d(regs, drive_g); break;
+    case 0x10: disk_1310(regs, drive_g); break;
+    case 0x11: disk_1311(regs, drive_g); break;
+    case 0x14: disk_1314(regs, drive_g); break;
+    case 0x15: disk_1315(regs, drive_g); break;
+    case 0x16: disk_1316(regs, drive_g); break;
+    case 0x41: disk_1341(regs, drive_g); break;
+    case 0x42: disk_1342(regs, drive_g); break;
+    case 0x43: disk_1343(regs, drive_g); break;
+    case 0x44: disk_1344(regs, drive_g); break;
+    case 0x45: disk_1345(regs, drive_g); break;
+    case 0x46: disk_1346(regs, drive_g); break;
+    case 0x47: disk_1347(regs, drive_g); break;
+    case 0x48: disk_1348(regs, drive_g); break;
+    case 0x49: disk_1349(regs, drive_g); break;
+    case 0x4e: disk_134e(regs, drive_g); break;
+    default:   disk_13XX(regs, drive_g); break;
+    }
+}
+
+static void
+floppy_13(struct bregs *regs, struct drive_s *drive_g)
+{
+    // 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_g);
+        break;
+    default:   disk_13XX(regs, drive_g); break;
+    }
+}
+
+
+/****************************************************************
+ * 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_g = getDrive(EXTTYPE_FLOPPY, extdrive);
+        if (!drive_g)
+            goto fail;
+        floppy_13(regs, drive_g);
+        return;
+    }
+
+    struct drive_s *drive_g;
+    if (extdrive >= EXTSTART_CD)
+        drive_g = getDrive(EXTTYPE_CD, extdrive - EXTSTART_CD);
+    else
+        drive_g = getDrive(EXTTYPE_HD, extdrive - EXTSTART_HD);
+    if (!drive_g)
+        goto fail;
+    disk_13(regs, drive_g);
+    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;
+        }
+        u16 ebda_seg = get_ebda_seg();
+        if (GET_EBDA2(ebda_seg, cdemu.active)) {
+            u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
+            if (extdrive == emudrive) {
+                // Access to an emulated drive.
+                struct drive_s *cdemu_g;
+                cdemu_g = GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf));
+                if (regs->ah > 0x16) {
+                    // Only old-style commands supported.
+                    disk_13XX(regs, cdemu_g);
+                    return;
+                }
+                disk_13(regs, cdemu_g);
+                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);
+    eoi_pic2();
+}
+
+// Old Fixed Disk Parameter Table (newer tables are in the ebda).
+struct fdpt_s OldFDPT VAR16FIXED(0xe401);
diff --git a/bios/seabios/src/disk.h b/bios/seabios/src/disk.h
new file mode 100644 (file)
index 0000000..ac33518
--- /dev/null
@@ -0,0 +1,261 @@
+// Definitions for X86 bios disks.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __DISK_H
+#define __DISK_H
+
+#include "types.h" // u8
+#include "config.h" // CONFIG_*
+#include "farptr.h" // struct segoff_s
+
+#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;
+
+#define GET_INT13EXT(regs,var)                                          \
+    GET_FARVAR((regs)->ds, ((struct int13ext_s*)((regs)->si+0))->var)
+#define SET_INT13EXT(regs,var,val)                                      \
+    SET_FARVAR((regs)->ds, ((struct int13ext_s*)((regs)->si+0))->var, (val))
+
+// Disk Physical Table definition
+struct int13dpt_s {
+    u16 size;
+    u16 infos;
+    u32 cylinders;
+    u32 heads;
+    u32 spt;
+    u64 sector_count;
+    u16 blksize;
+    u16 dpte_offset;
+    u16 dpte_segment;
+    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;
+
+#define GET_INT13DPT(regs,var)                                          \
+    GET_FARVAR((regs)->ds, ((struct int13dpt_s*)((regs)->si+0))->var)
+#define SET_INT13DPT(regs,var,val)                                      \
+    SET_FARVAR((regs)->ds, ((struct int13dpt_s*)((regs)->si+0))->var, (val))
+
+// 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;
+
+// Helper function for setting up a return code.
+struct bregs;
+void __disk_ret(struct bregs *regs, u32 linecode, const char *fname);
+#define disk_ret(regs, code) \
+    __disk_ret((regs), (code) | (__LINE__ << 8), __func__)
+void __disk_ret_unimplemented(struct bregs *regs, u32 linecode
+                              , const char *fname);
+#define disk_ret_unimplemented(regs, code) \
+    __disk_ret_unimplemented((regs), (code) | (__LINE__ << 8), __func__)
+
+
+/****************************************************************
+ * Master boot record
+ ****************************************************************/
+
+struct packed_chs_s {
+    u8 heads;
+    u8 sptcyl;
+    u8 cyllow;
+};
+
+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
+
+
+/****************************************************************
+ * Disk command request
+ ****************************************************************/
+
+struct disk_op_s {
+    u64 lba;
+    void *buf_fl;
+    struct drive_s *drive_g;
+    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 heads;      // # heads
+    u16 cylinders;  // # cylinders
+    u16 spt;        // # sectors / track
+};
+
+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   0x01
+#define DTYPE_ATA      0x02
+#define DTYPE_ATAPI    0x03
+#define DTYPE_RAMDISK  0x04
+#define DTYPE_CDEMU    0x05
+#define DTYPE_USB      0x06
+#define DTYPE_VIRTIO   0x07
+#define DTYPE_AHCI     0x08
+
+#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_g);
+void map_floppy_drive(struct drive_s *drive_g);
+void map_hd_drive(struct drive_s *drive_g);
+void map_cd_drive(struct drive_s *drive_g);
+int process_op(struct disk_op_s *op);
+int send_disk_op(struct disk_op_s *op);
+int bounce_buf_init(void);
+
+// 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);
+
+// cdrom.c
+extern struct drive_s *cdemu_drive_gf;
+int process_cdemu_op(struct disk_op_s *op);
+void cdemu_setup(void);
+void cdemu_134b(struct bregs *regs);
+int cdrom_boot(struct drive_s *drive_g);
+
+// ramdisk.c
+void ramdisk_setup(void);
+int process_ramdisk_op(struct disk_op_s *op);
+
+#endif // disk.h
diff --git a/bios/seabios/src/entryfuncs.S b/bios/seabios/src/entryfuncs.S
new file mode 100644 (file)
index 0000000..afc5e61
--- /dev/null
@@ -0,0 +1,173 @@
+// Macros for entering C code
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+/****************************************************************
+ * 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
+
+        // As above, but get calling function from stack.
+        .macro ENTRY_ST
+        cli
+        cld
+        pushl %ecx
+        pushl %edx
+        pushw %es
+        pushw %ds
+        movw %ss, %cx           // Move %ss to %ds
+        movw %cx, %ds
+        pushl %esp              // Backup %esp, then clear high bits
+        movzwl %sp, %esp
+        movl 16(%esp), %ecx     // Get calling function
+        movl %eax, 16(%esp)     // Save %eax
+        calll *%ecx
+        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
+        pushl %eax              // Save registers (matches struct bregs)
+        pushl %ecx
+        pushl %edx
+        pushl %ebx
+        pushl %ebp
+        pushl %esi
+        pushl %edi
+        pushw %es
+        pushw %ds
+        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)
+        popw %ds                // Restore registers (from struct bregs)
+        popw %es
+        popl %edi
+        popl %esi
+        popl %ebp
+        popl %ebx
+        popl %edx
+        popl %ecx
+        popl %eax
+        .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)
+        popw %ds                // Restore registers (from struct bregs)
+        popw %es
+        popl %edi
+        popl %esi
+        popl %ebp
+        popl %ebx
+        popl %edx
+        popl %ecx
+        popl %eax
+        .endm
+
+        // Same as ENTRY_ARG, but don't mangle %esp
+        .macro ENTRY_ARG_ESP cfunc
+        cli
+        cld
+        pushl %eax              // Save registers (matches struct bregs)
+        pushl %ecx
+        pushl %edx
+        pushl %ebx
+        pushl %ebp
+        pushl %esi
+        pushl %edi
+        pushw %es
+        pushw %ds
+        movw %ss, %ax           // Move %ss to %ds
+        movw %ax, %ds
+        movl %esp, %eax         // First arg is pointer to struct bregs
+        calll \cfunc
+        popw %ds                // Restore registers (from struct bregs)
+        popw %es
+        popl %edi
+        popl %esi
+        popl %ebp
+        popl %ebx
+        popl %edx
+        popl %ecx
+        popl %eax
+        .endm
+
+        // Reset stack, transition to 32bit mode, and call a C function.
+        // Clobbers %ax
+        .macro ENTRY_INTO32 cfunc
+        xorw %ax, %ax
+        movw %ax, %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
+
+        // Declare an exported function
+        .macro EXPORTFUNC func
+        .section .text.asm.export.\func
+        .global \func
+        .endm
diff --git a/bios/seabios/src/farptr.h b/bios/seabios/src/farptr.h
new file mode 100644 (file)
index 0000000..3dbf545
--- /dev/null
@@ -0,0 +1,204 @@
+// 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 "ioport.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.hi, __r64_ptr->hi);     \
+        READ32_SEG(prefix, SEG, __value.lo, __r64_ptr->lo);     \
+        *(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->hi, __value.hi);    \
+        WRITE32_SEG(prefix, SEG, __w64_ptr->lo, __value.lo);    \
+    } 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)
+
+// Low level macros for getting/setting a segment register.
+#define __SET_SEG(SEG, value)                                   \
+    __asm__("movw %w1, %%" #SEG : "=m"(__segment_ ## SEG)       \
+            : "rm"(value))
+#define __GET_SEG(SEG) ({                                       \
+    u16 __seg;                                                  \
+    __asm__("movw %%" #SEG ", %w0" : "=rm"(__seg)               \
+            : "m"(__segment_ ## 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
+
+// Definition for common 16bit segment/offset pointers.
+struct segoff_s {
+    union {
+        struct {
+            u16 offset;
+            u16 seg;
+        };
+        u32 segoff;
+    };
+};
+#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/bios/seabios/src/floppy.c b/bios/seabios/src/floppy.c
new file mode 100644 (file)
index 0000000..383744a
--- /dev/null
@@ -0,0 +1,622 @@
+// 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 "types.h" // u8
+#include "disk.h" // DISK_RET_SUCCESS
+#include "config.h" // CONFIG_FLOPPY
+#include "biosvar.h" // SET_BDA
+#include "util.h" // wait_irq
+#include "cmos.h" // inb_cmos
+#include "pic.h" // eoi_pic1
+#include "bregs.h" // struct bregs
+#include "boot.h" // boot_add_floppy
+#include "pci.h" // pci_to_bdf
+#include "pci_ids.h" // PCI_CLASS_BRIDGE_ISA
+
+#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
+
+// 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 VAR16VISIBLE = {
+    .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
+};
+
+// 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_dbt_s diskette_param_table VAR16FIXED(0xefc7) = {
+    .specify1       = 0xAF,
+    .specify2       = 0x02,
+    .shutoff_ticks  = FLOPPY_MOTOR_TICKS,
+    .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,
+    .startup_time   = 0x08,
+};
+
+struct floppyinfo_s {
+    struct chs_s chs;
+    u8 config_data;
+    u8 media_state;
+};
+
+struct floppyinfo_s FloppyInfo[] VAR16VISIBLE = {
+    // Unknown
+    { {0, 0, 0}, 0x00, 0x00},
+    // 1 - 360KB, 5.25" - 2 heads, 40 tracks, 9 sectors
+    { {2, 40, 9}, 0x00, 0x25},
+    // 2 - 1.2MB, 5.25" - 2 heads, 80 tracks, 15 sectors
+    { {2, 80, 15}, 0x00, 0x25},
+    // 3 - 720KB, 3.5"  - 2 heads, 80 tracks, 9 sectors
+    { {2, 80, 9}, 0x00, 0x17},
+    // 4 - 1.44MB, 3.5" - 2 heads, 80 tracks, 18 sectors
+    { {2, 80, 18}, 0x00, 0x17},
+    // 5 - 2.88MB, 3.5" - 2 heads, 80 tracks, 36 sectors
+    { {2, 80, 36}, 0xCC, 0xD7},
+    // 6 - 160k, 5.25"  - 1 heads, 40 tracks, 8 sectors
+    { {1, 40, 8}, 0x00, 0x27},
+    // 7 - 180k, 5.25"  - 1 heads, 40 tracks, 9 sectors
+    { {1, 40, 9}, 0x00, 0x27},
+    // 8 - 320k, 5.25"  - 2 heads, 40 tracks, 8 sectors
+    { {2, 40, 8}, 0x00, 0x27},
+};
+
+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_g = malloc_fseg(sizeof(*drive_g));
+    if (!drive_g) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(drive_g, 0, sizeof(*drive_g));
+    drive_g->cntl_id = floppyid;
+    drive_g->type = DTYPE_FLOPPY;
+    drive_g->blksize = DISK_SECTOR_SIZE;
+    drive_g->floppy_type = ftype;
+    drive_g->sectors = (u64)-1;
+
+    memcpy(&drive_g->lchs, &FloppyInfo[ftype].chs
+           , sizeof(FloppyInfo[ftype].chs));
+    return drive_g;
+}
+
+static void
+addFloppy(int floppyid, int ftype)
+{
+    struct drive_s *drive_g = init_floppy(floppyid, ftype);
+    if (!drive_g)
+        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_g, desc, prio);
+}
+
+void
+floppy_setup(void)
+{
+    if (! CONFIG_FLOPPY)
+        return;
+    dprintf(3, "init floppy drives\n");
+
+    if (CONFIG_COREBOOT) {
+        // XXX - disable floppies on coreboot for now.
+    } else {
+        u8 type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE);
+        if (type & 0xf0)
+            addFloppy(0, type >> 4);
+        if (type & 0x0f)
+            addFloppy(1, type & 0x0f);
+    }
+
+    outb(0x02, PORT_DMA1_MASK_REG);
+
+    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->cylinders * c->heads * c->spt * DISK_SECTOR_SIZE == size)
+            return i;
+    }
+    return -1;
+}
+
+
+/****************************************************************
+ * Low-level floppy IO
+ ****************************************************************/
+
+static void
+floppy_reset_controller(void)
+{
+    // Reset controller
+    u8 val8 = inb(PORT_FD_DOR);
+    outb(val8 & ~0x04, PORT_FD_DOR);
+    outb(val8 | 0x04, PORT_FD_DOR);
+
+    // Wait for controller to come out of reset
+    while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80)
+        ;
+}
+
+static int
+wait_floppy_irq(void)
+{
+    ASSERT16();
+    u8 v;
+    for (;;) {
+        if (!GET_BDA(floppy_motor_counter))
+            return -1;
+        v = GET_BDA(floppy_recalibration_status);
+        if (v & FRS_TIMEOUT)
+            break;
+        // Could use wait_irq() here, but that causes issues on
+        // bochs, so use yield() instead.
+        yield();
+    }
+
+    v &= ~FRS_TIMEOUT;
+    SET_BDA(floppy_recalibration_status, v);
+    return 0;
+}
+
+static void
+floppy_prepare_controller(u8 floppyid)
+{
+    CLEARBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT);
+
+    // turn on motor of selected drive, DMA & int enabled, normal operation
+    u8 prev_reset = inb(PORT_FD_DOR) & 0x04;
+    u8 dor = 0x10;
+    if (floppyid)
+        dor = 0x20;
+    dor |= 0x0c;
+    dor |= floppyid;
+    outb(dor, PORT_FD_DOR);
+
+    // reset the disk motor timeout value of INT 08
+    SET_BDA(floppy_motor_counter, FLOPPY_MOTOR_TICKS);
+
+    // wait for drive readiness
+    while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80)
+        ;
+
+    if (!prev_reset)
+        wait_floppy_irq();
+}
+
+static int
+floppy_pio(u8 *cmd, u8 cmdlen)
+{
+    floppy_prepare_controller(cmd[1] & 1);
+
+    // send command to controller
+    u8 i;
+    for (i=0; i<cmdlen; i++)
+        outb(cmd[i], PORT_FD_DATA);
+
+    int ret = wait_floppy_irq();
+    if (ret) {
+        floppy_reset_controller();
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+floppy_cmd(struct disk_op_s *op, u16 count, u8 *cmd, u8 cmdlen)
+{
+    // es:bx = pointer to where to place information from diskette
+    u32 addr = (u32)op->buf_fl;
+
+    // check for 64K boundary overrun
+    u16 end = count - 1;
+    u32 last_addr = addr + end;
+    if ((addr >> 16) != (last_addr >> 16))
+        return DISK_RET_EBOUNDARY;
+
+    u8 mode_register = 0x4a; // single mode, increment, autoinit disable,
+    if (cmd[0] == 0xe6)
+        // read
+        mode_register = 0x46;
+
+    //DEBUGF("floppy dma c2\n");
+    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
+
+    int ret = floppy_pio(cmd, cmdlen);
+    if (ret)
+        return DISK_RET_ETIMEOUT;
+
+    // check port 3f4 for accessibility to status bytes
+    if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0)
+        return DISK_RET_ECONTROLLER;
+
+    // read 7 return status bytes from controller
+    u8 i;
+    for (i=0; i<7; i++) {
+        u8 v = inb(PORT_FD_DATA);
+        cmd[i] = v;
+        SET_BDA(floppy_return_status[i], v);
+    }
+
+    return DISK_RET_SUCCESS;
+}
+
+
+/****************************************************************
+ * Floppy media sense
+ ****************************************************************/
+
+static inline void
+set_diskette_current_cyl(u8 floppyid, u8 cyl)
+{
+    SET_BDA(floppy_track[floppyid], cyl);
+}
+
+static void
+floppy_drive_recal(u8 floppyid)
+{
+    // send Recalibrate command (2 bytes) to controller
+    u8 data[12];
+    data[0] = 0x07;  // 07: Recalibrate
+    data[1] = floppyid; // 0=drive0, 1=drive1
+    floppy_pio(data, 2);
+
+    SETBITS_BDA(floppy_recalibration_status, 1<<floppyid);
+    set_diskette_current_cyl(floppyid, 0);
+}
+
+static int
+floppy_media_sense(struct drive_s *drive_g)
+{
+    // for now cheat and get drive type from CMOS,
+    // assume media is same as drive type
+
+    // ** config_data **
+    // Bitfields for diskette media control:
+    // Bit(s)  Description (Table M0028)
+    //  7-6  last data rate set by controller
+    //        00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+    //  5-4  last diskette drive step rate selected
+    //        00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
+    //  3-2  {data rate at start of operation}
+    //  1-0  reserved
+
+    // ** media_state **
+    // Bitfields for diskette drive media state:
+    // Bit(s)  Description (Table M0030)
+    //  7-6  data rate
+    //    00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+    //  5  double stepping required (e.g. 360kB in 1.2MB)
+    //  4  media type established
+    //  3  drive capable of supporting 4MB media
+    //  2-0  on exit from BIOS, contains
+    //    000 trying 360kB in 360kB
+    //    001 trying 360kB in 1.2MB
+    //    010 trying 1.2MB in 1.2MB
+    //    011 360kB in 360kB established
+    //    100 360kB in 1.2MB established
+    //    101 1.2MB in 1.2MB established
+    //    110 reserved
+    //    111 all other formats/drives
+
+    u8 ftype = GET_GLOBAL(drive_g->floppy_type);
+    SET_BDA(floppy_last_data_rate, GET_GLOBAL(FloppyInfo[ftype].config_data));
+    u8 floppyid = GET_GLOBAL(drive_g->cntl_id);
+    SET_BDA(floppy_media_state[floppyid]
+            , GET_GLOBAL(FloppyInfo[ftype].media_state));
+    return DISK_RET_SUCCESS;
+}
+
+static int
+check_recal_drive(struct drive_s *drive_g)
+{
+    u8 floppyid = GET_GLOBAL(drive_g->cntl_id);
+    if ((GET_BDA(floppy_recalibration_status) & (1<<floppyid))
+        && (GET_BDA(floppy_media_state[floppyid]) & FMS_MEDIA_DRIVE_ESTABLISHED))
+        // Media is known.
+        return DISK_RET_SUCCESS;
+
+    // Recalibrate drive.
+    floppy_drive_recal(floppyid);
+
+    // Sense media.
+    return floppy_media_sense(drive_g);
+}
+
+
+/****************************************************************
+ * Floppy handlers
+ ****************************************************************/
+
+static void
+lba2chs(struct disk_op_s *op, u8 *track, u8 *sector, u8 *head)
+{
+    u32 lba = op->lba;
+
+    u32 tmp = lba + 1;
+    u16 nlspt = GET_GLOBAL(op->drive_g->lchs.spt);
+    *sector = tmp % nlspt;
+
+    tmp /= nlspt;
+    u16 nlh = GET_GLOBAL(op->drive_g->lchs.heads);
+    *head = tmp % nlh;
+
+    tmp /= nlh;
+    *track = tmp;
+}
+
+// diskette controller reset
+static int
+floppy_reset(struct disk_op_s *op)
+{
+    u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+    set_diskette_current_cyl(floppyid, 0); // current cylinder
+    return DISK_RET_SUCCESS;
+}
+
+// Read Diskette Sectors
+static int
+floppy_read(struct disk_op_s *op)
+{
+    int res = check_recal_drive(op->drive_g);
+    if (res)
+        goto fail;
+
+    u8 track, sector, head;
+    lba2chs(op, &track, &sector, &head);
+
+    // send read-normal-data command (9 bytes) to controller
+    u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+    u8 data[12];
+    data[0] = 0xe6; // e6: read normal data
+    data[1] = (head << 2) | floppyid; // HD DR1 DR2
+    data[2] = track;
+    data[3] = head;
+    data[4] = sector;
+    data[5] = FLOPPY_SIZE_CODE;
+    data[6] = sector + op->count - 1; // last sector to read on track
+    data[7] = FLOPPY_GAPLEN;
+    data[8] = FLOPPY_DATALEN;
+
+    res = floppy_cmd(op, op->count * DISK_SECTOR_SIZE, data, 9);
+    if (res)
+        goto fail;
+
+    if (data[0] & 0xc0) {
+        res = DISK_RET_ECONTROLLER;
+        goto fail;
+    }
+
+    // ??? should track be new val from return_status[3] ?
+    set_diskette_current_cyl(floppyid, track);
+    return DISK_RET_SUCCESS;
+fail:
+    op->count = 0; // no sectors read
+    return res;
+}
+
+// Write Diskette Sectors
+static int
+floppy_write(struct disk_op_s *op)
+{
+    int res = check_recal_drive(op->drive_g);
+    if (res)
+        goto fail;
+
+    u8 track, sector, head;
+    lba2chs(op, &track, &sector, &head);
+
+    // send write-normal-data command (9 bytes) to controller
+    u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+    u8 data[12];
+    data[0] = 0xc5; // c5: write normal data
+    data[1] = (head << 2) | floppyid; // HD DR1 DR2
+    data[2] = track;
+    data[3] = head;
+    data[4] = sector;
+    data[5] = FLOPPY_SIZE_CODE;
+    data[6] = sector + op->count - 1; // last sector to write on track
+    data[7] = FLOPPY_GAPLEN;
+    data[8] = FLOPPY_DATALEN;
+
+    res = floppy_cmd(op, op->count * DISK_SECTOR_SIZE, data, 9);
+    if (res)
+        goto fail;
+
+    if (data[0] & 0xc0) {
+        if (data[1] & 0x02)
+            res = DISK_RET_EWRITEPROTECT;
+        else
+            res = DISK_RET_ECONTROLLER;
+        goto fail;
+    }
+
+    // ??? should track be new val from return_status[3] ?
+    set_diskette_current_cyl(floppyid, track);
+    return DISK_RET_SUCCESS;
+fail:
+    op->count = 0; // no sectors read
+    return res;
+}
+
+// Verify Diskette Sectors
+static int
+floppy_verify(struct disk_op_s *op)
+{
+    int res = check_recal_drive(op->drive_g);
+    if (res)
+        goto fail;
+
+    u8 track, sector, head;
+    lba2chs(op, &track, &sector, &head);
+
+    // ??? should track be new val from return_status[3] ?
+    u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+    set_diskette_current_cyl(floppyid, track);
+    return DISK_RET_SUCCESS;
+fail:
+    op->count = 0; // no sectors read
+    return res;
+}
+
+// format diskette track
+static int
+floppy_format(struct disk_op_s *op)
+{
+    int ret = check_recal_drive(op->drive_g);
+    if (ret)
+        return ret;
+
+    u8 head = op->lba;
+
+    // send format-track command (6 bytes) to controller
+    u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+    u8 data[12];
+    data[0] = 0x4d; // 4d: format track
+    data[1] = (head << 2) | floppyid; // HD DR1 DR2
+    data[2] = FLOPPY_SIZE_CODE;
+    data[3] = op->count; // number of sectors per track
+    data[4] = FLOPPY_FORMAT_GAPLEN;
+    data[5] = FLOPPY_FILLBYTE;
+
+    ret = floppy_cmd(op, op->count * 4, data, 6);
+    if (ret)
+        return ret;
+
+    if (data[0] & 0xc0) {
+        if (data[1] & 0x02)
+            return DISK_RET_EWRITEPROTECT;
+        return DISK_RET_ECONTROLLER;
+    }
+
+    set_diskette_current_cyl(floppyid, 0);
+    return DISK_RET_SUCCESS;
+}
+
+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:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
+
+
+/****************************************************************
+ * HW irqs
+ ****************************************************************/
+
+// INT 0Eh Diskette Hardware ISR Entry Point
+void VISIBLE16
+handle_0e(void)
+{
+    debug_isr(DEBUG_ISR_0e);
+    if (! CONFIG_FLOPPY)
+        goto done;
+
+    if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0) {
+        outb(0x08, PORT_FD_DATA); // sense interrupt status
+        while ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0)
+            ;
+        do {
+            inb(PORT_FD_DATA);
+        } while ((inb(PORT_FD_STATUS) & 0xc0) == 0xc0);
+    }
+    // diskette interrupt has occurred
+    SETBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT);
+
+done:
+    eoi_pic1();
+}
+
+// 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
+            outb(inb(PORT_FD_DOR) & 0xcf, PORT_FD_DOR);
+    }
+}
diff --git a/bios/seabios/src/font.c b/bios/seabios/src/font.c
new file mode 100644 (file)
index 0000000..3f8662f
--- /dev/null
@@ -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] VAR16FIXED(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/bios/seabios/src/gen-defs.h b/bios/seabios/src/gen-defs.h
new file mode 100644 (file)
index 0000000..dabf64c
--- /dev/null
@@ -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/bios/seabios/src/ioport.h b/bios/seabios/src/ioport.h
new file mode 100644 (file)
index 0000000..3282fb4
--- /dev/null
@@ -0,0 +1,136 @@
+// Definitions for X86 IO port access.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __IOPORT_H
+#define __IOPORT_H
+
+#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_PIC1_CMD          0x0020
+#define PORT_PIC1_DATA         0x0021
+#define PORT_PIT_COUNTER0      0x0040
+#define PORT_PIT_COUNTER1      0x0041
+#define PORT_PIT_COUNTER2      0x0042
+#define PORT_PIT_MODE          0x0043
+#define PORT_PS2_DATA          0x0060
+#define PORT_PS2_CTRLB         0x0061
+#define PORT_PS2_STATUS        0x0064
+#define PORT_CMOS_INDEX        0x0070
+#define PORT_CMOS_DATA         0x0071
+#define PORT_DIAG              0x0080
+#define PORT_DMA_PAGE_2        0x0081
+#define PORT_A20               0x0092
+#define PORT_PIC2_CMD          0x00a0
+#define PORT_PIC2_DATA         0x00a1
+#define PORT_SMI_CMD           0x00b2
+#define PORT_SMI_STATUS        0x00b3
+#define PORT_DMA2_MASK_REG     0x00d4
+#define PORT_DMA2_MODE_REG     0x00d6
+#define PORT_DMA2_MASTER_CLEAR 0x00da
+#define PORT_MATH_CLEAR        0x00f0
+#define PORT_ATA2_CMD_BASE     0x0170
+#define PORT_ATA1_CMD_BASE     0x01f0
+#define PORT_LPT2              0x0278
+#define PORT_SERIAL4           0x02e8
+#define PORT_SERIAL2           0x02f8
+#define PORT_ATA2_CTRL_BASE    0x0374
+#define PORT_LPT1              0x0378
+#define PORT_SERIAL3           0x03e8
+#define PORT_ATA1_CTRL_BASE    0x03f4
+#define PORT_FD_BASE           0x03f0
+#define PORT_FD_DOR            0x03f2
+#define PORT_FD_STATUS         0x03f4
+#define PORT_FD_DATA           0x03f5
+#define PORT_HD_DATA           0x03f6
+#define PORT_FD_DIR            0x03f7
+#define PORT_SERIAL1           0x03f8
+#define PORT_PCI_CMD           0x0cf8
+#define PORT_PCI_REBOOT        0x0cf9
+#define PORT_PCI_DATA          0x0cfc
+#define PORT_BIOS_DEBUG        0x0402
+#define PORT_QEMU_CFG_CTL      0x0510
+#define PORT_QEMU_CFG_DATA     0x0511
+#define PORT_ACPI_PM_BASE      0xb000
+#define PORT_SMB_BASE          0xb100
+#define PORT_BIOS_APM          0x8900
+
+// 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
+
+// PORT_A20 bitdefs
+#define A20_ENABLE_BIT 0x02
+
+// PORT_CMOS_INDEX nmi disable bit
+#define NMI_DISABLE_BIT 0x80
+
+#ifndef __ASSEMBLY__
+
+#include "types.h" // u8
+
+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");
+}
+
+#endif // !__ASSEMBLY__
+
+#endif // ioport.h
diff --git a/bios/seabios/src/jpeg.c b/bios/seabios/src/jpeg.c
new file mode 100644 (file)
index 0000000..a96a9d7
--- /dev/null
@@ -0,0 +1,1054 @@
+/*
+ * 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 "util.h"
+#include "jpeg.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/bios/seabios/src/jpeg.h b/bios/seabios/src/jpeg.h
new file mode 100644 (file)
index 0000000..2d08f45
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __JPEG_H
+#define __JPEG_H
+
+struct jpeg_decdata;
+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);
+
+#endif
diff --git a/bios/seabios/src/kbd.c b/bios/seabios/src/kbd.c
new file mode 100644 (file)
index 0000000..1977c5d
--- /dev/null
@@ -0,0 +1,573 @@
+// 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 "util.h" // debug_enter
+#include "config.h" // CONFIG_*
+#include "bregs.h" // struct bregs
+#include "ps2port.h" // ps2_kbd_command
+#include "usb-hid.h" // usb_kbd_command
+
+// 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_setup(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;
+        }
+        wait_irq();
+    }
+
+    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 inline 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
+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
+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 scancode read from the ps2 port.  Note that "noinline" is
+// used to make sure the call to call16_simpint in process_key doesn't
+// have the overhead of this function's stack.
+static void noinline
+__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_vector();
+        }
+        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
+        u32 eax = (0x4f << 8) | key;
+        u32 flags;
+        call16_simpint(0x15, &eax, &flags);
+        if (!(flags & F_CF))
+            return;
+        key = eax;
+    }
+    __process_key(key);
+}
diff --git a/bios/seabios/src/lzmadecode.c b/bios/seabios/src/lzmadecode.c
new file mode 100644 (file)
index 0000000..65819b5
--- /dev/null
@@ -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/bios/seabios/src/lzmadecode.h b/bios/seabios/src/lzmadecode.h
new file mode 100644 (file)
index 0000000..dedde0d
--- /dev/null
@@ -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/bios/seabios/src/memmap.c b/bios/seabios/src/memmap.c
new file mode 100644 (file)
index 0000000..20ccae0
--- /dev/null
@@ -0,0 +1,141 @@
+// 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 "memmap.h" // struct e820entry
+#include "util.h" // dprintf.h
+#include "biosvar.h" // SET_EBDA
+
+
+/****************************************************************
+ * e820 memory map
+ ****************************************************************/
+
+// 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 >= CONFIG_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: %08x%08x - %08x%08x = %d %s\n", i
+                , (u32)(e->start >> 32), (u32)e->start
+                , (u32)(e_end >> 32), (u32)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_finalize(void)
+{
+    dump_map();
+}
diff --git a/bios/seabios/src/memmap.h b/bios/seabios/src/memmap.h
new file mode 100644 (file)
index 0000000..01c7ddb
--- /dev/null
@@ -0,0 +1,32 @@
+#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_finalize(void);
+
+// A typical OS page size
+#define PAGE_SIZE 4096
+
+// e820 map storage (defined in system.c)
+extern struct e820entry e820_list[];
+extern int e820_count;
+
+// Space for exported bios tables (defined in misc.c)
+extern char BiosTableSpace[];
+
+#endif // e820map.h
diff --git a/bios/seabios/src/misc.c b/bios/seabios/src/misc.c
new file mode 100644 (file)
index 0000000..9db49e3
--- /dev/null
@@ -0,0 +1,190 @@
+// 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 "bregs.h" // struct bregs
+#include "biosvar.h" // GET_BDA
+#include "util.h" // debug_enter
+#include "pic.h" // enable_hwirq
+
+// Amount of continuous ram under 4Gig
+u32 RamSize VAR16VISIBLE;
+// Amount of continuous ram >4Gig
+u64 RamSizeOver4G;
+// Space for bios tables built an run-time.
+char BiosTableSpace[CONFIG_MAX_BIOSTABLE] __aligned(MALLOC_MIN_ALIGN) VAR16VISIBLE;
+
+
+/****************************************************************
+ * 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
+    SETBITS_BDA(equipment_list_flags, 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
+    eoi_pic2();
+    // legacy nmi call
+    u32 eax=0, flags;
+    call16_simpint(0x02, &eax, &flags);
+}
+
+
+/****************************************************************
+ * 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 VAR16FIXED(0xe6f5) = {
+    .size     = sizeof(BIOS_CONFIG_TABLE) - 2,
+    .model    = CONFIG_MODEL_ID,
+    .submodel = CONFIG_SUBMODEL_ID,
+    .biosrev  = CONFIG_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 VAR16VISIBLE = {
+    .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 VAR16VISIBLE;
+
+// Protected mode IDT descriptor
+struct descloc_s pmode_IDT_info VAR16VISIBLE = {
+    .length = sizeof(dummy_IDT) - 1,
+    .addr = (u32)MAKE_FLATPTR(SEG_BIOS, &dummy_IDT),
+};
+
+// GDT
+u64 rombios32_gdt[] VAR16VISIBLE __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 VAR16VISIBLE = {
+    .length = sizeof(rombios32_gdt) - 1,
+    .addr = (u32)MAKE_FLATPTR(SEG_BIOS, rombios32_gdt),
+};
+
+
+/****************************************************************
+ * Misc fixed vars
+ ****************************************************************/
+
+char BiosCopyright[] VAR16FIXED(0xff00) =
+    "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team.";
+
+// BIOS build date
+char BiosDate[] VAR16FIXED(0xfff5) = "06/23/99";
+
+u8 BiosModelId VAR16FIXED(0xfffe) = CONFIG_MODEL_ID;
+
+u8 BiosChecksum VAR16FIXED(0xffff);
+
+// XXX - Initial Interrupt Vector Offsets Loaded by POST
+u8 InitVectors[13] VAR16FIXED(0xfef3);
+
+// XXX - INT 1D - SYSTEM DATA - VIDEO PARAMETER TABLES
+u8 VideoParams[88] VAR16FIXED(0xf0a4);
diff --git a/bios/seabios/src/mouse.c b/bios/seabios/src/mouse.c
new file mode 100644 (file)
index 0000000..e26cf69
--- /dev/null
@@ -0,0 +1,326 @@
+// 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 "util.h" // debug_isr
+#include "pic.h" // eoi_pic2
+#include "bregs.h" // struct bregs
+#include "ps2port.h" // ps2_mouse_command
+#include "usb-hid.h" // usb_mouse_command
+
+void
+mouse_setup(void)
+{
+    if (! CONFIG_MOUSE)
+        return;
+    dprintf(3, "init mouse\n");
+    // pointing device installed
+    SETBITS_BDA(equipment_list_flags, 0x04);
+}
+
+static inline 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)
+{
+    u8 mouse_flags_2 = GET_EBDA(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_EBDA2(ebda_seg, mouse_flag1, 0x00);
+    SET_EBDA2(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_EBDA2(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_EBDA2(ebda_seg, mouse_flag2, mouse_flags_2);
+    SET_EBDA2(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 noinline
+process_mouse(u8 data)
+{
+    if (!CONFIG_MOUSE)
+        return;
+
+    u16 ebda_seg = get_ebda_seg();
+    u8 mouse_flags_1 = GET_EBDA2(ebda_seg, mouse_flag1);
+    u8 mouse_flags_2 = GET_EBDA2(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_EBDA2(ebda_seg, mouse_data[index], data);
+
+    if ((index+1) < package_count) {
+        mouse_flags_1++;
+        SET_EBDA2(ebda_seg, mouse_flag1, mouse_flags_1);
+        return;
+    }
+
+    u16 status = GET_EBDA2(ebda_seg, mouse_data[0]);
+    u16 X      = GET_EBDA2(ebda_seg, mouse_data[1]);
+    u16 Y      = GET_EBDA2(ebda_seg, mouse_data[2]);
+    SET_EBDA2(ebda_seg, mouse_flag1, 0);
+
+    struct segoff_s func = GET_EBDA2(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");
+}
diff --git a/bios/seabios/src/mptable.c b/bios/seabios/src/mptable.c
new file mode 100644 (file)
index 0000000..3100c9a
--- /dev/null
@@ -0,0 +1,208 @@
+// MPTable generation (on emulators)
+//
+// 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 "util.h" // dprintf
+#include "config.h" // CONFIG_*
+#include "mptable.h" // MPTABLE_SIGNATURE
+#include "paravirt.h" // qemu_cfg_irq0_override
+#include "pci.h"
+#include "pci_regs.h"
+
+void
+mptable_init(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, CONFIG_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 = ((i<CountCPUs) ? 0x01 : 0x00) | ((i==0) ? 0x02 : 0x00);
+        cpu->cpusignature = cpuid_signature;
+        cpu->featureflag = cpuid_features;
+        cpu++;
+    }
+    int entrycount = cpu - cpus;
+
+    // PCI buses
+    struct mpt_bus *buses = (void*)cpu, *bus = buses;
+    int lastbus = -1;
+    struct pci_device *pci;
+    foreachpci(pci) {
+        int curbus = pci_bdf_to_bus(pci->bdf);
+        if (curbus == lastbus)
+            continue;
+        lastbus = curbus;
+        memset(bus, 0, sizeof(*bus));
+        bus->type = MPT_TYPE_BUS;
+        bus->busid = curbus;
+        memcpy(bus->bustype, "PCI   ", sizeof(bus->bustype));
+        bus++;
+    }
+
+    /* isa bus */
+    int isabusid;
+    memset(bus, 0, sizeof(*bus));
+    bus->type = MPT_TYPE_BUS;
+    isabusid = bus->busid = lastbus + 1;
+    memcpy(bus->bustype, "ISA   ", sizeof(bus->bustype));
+    bus++;
+    entrycount += bus - buses;
+
+    /* ioapic */
+    u8 ioapic_id = CountCPUs;
+    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 mask = 0, pinmask = 0;
+
+    foreachpci(pci) {
+        u16 bdf = pci->bdf;
+        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);
+        mask |= (1 << irq);
+        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++;
+    }
+
+    for (i = 0; i < 16; i++) {
+        memset(intsrc, 0, sizeof(*intsrc));
+        if (mask & (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 (qemu_cfg_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 = 0; /* BSP == APIC #0 */
+    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);
+
+    // Allocate final memory locations.  (In theory the config
+    // structure can go in high memory, but Linux kernels before
+    // v2.6.30 crash with that.)
+    struct mptable_config_s *finalconfig = malloc_fseg(length);
+    struct mptable_floating_s *floating = malloc_fseg(sizeof(*floating));
+    if (!finalconfig || !floating) {
+        warn_noalloc();
+        free(config);
+        free(finalconfig);
+        free(floating);
+        return;
+    }
+    memcpy(finalconfig, config, length);
+    free(config);
+
+    /* floating pointer structure */
+    memset(floating, 0, sizeof(*floating));
+    floating->signature = MPTABLE_SIGNATURE;
+    floating->physaddr = (u32)finalconfig;
+    floating->length = 1;
+    floating->spec_rev = 4;
+    floating->checksum -= checksum(floating, sizeof(*floating));
+
+    dprintf(1, "MP table addr=%p MPC table addr=%p size=%d\n",
+            floating, finalconfig, length);
+}
diff --git a/bios/seabios/src/mptable.h b/bios/seabios/src/mptable.h
new file mode 100644 (file)
index 0000000..c4e3c51
--- /dev/null
@@ -0,0 +1,80 @@
+#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;
+
+// mptable.c
+void mptable_init(void);
+
+#endif // mptable.h
diff --git a/bios/seabios/src/mtrr.c b/bios/seabios/src/mtrr.c
new file mode 100644 (file)
index 0000000..0548043
--- /dev/null
@@ -0,0 +1,103 @@
+// 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 "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "xen.h" // usingXen
+
+#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 || CONFIG_COREBOOT || usingXen())
+        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), BUILD_MAX_HIGHMEM | MTRR_MEMTYPE_UC);
+    wrmsr_smp(MTRRphysMask_MSR(0)
+              , (-((1ull<<32)-BUILD_MAX_HIGHMEM) & phys_mask) | 0x800);
+
+    // Enable fixed and variable MTRRs; set default type.
+    wrmsr_smp(MSR_MTRRdefType, 0xc00 | MTRR_MEMTYPE_WB);
+}
diff --git a/bios/seabios/src/optionroms.c b/bios/seabios/src/optionroms.c
new file mode 100644 (file)
index 0000000..2832eab
--- /dev/null
@@ -0,0 +1,520 @@
+// 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 "farptr.h" // FLATPTR_TO_SEG
+#include "config.h" // CONFIG_*
+#include "util.h" // dprintf
+#include "pci.h" // foreachpci
+#include "pci_regs.h" // PCI_ROM_ADDRESS
+#include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA
+#include "boot.h" // IPL
+#include "paravirt.h" // qemu_cfg_*
+
+
+/****************************************************************
+ * Definitions
+ ****************************************************************/
+
+struct rom_header {
+    u16 signature;
+    u8 size;
+    u8 initVector[4];
+    u8 reserved[17];
+    u16 pcioffset;
+    u16 pnpoffset;
+} PACKED;
+
+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_SIGNATURE 0xaa55
+#define OPTION_ROM_ALIGN 2048
+#define OPTION_ROM_INITVECTOR offsetof(struct rom_header, initVector[0])
+#define PCI_ROM_SIGNATURE 0x52494350 // PCIR
+#define PCIROM_CODETYPE_X86 0
+
+// The end of the last deployed rom.
+u32 RomEnd = BUILD_ROM_START;
+
+
+/****************************************************************
+ * 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();
+    call16big(&br);
+    finish_preempt();
+
+    debug_serial_setup();
+}
+
+// Execute a given option rom at the standard entry vector.
+static 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;
+    return pd;
+}
+
+// Return start of code in 0xc0000-0xf0000 space.
+static inline u32 _max_rom(void) {
+    extern u8 code32flat_start[], code32init_end[];
+    return CONFIG_RELOCATE_INIT ? (u32)code32init_end : (u32)code32flat_start;
+}
+// Return the memory position up to which roms may be located.
+static inline u32 max_rom(void) {
+    u32 end = _max_rom();
+    return end > BUILD_BIOS_ADDR ? BUILD_BIOS_ADDR : end;
+}
+
+// Copy a rom to its permanent location below 1MiB
+static struct rom_header *
+copy_rom(struct rom_header *rom)
+{
+    u32 romsize = rom->size * 512;
+    if (RomEnd + romsize > max_rom()) {
+        // Option rom doesn't fit.
+        warn_noalloc();
+        return NULL;
+    }
+    dprintf(4, "Copying option rom (size %d) from %p to %x\n"
+            , romsize, rom, RomEnd);
+    iomemcpy((void*)RomEnd, rom, romsize);
+    return (void*)RomEnd;
+}
+
+// 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;
+
+    if (isvga || get_pnp_rom(rom))
+        // Only init vga and PnP roms here.
+        callrom(rom, bdf);
+
+    RomEnd = (u32)rom + ALIGN(rom->size * 512, OPTION_ROM_ALIGN);
+
+    return 0;
+}
+
+#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);
+    return bootprio_find_named_rom(romfile_name(source), instance);
+}
+
+
+/****************************************************************
+ * Roms in CBFS
+ ****************************************************************/
+
+// 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);
+    int ret = romfile_copy(romfile_find(fname), (void*)RomEnd
+                           , max_rom() - RomEnd);
+    if (ret <= 0)
+        return NULL;
+    return (void*)RomEnd;
+}
+
+// Run all roms in a given CBFS directory.
+static void
+run_file_roms(const char *prefix, int isvga, u64 *sources)
+{
+    u32 file = 0;
+    for (;;) {
+        file = romfile_findprefix(prefix, file);
+        if (!file)
+            break;
+        struct rom_header *rom = (void*)RomEnd;
+        int ret = romfile_copy(file, rom, max_rom() - RomEnd);
+        if (ret > 0) {
+            setRomSource(sources, rom, file);
+            init_optionrom(rom, 0, isvga);
+        }
+    }
+}
+
+
+/****************************************************************
+ * PCI roms
+ ****************************************************************/
+
+// Verify device is a vga device with legacy address decoding enabled.
+static 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;
+}
+
+// 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 = RomEnd;
+
+    if (CONFIG_OPTIONROMS_DEPLOYED) {
+        // Option roms are already deployed on the system.
+        u32 pos = RomEnd;
+        while (pos < max_rom()) {
+            int ret = init_optionrom((void*)pos, 0, 0);
+            if (ret)
+                pos += OPTION_ROM_ALIGN;
+            else
+                pos = RomEnd;
+        }
+    } 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);
+    }
+
+    // All option roms found and deployed - now build BEV/BCV vectors.
+
+    u32 pos = post_vga;
+    while (pos < RomEnd) {
+        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.
+        if (pnp->bev) {
+            // Can boot system - add to IPL list.
+            boot_add_bev(FLATPTR_TO_SEG(rom), pnp->bev, pnp->productname
+                         , getRomPriority(sources, rom, 0));
+        } else {
+            // Check for BCV (there may be multiple).
+            int instance = 0;
+            while (pnp && pnp->bcv) {
+                boot_add_bcv(FLATPTR_TO_SEG(rom), pnp->bcv, pnp->productname
+                             , getRomPriority(sources, rom, instance++));
+                pnp = get_pnp_next(rom, pnp);
+            }
+        }
+    }
+}
+
+
+/****************************************************************
+ * VGA init
+ ****************************************************************/
+
+static int S3ResumeVgaInit;
+int ScreenAndDebug;
+
+// Call into vga code to turn on console.
+void
+vga_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);
+    S3ResumeVgaInit = romfile_loadint("etc/s3-resume-vga-init", 0);
+    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*)RomEnd, 0, max_rom() - RomEnd);
+
+        // 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);
+    }
+
+    if (RomEnd == BUILD_ROM_START) {
+        // No VGA rom found
+        RomEnd += OPTION_ROM_ALIGN;
+        return;
+    }
+
+    enable_vga_console();
+}
+
+void
+s3_resume_vga_init(void)
+{
+    if (!S3ResumeVgaInit)
+        return;
+    struct rom_header *rom = (void*)BUILD_ROM_START;
+    if (! is_valid_rom(rom))
+        return;
+    callrom(rom, 0);
+}
diff --git a/bios/seabios/src/output.c b/bios/seabios/src/output.c
new file mode 100644 (file)
index 0000000..462ffb7
--- /dev/null
@@ -0,0 +1,581 @@
+// Raw screen writing and debug output code.
+//
+// Copyright (C) 2008,2009  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 "util.h" // printf
+#include "bregs.h" // struct bregs
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+
+struct putcinfo {
+    void (*func)(struct putcinfo *info, char c);
+};
+
+
+/****************************************************************
+ * Debug output
+ ****************************************************************/
+
+#define DEBUG_TIMEOUT 100000
+
+void
+debug_serial_setup(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
+debug_serial(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);
+}
+
+// Make sure all serial port writes have been completely sent.
+static void
+debug_serial_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;
+}
+
+// Write a character to debug port(s).
+static void
+putc_debug(struct putcinfo *action, char c)
+{
+    if (! CONFIG_DEBUG_LEVEL)
+        return;
+    if (! CONFIG_COREBOOT)
+        // Send character to debug port.
+        outb(c, PORT_BIOS_DEBUG);
+    if (c == '\n')
+        debug_serial('\r');
+    debug_serial(c);
+}
+
+// In segmented mode just need a dummy variable (putc_debug is always
+// used anyway), and in 32bit flat mode need a pointer to the 32bit
+// instance of putc_debug().
+#if MODE16
+static struct putcinfo debuginfo VAR16;
+#elif MODESEGMENT
+static struct putcinfo debuginfo VAR32SEG;
+#else
+static struct putcinfo debuginfo = { putc_debug };
+#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;
+    call16_int(0x10, &br);
+}
+
+// Handle a character from a printf request.
+static void
+putc_screen(struct putcinfo *action, char c)
+{
+    if (ScreenAndDebug)
+        putc_debug(&debuginfo, c);
+    if (c == '\n')
+        screenc('\r');
+    screenc(c);
+}
+
+static struct putcinfo screeninfo = { putc_screen };
+
+
+/****************************************************************
+ * Xprintf code
+ ****************************************************************/
+
+// Output a character.
+static void
+putc(struct putcinfo *action, char c)
+{
+    if (MODESEGMENT) {
+        // Only debugging output supported in segmented mode.
+        putc_debug(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.
+static void
+puthex(struct putcinfo *action, u32 val, int width, int spacepad)
+{
+    if (!width) {
+        u32 tmp = val;
+        width = 1;
+        while (tmp >>= 4)
+            width++;
+    } else if (spacepad)  {
+        u32 tmp = val;
+        u32 count = 1;
+        while (tmp >>= 4)
+            count++;
+        if (width > count) {
+            count = width - count;
+            width -= count;
+            while (count--)
+                putc(action, ' ');
+        }
+    }
+
+    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);
+    }
+}
+
+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;
+        int spacepad = 1;
+        for (;;) {
+            c = GET_GLOBAL(*(u8*)n);
+            if (!isdigit(c))
+                break;
+            if (!field_width && (c == '0'))
+                spacepad = 0;
+            else
+                field_width = field_width * 10 + c - '0';
+            n++;
+        }
+        if (c == 'l') {
+            // Ignore long format indicator
+            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 (val < 0) {
+                putc(action, '-');
+                val = -val;
+            }
+            putuint(action, val);
+            break;
+        case 'u':
+            val = va_arg(args, s32);
+            putuint(action, val);
+            break;
+        case 'p':
+            /* %p always has 0x prepended */
+            putc(action, '0');
+            putc(action, 'x');
+            field_width = 8;
+            spacepad = 0;
+        case 'x':
+            val = va_arg(args, s32);
+            puthex(action, val, field_width, spacepad);
+            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_serial_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.
+            putc_debug(&debuginfo, '|');
+            puthex(&debuginfo, (u32)cur, 8, 0);
+            putc_debug(&debuginfo, '|');
+            putc_debug(&debuginfo, ' ');
+        }
+    }
+
+    va_list args;
+    va_start(args, fmt);
+    bvprintf(&debuginfo, fmt, args);
+    va_end(args);
+    debug_serial_flush();
+}
+
+void
+printf(const char *fmt, ...)
+{
+    ASSERT32FLAT();
+    va_list args;
+    va_start(args, fmt);
+    bvprintf(&screeninfo, fmt, args);
+    va_end(args);
+    if (ScreenAndDebug)
+        debug_serial_flush();
+}
+
+
+/****************************************************************
+ * snprintf
+ ****************************************************************/
+
+struct snprintfinfo {
+    struct putcinfo info;
+    char *str, *end;
+};
+
+static void
+putc_str(struct putcinfo *info, char c)
+{
+    struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
+    if (sinfo->str >= sinfo->end)
+        return;
+    *sinfo->str = c;
+    sinfo->str++;
+}
+
+// Build a formatted string.  Note, this function returns the actual
+// number of bytes used (not including null) even in the overflow
+// case.
+int
+snprintf(char *str, size_t size, const char *fmt, ...)
+{
+    ASSERT32FLAT();
+    if (!size)
+        return 0;
+    struct snprintfinfo sinfo = { { putc_str }, str, str + size };
+    va_list args;
+    va_start(args, fmt);
+    bvprintf(&sinfo.info, fmt, args);
+    va_end(args);
+    char *end = sinfo.str;
+    if (end >= sinfo.end)
+        end = sinfo.end - 1;
+    *end = '\0';
+    return end - str;
+}
+
+// Build a formatted string - malloc'ing the memory.
+char *
+znprintf(size_t size, const char *fmt, ...)
+{
+    ASSERT32FLAT();
+    if (!size)
+        return NULL;
+    char *str = malloc_tmp(size);
+    if (!str) {
+        warn_noalloc();
+        return NULL;
+    }
+    struct snprintfinfo sinfo = { { putc_str }, str, str + size };
+    va_list args;
+    va_start(args, fmt);
+    bvprintf(&sinfo.info, fmt, args);
+    va_end(args);
+    char *end = sinfo.str;
+    if (end >= sinfo.end)
+        end = sinfo.end - 1;
+    *end = '\0';
+    return str;
+}
+
+
+/****************************************************************
+ * Misc helpers
+ ****************************************************************/
+
+void
+hexdump(const void *d, int len)
+{
+    int count=0;
+    while (len > 0) {
+        if (count % 8 == 0) {
+            putc(&debuginfo, '\n');
+            puthex(&debuginfo, count*4, 8, 0);
+            putc(&debuginfo, ':');
+        } else {
+            putc(&debuginfo, ' ');
+        }
+        puthex(&debuginfo, *(u32*)d, 8, 0);
+        count++;
+        len-=4;
+        d+=4;
+    }
+    putc(&debuginfo, '\n');
+    debug_serial_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_serial_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/bios/seabios/src/paravirt.c b/bios/seabios/src/paravirt.c
new file mode 100644 (file)
index 0000000..9cf77de
--- /dev/null
@@ -0,0 +1,430 @@
+// Paravirtualization support.
+//
+// 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 "config.h" // CONFIG_COREBOOT
+#include "util.h" // ntoh[ls]
+#include "ioport.h" // outw
+#include "paravirt.h" // qemu_cfg_port_probe
+#include "smbios.h" // struct smbios_structure_header
+
+int qemu_cfg_present;
+
+static void
+qemu_cfg_select(u16 f)
+{
+    outw(f, PORT_QEMU_CFG_CTL);
+}
+
+static void
+qemu_cfg_read(u8 *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);
+}
+
+void qemu_cfg_port_probe(void)
+{
+    char *sig = "QEMU";
+    int i;
+
+    if (CONFIG_COREBOOT)
+        return;
+
+    qemu_cfg_present = 1;
+
+    qemu_cfg_select(QEMU_CFG_SIGNATURE);
+
+    for (i = 0; i < 4; i++)
+        if (inb(PORT_QEMU_CFG_DATA) != sig[i]) {
+            qemu_cfg_present = 0;
+            break;
+        }
+    dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
+}
+
+void qemu_cfg_get_uuid(u8 *uuid)
+{
+    if (!qemu_cfg_present)
+        return;
+
+    qemu_cfg_read_entry(uuid, QEMU_CFG_UUID, 16);
+}
+
+int qemu_cfg_show_boot_menu(void)
+{
+    u16 v;
+    if (!qemu_cfg_present)
+        return 1;
+
+    qemu_cfg_read_entry(&v, QEMU_CFG_BOOT_MENU, sizeof(v));
+
+    return v;
+}
+
+int qemu_cfg_irq0_override(void)
+{
+    u8 v;
+
+    if (!qemu_cfg_present)
+        return 0;
+
+    qemu_cfg_read_entry(&v, QEMU_CFG_IRQ0_OVERRIDE, sizeof(v));
+
+    return v;
+}
+
+u16 qemu_cfg_acpi_additional_tables(void)
+{
+    u16 cnt;
+
+    if (!qemu_cfg_present)
+        return 0;
+
+    qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
+
+    return cnt;
+}
+
+u16 qemu_cfg_next_acpi_table_len(void)
+{
+    u16 len;
+
+    qemu_cfg_read((u8*)&len, sizeof(len));
+
+    return len;
+}
+
+void* qemu_cfg_next_acpi_table_load(void *addr, u16 len)
+{
+    qemu_cfg_read(addr, len);
+    return addr;
+}
+
+u16 qemu_cfg_smbios_entries(void)
+{
+    u16 cnt;
+
+    if (!qemu_cfg_present)
+        return 0;
+
+    qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
+
+    return cnt;
+}
+
+u32 qemu_cfg_e820_entries(void)
+{
+    u32 cnt;
+
+    if (!qemu_cfg_present)
+        return 0;
+
+    qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt));
+    return cnt;
+}
+
+void* qemu_cfg_e820_load_next(void *addr)
+{
+    qemu_cfg_read(addr, sizeof(struct e820_reservation));
+    return addr;
+}
+
+struct smbios_header {
+    u16 length;
+    u8 type;
+} PACKED;
+
+struct smbios_field {
+    struct smbios_header header;
+    u8 type;
+    u16 offset;
+    u8 data[];
+} PACKED;
+
+struct smbios_table {
+    struct smbios_header header;
+    u8 data[];
+} PACKED;
+
+#define SMBIOS_FIELD_ENTRY 0
+#define SMBIOS_TABLE_ENTRY 1
+
+size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr)
+{
+    int i;
+
+    for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
+        struct smbios_field field;
+
+        qemu_cfg_read((u8 *)&field, sizeof(struct smbios_header));
+        field.header.length -= sizeof(struct smbios_header);
+
+        if (field.header.type != SMBIOS_FIELD_ENTRY) {
+            qemu_cfg_skip(field.header.length);
+            continue;
+        }
+
+        qemu_cfg_read((u8 *)&field.type,
+                      sizeof(field) - sizeof(struct smbios_header));
+        field.header.length -= sizeof(field) - sizeof(struct smbios_header);
+
+        if (field.type != type || field.offset != offset) {
+            qemu_cfg_skip(field.header.length);
+            continue;
+        }
+
+        qemu_cfg_read(addr, field.header.length);
+        return (size_t)field.header.length;
+    }
+    return 0;
+}
+
+int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
+                                  unsigned *max_struct_size, char *end)
+{
+    static u64 used_bitmap[4] = { 0 };
+    char *start = *p;
+    int i;
+
+    /* 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;
+
+    for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
+        struct smbios_table table;
+        struct smbios_structure_header *header = (void *)*p;
+        int string;
+
+        qemu_cfg_read((u8 *)&table, sizeof(struct smbios_header));
+        table.header.length -= sizeof(struct smbios_header);
+
+        if (table.header.type != SMBIOS_TABLE_ENTRY) {
+            qemu_cfg_skip(table.header.length);
+            continue;
+        }
+
+        if (end - *p < sizeof(struct smbios_structure_header)) {
+            warn_noalloc();
+            break;
+        }
+
+        qemu_cfg_read((u8 *)*p, sizeof(struct smbios_structure_header));
+        table.header.length -= sizeof(struct smbios_structure_header);
+
+        if (header->type != type) {
+            qemu_cfg_skip(table.header.length);
+            continue;
+        }
+
+        *p += sizeof(struct smbios_structure_header);
+
+        /* 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. */
+        string = header->length < table.header.length +
+                 sizeof(struct smbios_structure_header);
+
+        /* Read the rest and terminate the entry */
+        if (end - *p < table.header.length) {
+            warn_noalloc();
+            *p -= sizeof(struct smbios_structure_header);
+            continue;
+        }
+        qemu_cfg_read((u8 *)*p, table.header.length);
+        *p += table.header.length;
+        *((u8*)*p) = 0;
+        (*p)++;
+        if (!string) {
+            *((u8*)*p) = 0;
+            (*p)++;
+        }
+
+        (*nr_structs)++;
+        if (*p - (char *)header > *max_struct_size)
+            *max_struct_size = *p - (char *)header;
+    }
+
+    if (start != *p) {
+        /* Mark that we've reported on this type */
+        used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
+        return 1;
+    }
+
+    return 0;
+}
+
+int qemu_cfg_get_numa_nodes(void)
+{
+    u64 cnt;
+
+    qemu_cfg_read_entry(&cnt, QEMU_CFG_NUMA, sizeof(cnt));
+
+    return (int)cnt;
+}
+
+void qemu_cfg_get_numa_data(u64 *data, int n)
+{
+    int i;
+
+    for (i = 0; i < n; i++)
+        qemu_cfg_read((u8*)(data + i), sizeof(u64));
+}
+
+u16 qemu_cfg_get_max_cpus(void)
+{
+    u16 cnt;
+
+    if (!qemu_cfg_present)
+        return 0;
+
+    qemu_cfg_read_entry(&cnt, QEMU_CFG_MAX_CPUS, sizeof(cnt));
+
+    return cnt;
+}
+
+static QemuCfgFile LastFile;
+
+static u32
+__cfg_next_prefix_file(const char *prefix, int prefixlen, u32 prevselect)
+{
+    if (!qemu_cfg_present)
+        return 0;
+
+    u32 count;
+    qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
+    count = ntohl(count);
+    u32 e;
+    for (e = 0; e < count; e++) {
+        qemu_cfg_read((void*)&LastFile, sizeof(LastFile));
+        u32 select = ntohs(LastFile.select);
+        if (select <= prevselect)
+            continue;
+        if (memcmp(prefix, LastFile.name, prefixlen) == 0)
+            return select;
+    }
+    return 0;
+}
+
+u32 qemu_cfg_next_prefix_file(const char *prefix, u32 prevselect)
+{
+    return __cfg_next_prefix_file(prefix, strlen(prefix), prevselect);
+}
+
+u32 qemu_cfg_find_file(const char *name)
+{
+    return __cfg_next_prefix_file(name, strlen(name) + 1, 0);
+}
+
+static int
+__qemu_cfg_set_file(u32 select)
+{
+    if (!qemu_cfg_present || !select)
+        return -1;
+    if (select == ntohs(LastFile.select))
+        return 0;
+
+    u32 count;
+    qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
+    count = ntohl(count);
+    u32 e;
+    for (e = 0; e < count; e++) {
+        qemu_cfg_read((void*)&LastFile, sizeof(LastFile));
+        if (select == ntohs(LastFile.select))
+            return 0;
+    }
+    return -1;
+}
+
+int qemu_cfg_size_file(u32 select)
+{
+    if (__qemu_cfg_set_file(select))
+        return -1;
+    return ntohl(LastFile.size);
+}
+
+const char* qemu_cfg_name_file(u32 select)
+{
+    if (__qemu_cfg_set_file(select))
+        return NULL;
+    return LastFile.name;
+}
+
+int qemu_cfg_read_file(u32 select, void *dst, u32 maxlen)
+{
+    if (__qemu_cfg_set_file(select))
+        return -1;
+    int len = qemu_cfg_size_file(select);
+    if (len < 0 || len > maxlen)
+        return -1;
+    qemu_cfg_read_entry(dst, select, len);
+    return len;
+}
+
+// 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)
+{
+    u32 file = romfile_find(name);
+    if (!file)
+        return NULL;
+
+    int filesize = romfile_size(file);
+    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);
+    romfile_copy(file, data, filesize);
+    if (psize)
+        *psize = filesize;
+    data[filesize] = '\0';
+    return data;
+}
+
+// Attempt to load an integer from the given file - return 'defval'
+// if unsuccesful.
+u64
+romfile_loadint(const char *name, u64 defval)
+{
+    u32 file = romfile_find(name);
+    if (!file)
+        return defval;
+
+    int filesize = romfile_size(file);
+    if (!filesize || filesize > sizeof(u64) || (filesize & (filesize-1)))
+        // Doesn't look like a valid integer.
+        return defval;
+
+    u64 val = 0;
+    romfile_copy(file, &val, sizeof(val));
+    return val;
+}
diff --git a/bios/seabios/src/paravirt.h b/bios/seabios/src/paravirt.h
new file mode 100644 (file)
index 0000000..4a370a0
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef __PV_H
+#define __PV_H
+
+#include "config.h" // CONFIG_COREBOOT
+#include "util.h"
+
+/* 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 inline int kvm_para_available(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)
+        return 1;
+
+    return 0;
+}
+
+#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)
+
+extern int qemu_cfg_present;
+
+void qemu_cfg_port_probe(void);
+int qemu_cfg_show_boot_menu(void);
+void qemu_cfg_get_uuid(u8 *uuid);
+int qemu_cfg_irq0_override(void);
+u16 qemu_cfg_acpi_additional_tables(void);
+u16 qemu_cfg_next_acpi_table_len(void);
+void *qemu_cfg_next_acpi_table_load(void *addr, u16 len);
+u16 qemu_cfg_smbios_entries(void);
+size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr);
+int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
+                                  unsigned *max_struct_size, char *end);
+int qemu_cfg_get_numa_nodes(void);
+void qemu_cfg_get_numa_data(u64 *data, int n);
+u16 qemu_cfg_get_max_cpus(void);
+
+typedef struct QemuCfgFile {
+    u32  size;        /* file size */
+    u16  select;      /* write this to 0x510 to read it */
+    u16  reserved;
+    char name[56];
+} QemuCfgFile;
+
+struct e820_reservation {
+    u64 address;
+    u64 length;
+    u32 type;
+};
+
+u32 qemu_cfg_next_prefix_file(const char *prefix, u32 prevselect);
+u32 qemu_cfg_find_file(const char *name);
+int qemu_cfg_size_file(u32 select);
+const char* qemu_cfg_name_file(u32 select);
+int qemu_cfg_read_file(u32 select, void *dst, u32 maxlen);
+
+// Wrappers that select cbfs or qemu_cfg file interface.
+static inline u32 romfile_findprefix(const char *prefix, u32 previd) {
+    if (CONFIG_COREBOOT)
+        return (u32)cbfs_findprefix(prefix, (void*)previd);
+    return qemu_cfg_next_prefix_file(prefix, previd);
+}
+static inline u32 romfile_find(const char *name) {
+    if (CONFIG_COREBOOT)
+        return (u32)cbfs_finddatafile(name);
+    return qemu_cfg_find_file(name);
+}
+static inline u32 romfile_size(u32 fileid) {
+    if (CONFIG_COREBOOT)
+        return cbfs_datasize((void*)fileid);
+    return qemu_cfg_size_file(fileid);
+}
+static inline int romfile_copy(u32 fileid, void *dst, u32 maxlen) {
+    if (CONFIG_COREBOOT)
+        return cbfs_copyfile((void*)fileid, dst, maxlen);
+    return qemu_cfg_read_file(fileid, dst, maxlen);
+}
+static inline const char* romfile_name(u32 fileid) {
+    if (CONFIG_COREBOOT)
+        return cbfs_filename((void*)fileid);
+    return qemu_cfg_name_file(fileid);
+}
+void *romfile_loadfile(const char *name, int *psize);
+u64 romfile_loadint(const char *name, u64 defval);
+
+u32 qemu_cfg_e820_entries(void);
+void* qemu_cfg_e820_load_next(void *addr);
+
+#endif
diff --git a/bios/seabios/src/pci.c b/bios/seabios/src/pci.c
new file mode 100644 (file)
index 0000000..6031c9f
--- /dev/null
@@ -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 "pci.h" // pci_config_writel
+#include "ioport.h" // outl
+#include "util.h" // dprintf
+#include "paravirt.h" // romfile_loadint
+#include "farptr.h" // MAKE_FLATPTR
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA
+
+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 pci_device *PCIDevices;
+int MaxPCIBus VAR16VISIBLE;
+
+// 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 pci_device **pprev = &PCIDevices;
+    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));
+            *pprev = dev;
+            pprev = &dev->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;
+}
+
+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);
+}
+
+// helper functions to access pci mmio bars from real mode
+
+u32 VISIBLE32FLAT
+pci_readl_32(u32 addr)
+{
+    dprintf(3, "32: pci read : %x\n", addr);
+    return readl((void*)addr);
+}
+
+u32 pci_readl(u32 addr)
+{
+    if (MODESEGMENT) {
+        dprintf(3, "16: pci read : %x\n", addr);
+        extern void _cfunc32flat_pci_readl_32(u32 addr);
+        return call32(_cfunc32flat_pci_readl_32, addr, -1);
+    } else {
+        return pci_readl_32(addr);
+    }
+}
+
+struct reg32 {
+    u32 addr;
+    u32 data;
+};
+
+void VISIBLE32FLAT
+pci_writel_32(struct reg32 *reg32)
+{
+    dprintf(3, "32: pci write: %x, %x (%p)\n", reg32->addr, reg32->data, reg32);
+    writel((void*)(reg32->addr), reg32->data);
+}
+
+void pci_writel(u32 addr, u32 val)
+{
+    struct reg32 reg32 = { .addr = addr, .data = val };
+    if (MODESEGMENT) {
+        dprintf(3, "16: pci write: %x, %x (%x:%p)\n",
+                reg32.addr, reg32.data, GET_SEG(SS), &reg32);
+        void *flatptr = MAKE_FLATPTR(GET_SEG(SS), &reg32);
+        extern void _cfunc32flat_pci_writel_32(struct reg32 *reg32);
+        call32(_cfunc32flat_pci_writel_32, (u32)flatptr, -1);
+    } else {
+        pci_writel_32(&reg32);
+    }
+}
diff --git a/bios/seabios/src/pci.h b/bios/seabios/src/pci.h
new file mode 100644 (file)
index 0000000..a2a5a4c
--- /dev/null
@@ -0,0 +1,162 @@
+#ifndef __PCI_H
+#define __PCI_H
+
+#include "types.h" // u32
+
+#define PCI_ROM_SLOT 6
+#define PCI_NUM_REGIONS 7
+
+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 pci_device *next;
+    struct pci_device *parent;
+
+    // Configuration space device information
+    u16 vendor, device;
+    u16 class;
+    u8 prog_if, revision;
+    u8 header_type;
+    u8 secondary_bus;
+    struct {
+        u32 addr;
+        u32 size;
+        int is64;
+    } bars[PCI_NUM_REGIONS];
+
+    // Local information on device.
+    int have_driver;
+};
+extern struct pci_device *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)                         \
+    for (PCI=PCIDevices; PCI; PCI=PCI->next)
+
+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);
+void pci_reboot(void);
+
+// helper functions to access pci mmio bars from real mode
+u32 pci_readl(u32 addr);
+void pci_writel(u32 addr, u32 val);
+
+// pirtable.c
+void create_pirtable(void);
+
+
+/****************************************************************
+ * PIR table
+ ****************************************************************/
+
+extern u16 PirOffset;
+
+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
diff --git a/bios/seabios/src/pci_ids.h b/bios/seabios/src/pci_ids.h
new file mode 100644 (file)
index 0000000..e1cded2
--- /dev/null
@@ -0,0 +1,2610 @@
+/*
+ *     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_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_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_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
diff --git a/bios/seabios/src/pci_regs.h b/bios/seabios/src/pci_regs.h
new file mode 100644 (file)
index 0000000..e5effd4
--- /dev/null
@@ -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/bios/seabios/src/pcibios.c b/bios/seabios/src/pcibios.c
new file mode 100644 (file)
index 0000000..8b792fb
--- /dev/null
@@ -0,0 +1,237 @@
+// 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 "types.h" // u32
+#include "util.h" // handle_1ab1
+#include "pci.h" // pci_config_readl
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_EBDA
+#include "pci_regs.h" // PCI_VENDOR_ID
+
+// 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_g = (void*)(GET_GLOBAL(PirOffset) + 0);
+    if (! pirtable_g) {
+        set_code_invalid(regs, RET_FUNC_NOT_SUPPORTED);
+        return;
+    }
+
+    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;
+    }
+}
+
+
+/****************************************************************
+ * 32bit interface
+ ****************************************************************/
+
+// Entry point for 32bit pci bios functions.
+void VISIBLE32SEG
+handle_pcibios32(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_HDL_pcibios32);
+    handle_1ab1(regs);
+}
+
+struct bios32_s {
+    u32 signature;
+    u32 entry;
+    u8 version;
+    u8 length;
+    u8 checksum;
+    u8 reserved[5];
+} PACKED;
+
+struct bios32_s BIOS32HEADER __aligned(16) VAR16EXPORT = {
+    .signature = 0x5f32335f, // _32_
+    .length = sizeof(BIOS32HEADER) / 16,
+};
+
+void
+bios32_setup(void)
+{
+    dprintf(3, "init bios32\n");
+
+    BIOS32HEADER.entry = (u32)entry_bios32;
+    BIOS32HEADER.checksum -= checksum(&BIOS32HEADER, sizeof(BIOS32HEADER));
+}
diff --git a/bios/seabios/src/pciinit.c b/bios/seabios/src/pciinit.c
new file mode 100644 (file)
index 0000000..0d8758e
--- /dev/null
@@ -0,0 +1,620 @@
+// 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 "util.h" // dprintf
+#include "pci.h" // pci_config_readl
+#include "biosvar.h" // GET_EBDA
+#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "pci_regs.h" // PCI_COMMAND
+#include "xen.h" // usingXen
+
+#define PCI_IO_INDEX_SHIFT 2
+#define PCI_MEM_INDEX_SHIFT 12
+
+#define PCI_BRIDGE_IO_MIN      0x1000
+#define PCI_BRIDGE_MEM_MIN   0x100000
+
+enum pci_region_type {
+    PCI_REGION_TYPE_IO,
+    PCI_REGION_TYPE_MEM,
+    PCI_REGION_TYPE_PREFMEM,
+    PCI_REGION_TYPE_COUNT,
+};
+
+static const char *region_type_name[] = {
+    [ PCI_REGION_TYPE_IO ]      = "io",
+    [ PCI_REGION_TYPE_MEM ]     = "mem",
+    [ PCI_REGION_TYPE_PREFMEM ] = "prefmem",
+};
+
+static struct pci_bus {
+    struct {
+        /* pci region stats */
+        u32 count[32 - PCI_MEM_INDEX_SHIFT];
+        u32 sum, max;
+        /* seconday bus region sizes */
+        u32 size;
+        /* pci region assignments */
+        u32 bases[32 - PCI_MEM_INDEX_SHIFT];
+        u32 base;
+    } r[PCI_REGION_TYPE_COUNT];
+} *busses;
+static int busses_count;
+
+static void pci_bios_init_device_in_bus(int bus);
+static void pci_bios_check_device_in_bus(int bus);
+static void pci_bios_init_bus_bases(struct pci_bus *bus);
+static void pci_bios_map_device_in_bus(int bus);
+
+static int pci_size_to_index(u32 size, enum pci_region_type type)
+{
+    int index = __fls(size);
+    int shift = (type == PCI_REGION_TYPE_IO) ?
+        PCI_IO_INDEX_SHIFT : PCI_MEM_INDEX_SHIFT;
+
+    if (index < shift)
+        index = shift;
+    index -= shift;
+    return index;
+}
+
+static u32 pci_index_to_size(int index, enum pci_region_type type)
+{
+    int shift = (type == PCI_REGION_TYPE_IO) ?
+        PCI_IO_INDEX_SHIFT : PCI_MEM_INDEX_SHIFT;
+
+    return 0x1 << (index + shift);
+}
+
+static enum pci_region_type pci_addr_to_type(u32 addr)
+{
+    if (addr & PCI_BASE_ADDRESS_SPACE_IO)
+        return PCI_REGION_TYPE_IO;
+    if (addr & PCI_BASE_ADDRESS_MEM_PREFETCH)
+        return PCI_REGION_TYPE_PREFMEM;
+    return PCI_REGION_TYPE_MEM;
+}
+
+static u32 pci_size_roundup(u32 size)
+{
+    int index = __fls(size-1)+1;
+    return 0x1 << index;
+}
+
+/* host irqs corresponding to PCI irqs A-D */
+const u8 pci_irqs[4] = {
+    10, 10, 11, 11
+};
+
+static u32 pci_bar(u16 bdf, 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_config_readb(bdf, PCI_HEADER_TYPE);
+    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(u16 bdf, int region_num, u32 addr)
+{
+    u32 ofs;
+
+    ofs = pci_bar(bdf, region_num);
+
+    pci_config_writel(bdf, ofs, addr);
+}
+
+/* return the global irq number corresponding to a given device irq
+   pin. We could also use the bus number to have a more precise
+   mapping. */
+static int pci_slot_get_pirq(u16 bdf, int irq_num)
+{
+    int slot_addend = pci_bdf_to_dev(bdf) - 1;
+    return (irq_num + slot_addend) & 3;
+}
+
+/* PIIX3/PIIX4 PCI to ISA bridge */
+static void piix_isa_bridge_init(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], 0x4d0);
+    outb(elcr[1], 0x4d1);
+    dprintf(1, "PIIX3/PIIX4 init: elcr=%02x %02x\n", elcr[0], elcr[1]);
+}
+
+static const struct pci_device_id pci_isa_bridge_tbl[] = {
+    /* PIIX3/PIIX4 PCI to ISA bridge */
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0,
+               piix_isa_bridge_init),
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
+               piix_isa_bridge_init),
+
+    PCI_DEVICE_END
+};
+
+#define PCI_IO_ALIGN            4096
+#define PCI_IO_SHIFT            8
+#define PCI_MEMORY_ALIGN        (1UL << 20)
+#define PCI_MEMORY_SHIFT        16
+#define PCI_PREF_MEMORY_ALIGN   (1UL << 20)
+#define PCI_PREF_MEMORY_SHIFT   16
+
+static void storage_ide_init(struct pci_device *pci, void *arg)
+{
+    u16 bdf = pci->bdf;
+    /* IDE: we map it as in ISA mode */
+    pci_set_io_region_addr(bdf, 0, PORT_ATA1_CMD_BASE);
+    pci_set_io_region_addr(bdf, 1, PORT_ATA1_CTRL_BASE);
+    pci_set_io_region_addr(bdf, 2, PORT_ATA2_CMD_BASE);
+    pci_set_io_region_addr(bdf, 3, PORT_ATA2_CTRL_BASE);
+}
+
+/* PIIX3/PIIX4 IDE */
+static void piix_ide_init(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_init(struct pci_device *pci, void *arg)
+{
+    /* PIC, IBM, MPIC & MPIC2 */
+    pci_set_io_region_addr(pci->bdf, 0, 0x80800000 + 0x00040000);
+}
+
+static void apple_macio_init(struct pci_device *pci, void *arg)
+{
+    /* macio bridge */
+    pci_set_io_region_addr(pci->bdf, 0, 0x80800000);
+}
+
+static const struct pci_device_id pci_class_tbl[] = {
+    /* STORAGE IDE */
+    PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1,
+                     PCI_CLASS_STORAGE_IDE, piix_ide_init),
+    PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,
+                     PCI_CLASS_STORAGE_IDE, piix_ide_init),
+    PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE,
+                     storage_ide_init),
+
+    /* PIC, IBM, MIPC & MPIC2 */
+    PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0x0046, PCI_CLASS_SYSTEM_PIC,
+                     pic_ibm_init),
+    PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0xFFFF, PCI_CLASS_SYSTEM_PIC,
+                     pic_ibm_init),
+
+    /* 0xff00 */
+    PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0017, 0xff00, apple_macio_init),
+    PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0022, 0xff00, apple_macio_init),
+
+    PCI_DEVICE_END,
+};
+
+/* PIIX4 Power Management device (for ACPI) */
+static void piix4_pm_init(struct pci_device *pci, void *arg)
+{
+    u16 bdf = pci->bdf;
+    // acpi sci is hardwired to 9
+    pci_config_writeb(bdf, PCI_INTERRUPT_LINE, 9);
+
+    pci_config_writel(bdf, 0x40, PORT_ACPI_PM_BASE | 1);
+    pci_config_writeb(bdf, 0x80, 0x01); /* enable PM io space */
+    pci_config_writel(bdf, 0x90, PORT_SMB_BASE | 1);
+    pci_config_writeb(bdf, 0xd2, 0x09); /* enable SMBus io space */
+}
+
+static const struct pci_device_id pci_device_tbl[] = {
+    /* PIIX4 Power Management device (for ACPI) */
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+               piix4_pm_init),
+
+    PCI_DEVICE_END,
+};
+
+static void pci_bios_init_device(struct pci_device *pci)
+{
+    u16 bdf = pci->bdf;
+    int pin, pic_irq;
+
+    dprintf(1, "PCI: bus=%d devfn=0x%02x: vendor_id=0x%04x device_id=0x%04x\n"
+            , pci_bdf_to_bus(bdf), pci_bdf_to_devfn(bdf)
+            , pci->vendor, pci->device);
+    pci_init_device(pci_class_tbl, pci, NULL);
+
+    /* enable memory mappings */
+    pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+    /* map the interrupt */
+    pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
+    if (pin != 0) {
+        pin = pci_slot_get_pirq(bdf, pin - 1);
+        pic_irq = pci_irqs[pin];
+        pci_config_writeb(bdf, PCI_INTERRUPT_LINE, pic_irq);
+    }
+
+    pci_init_device(pci_device_tbl, pci, NULL);
+}
+
+static void pci_bios_init_device_in_bus(int bus)
+{
+    struct pci_device *pci;
+    foreachpci(pci) {
+        u8 pci_bus = pci_bdf_to_bus(pci->bdf);
+        if (pci_bus < bus)
+            continue;
+        if (pci_bus > bus)
+            break;
+        pci_bios_init_device(pci);
+    }
+}
+
+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 pci_bus = 0;
+    pci_bios_init_bus_rec(0 /* host bus */, &pci_bus);
+    busses_count = pci_bus + 1;
+}
+
+static void pci_bios_bus_get_bar(struct pci_bus *bus, int bdf, int bar,
+                                 u32 *val, u32 *size)
+{
+    u32 ofs = pci_bar(bdf, bar);
+    u32 old = pci_config_readl(bdf, ofs);
+    u32 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;
+        else
+            mask = PCI_BASE_ADDRESS_MEM_MASK;
+        pci_config_writel(bdf, ofs, ~0);
+    }
+    *val = pci_config_readl(bdf, ofs);
+    pci_config_writel(bdf, ofs, old);
+    *size = (~(*val & mask)) + 1;
+}
+
+static void pci_bios_bus_reserve(struct pci_bus *bus, int type, u32 size)
+{
+    u32 index;
+
+    index = pci_size_to_index(size, type);
+    size = pci_index_to_size(index, type);
+    bus->r[type].count[index]++;
+    bus->r[type].sum += size;
+    if (bus->r[type].max < size)
+        bus->r[type].max = size;
+}
+
+static u32 pci_bios_bus_get_addr(struct pci_bus *bus, int type, u32 size)
+{
+    u32 index, addr;
+
+    index = pci_size_to_index(size, type);
+    addr = bus->r[type].bases[index];
+    bus->r[type].bases[index] += pci_index_to_size(index, type);
+    return addr;
+}
+
+static void pci_bios_check_device(struct pci_bus *bus, struct pci_device *dev)
+{
+    u16 bdf = dev->bdf;
+    u32 limit;
+    int i,type;
+
+    if (dev->class == PCI_CLASS_BRIDGE_PCI) {
+        if (dev->secondary_bus >= busses_count) {
+            /* should never trigger */
+            dprintf(1, "PCI: bus count too small (%d), skipping bus #%d\n",
+                    busses_count, dev->secondary_bus);
+            return;
+        }
+        struct pci_bus *s = busses + dev->secondary_bus;
+        pci_bios_check_device_in_bus(dev->secondary_bus);
+        for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
+            limit = (type == PCI_REGION_TYPE_IO) ?
+                PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN;
+            s->r[type].size = s->r[type].sum;
+            if (s->r[type].size < limit)
+                s->r[type].size = limit;
+            s->r[type].size = pci_size_roundup(s->r[type].size);
+            pci_bios_bus_reserve(bus, type, s->r[type].size);
+        }
+        dprintf(1, "PCI: secondary bus %d sizes: io %x, mem %x, prefmem %x\n",
+                dev->secondary_bus,
+                s->r[PCI_REGION_TYPE_IO].size,
+                s->r[PCI_REGION_TYPE_MEM].size,
+                s->r[PCI_REGION_TYPE_PREFMEM].size);
+        return;
+    }
+
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        u32 val, size;
+        pci_bios_bus_get_bar(bus, bdf, i, &val, &size);
+        if (val == 0) {
+            continue;
+        }
+        pci_bios_bus_reserve(bus, pci_addr_to_type(val), size);
+        dev->bars[i].addr = val;
+        dev->bars[i].size = size;
+        dev->bars[i].is64 = (!(val & PCI_BASE_ADDRESS_SPACE_IO) &&
+            (val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64);
+
+        if (dev->bars[i].is64) {
+            i++;
+        }
+    }
+}
+
+static void pci_bios_map_device(struct pci_bus *bus, struct pci_device *dev)
+{
+    u16 bdf = dev->bdf;
+    int type, i;
+
+    if (dev->class == PCI_CLASS_BRIDGE_PCI) {
+        if (dev->secondary_bus >= busses_count) {
+            return;
+        }
+        struct pci_bus *s = busses + dev->secondary_bus;
+        u32 base, limit;
+
+        for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
+            s->r[type].base = pci_bios_bus_get_addr(bus, type, s->r[type].size);
+        }
+        dprintf(1, "PCI: init bases bus %d (secondary)\n", dev->secondary_bus);
+        pci_bios_init_bus_bases(s);
+
+        base = s->r[PCI_REGION_TYPE_IO].base;
+        limit = base + s->r[PCI_REGION_TYPE_IO].size - 1;
+        pci_config_writeb(bdf, PCI_IO_BASE, base >> 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);
+
+        base = s->r[PCI_REGION_TYPE_MEM].base;
+        limit = base + s->r[PCI_REGION_TYPE_MEM].size - 1;
+        pci_config_writew(bdf, PCI_MEMORY_BASE, base >> PCI_MEMORY_SHIFT);
+        pci_config_writew(bdf, PCI_MEMORY_LIMIT, limit >> PCI_MEMORY_SHIFT);
+
+        base = s->r[PCI_REGION_TYPE_PREFMEM].base;
+        limit = base + s->r[PCI_REGION_TYPE_PREFMEM].size - 1;
+        pci_config_writew(bdf, PCI_PREF_MEMORY_BASE, base >> 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, 0);
+        pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, 0);
+
+        pci_bios_map_device_in_bus(dev->secondary_bus);
+        return;
+    }
+
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        u32 addr;
+        if (dev->bars[i].addr == 0) {
+            continue;
+        }
+
+        addr = pci_bios_bus_get_addr(bus, pci_addr_to_type(dev->bars[i].addr),
+                                     dev->bars[i].size);
+        dprintf(1, "  bar %d, addr %x, size %x [%s]\n",
+                i, addr, dev->bars[i].size,
+                dev->bars[i].addr & PCI_BASE_ADDRESS_SPACE_IO ? "io" : "mem");
+        pci_set_io_region_addr(bdf, i, addr);
+
+        if (dev->bars[i].is64) {
+            i++;
+        }
+    }
+}
+
+static void pci_bios_check_device_in_bus(int bus)
+{
+    struct pci_device *pci;
+
+    dprintf(1, "PCI: check devices bus %d\n", bus);
+    foreachpci(pci) {
+        if (pci_bdf_to_bus(pci->bdf) != bus)
+            continue;
+        pci_bios_check_device(&busses[bus], pci);
+    }
+}
+
+static void pci_bios_map_device_in_bus(int bus)
+{
+    struct pci_device *pci;
+
+    foreachpci(pci) {
+        if (pci_bdf_to_bus(pci->bdf) != bus)
+            continue;
+        dprintf(1, "PCI: map device bus %d, bfd 0x%x\n", bus, pci->bdf);
+        pci_bios_map_device(&busses[bus], pci);
+    }
+}
+
+static void pci_bios_init_bus_bases(struct pci_bus *bus)
+{
+    u32 base, newbase, size;
+    int type, i;
+
+    for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
+        dprintf(1, "  type %s max %x sum %x base %x\n", region_type_name[type],
+                bus->r[type].max, bus->r[type].sum, bus->r[type].base);
+        base = bus->r[type].base;
+        for (i = ARRAY_SIZE(bus->r[type].count)-1; i >= 0; i--) {
+            size = pci_index_to_size(i, type);
+            if (!bus->r[type].count[i])
+                continue;
+            newbase = base + size * bus->r[type].count[i];
+            dprintf(1, "    size %8x: %d bar(s), %8x -> %8x\n",
+                    size, bus->r[type].count[i], base, newbase - 1);
+            bus->r[type].bases[i] = base;
+            base = newbase;
+        }
+    }
+}
+
+#define ROOT_BASE(top, sum, max) ALIGN_DOWN((top)-(sum),(max) ?: 1)
+
+static int pci_bios_init_root_regions(u32 start, u32 end)
+{
+    struct pci_bus *bus = &busses[0];
+
+    bus->r[PCI_REGION_TYPE_IO].base = 0xc000;
+
+    if (bus->r[PCI_REGION_TYPE_MEM].sum < bus->r[PCI_REGION_TYPE_PREFMEM].sum) {
+        bus->r[PCI_REGION_TYPE_MEM].base =
+            ROOT_BASE(end,
+                      bus->r[PCI_REGION_TYPE_MEM].sum,
+                      bus->r[PCI_REGION_TYPE_MEM].max);
+        bus->r[PCI_REGION_TYPE_PREFMEM].base =
+            ROOT_BASE(bus->r[PCI_REGION_TYPE_MEM].base,
+                      bus->r[PCI_REGION_TYPE_PREFMEM].sum,
+                      bus->r[PCI_REGION_TYPE_PREFMEM].max);
+        if (bus->r[PCI_REGION_TYPE_PREFMEM].base >= start) {
+            return 0;
+        }
+    } else {
+        bus->r[PCI_REGION_TYPE_PREFMEM].base =
+            ROOT_BASE(end,
+                      bus->r[PCI_REGION_TYPE_PREFMEM].sum,
+                      bus->r[PCI_REGION_TYPE_PREFMEM].max);
+        bus->r[PCI_REGION_TYPE_MEM].base =
+            ROOT_BASE(bus->r[PCI_REGION_TYPE_PREFMEM].base,
+                      bus->r[PCI_REGION_TYPE_MEM].sum,
+                      bus->r[PCI_REGION_TYPE_MEM].max);
+        if (bus->r[PCI_REGION_TYPE_MEM].base >= start) {
+            return 0;
+        }
+    }
+    return -1;
+}
+
+void
+pci_setup(void)
+{
+    if (CONFIG_COREBOOT || usingXen()) {
+        // PCI setup already done by coreboot or Xen - just do probe.
+        pci_probe_devices();
+        return;
+    }
+
+    dprintf(3, "pci setup\n");
+
+    u32 start = BUILD_PCIMEM_START;
+    u32 end   = BUILD_PCIMEM_END;
+
+    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();
+
+    dprintf(1, "=== PCI new allocation pass #1 ===\n");
+    busses = malloc_tmp(sizeof(*busses) * busses_count);
+    memset(busses, 0, sizeof(*busses) * busses_count);
+    pci_bios_check_device_in_bus(0 /* host bus */);
+    if (pci_bios_init_root_regions(start, end) != 0) {
+        panic("PCI: out of address space\n");
+    }
+
+    dprintf(1, "=== PCI new allocation pass #2 ===\n");
+    dprintf(1, "PCI: init bases bus 0 (primary)\n");
+    pci_bios_init_bus_bases(&busses[0]);
+    pci_bios_map_device_in_bus(0 /* host bus */);
+
+    pci_bios_init_device_in_bus(0 /* host bus */);
+
+    struct pci_device *pci;
+    foreachpci(pci) {
+        pci_init_device(pci_isa_bridge_tbl, pci, NULL);
+    }
+
+    free(busses);
+    busses_count = 0;
+}
diff --git a/bios/seabios/src/pic.c b/bios/seabios/src/pic.c
new file mode 100644 (file)
index 0000000..8992a8b
--- /dev/null
@@ -0,0 +1,52 @@
+// 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 "pic.h" // get_pic1_isr
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_*
+
+void
+set_pics(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)
+    outb(~PIC1_IRQ2, PORT_PIC1_DATA);
+    outb(~0, PORT_PIC2_DATA);
+}
+
+void
+pic_setup(void)
+{
+    dprintf(3, "init pic\n");
+    set_pics(0x08, 0x70);
+}
+
+// Handler for otherwise unused hardware irqs.
+void VISIBLE16
+handle_hwpic1(struct bregs *regs)
+{
+    dprintf(DEBUG_ISR_hwpic1, "handle_hwpic1 irq=%x\n", get_pic1_isr());
+    eoi_pic1();
+}
+
+void VISIBLE16
+handle_hwpic2(struct bregs *regs)
+{
+    dprintf(DEBUG_ISR_hwpic2, "handle_hwpic2 irq=%x\n", get_pic2_isr());
+    eoi_pic2();
+}
diff --git a/bios/seabios/src/pic.h b/bios/seabios/src/pic.h
new file mode 100644 (file)
index 0000000..c75af3e
--- /dev/null
@@ -0,0 +1,97 @@
+// 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 "ioport.h" // PORT_PIC*
+#include "biosvar.h" // SET_IVT
+
+// 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<<0)
+#define PIC2_IRQ12 (1<<4)
+#define PIC2_IRQ13 (1<<5)
+#define PIC2_IRQ14 (1<<6)
+
+static inline void
+eoi_pic1(void)
+{
+    // Send eoi (select OCW2 + eoi)
+    outb(0x20, PORT_PIC1_CMD);
+}
+
+static inline void
+eoi_pic2(void)
+{
+    // Send eoi (select OCW2 + eoi)
+    outb(0x20, PORT_PIC2_CMD);
+    eoi_pic1();
+}
+
+static inline void
+unmask_pic1(u8 irq)
+{
+    outb(inb(PORT_PIC1_DATA) & ~irq, PORT_PIC1_DATA);
+}
+
+static inline void
+unmask_pic2(u8 irq)
+{
+    outb(inb(PORT_PIC2_DATA) & ~irq, PORT_PIC2_DATA);
+}
+
+static inline void
+mask_pic1(u8 irq)
+{
+    outb(inb(PORT_PIC1_DATA) | irq, PORT_PIC1_DATA);
+}
+
+static inline void
+mask_pic2(u8 irq)
+{
+    outb(inb(PORT_PIC2_DATA) | irq, PORT_PIC2_DATA);
+}
+
+static inline u8
+get_pic1_isr(void)
+{
+    // 0x0b == select OCW1 + read ISR
+    outb(0x0b, PORT_PIC1_CMD);
+    return inb(PORT_PIC1_CMD);
+}
+
+static inline u8
+get_pic2_isr(void)
+{
+    // 0x0b == select OCW1 + read ISR
+    outb(0x0b, PORT_PIC2_CMD);
+    return inb(PORT_PIC2_CMD);
+}
+
+static inline void
+enable_hwirq(int hwirq, struct segoff_s func)
+{
+    int vector;
+    if (hwirq < 8) {
+        unmask_pic1(1 << hwirq);
+        vector = 0x08 + hwirq;
+    } else {
+        unmask_pic2(1 << (hwirq - 8));
+        vector = 0x70 + hwirq - 8;
+    }
+    SET_IVT(vector, func);
+}
+
+void set_pics(u8 irq0, u8 irq8);
+void pic_setup(void);
+
+#endif // pic.h
diff --git a/bios/seabios/src/pirtable.c b/bios/seabios/src/pirtable.c
new file mode 100644 (file)
index 0000000..4c3f1ff
--- /dev/null
@@ -0,0 +1,105 @@
+// PIR table generation (for emulators)
+//
+// 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 "pci.h" // struct pir_header
+#include "util.h" // checksum
+#include "biosvar.h" // SET_EBDA
+
+u16 PirOffset VAR16VISIBLE;
+
+struct pir_table {
+    struct pir_header pir;
+    struct pir_slot slots[6];
+} PACKED;
+
+extern struct pir_table PIR_TABLE;
+#if CONFIG_PIRTABLE && !CONFIG_COREBOOT
+struct pir_table PIR_TABLE __aligned(16) VAR16EXPORT = {
+    .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,
+        },
+    }
+};
+#endif // CONFIG_PIRTABLE && !CONFIG_COREBOOT
+
+void
+create_pirtable(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));
+    PirOffset = (u32)&PIR_TABLE.pir - BUILD_BIOS_ADDR;
+}
diff --git a/bios/seabios/src/pmm.c b/bios/seabios/src/pmm.c
new file mode 100644 (file)
index 0000000..82a0b1d
--- /dev/null
@@ -0,0 +1,603 @@
+// Post memory manager (PMM) calls
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // checksum
+#include "config.h" // BUILD_BIOS_ADDR
+#include "memmap.h" // struct e820entry
+#include "farptr.h" // GET_FARVAR
+#include "biosvar.h" // GET_BDA
+
+// Information on a reserved area.
+struct allocinfo_s {
+    struct allocinfo_s *next, **pprev;
+    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 allocinfo_s *info;
+};
+
+struct zone_s ZoneLow, ZoneHigh, ZoneFSeg, ZoneTmpLow, ZoneTmpHigh;
+
+static struct zone_s *Zones[] = {
+    &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;
+    for (info = zone->info; info; info = info->next) {
+        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.
+            struct allocinfo_s **pprev = info->pprev;
+            if (!fill)
+                fill = newallocend;
+            fill->next = info;
+            fill->pprev = pprev;
+            fill->data = newallocend;
+            fill->dataend = newallocend + size;
+            fill->allocend = allocend;
+
+            info->allocend = newallocend;
+            info->pprev = &fill->next;
+            *pprev = fill;
+            return newallocend;
+        }
+    }
+    return NULL;
+}
+
+// Release space allocated with allocSpace()
+static void
+freeSpace(struct allocinfo_s *info)
+{
+    struct allocinfo_s *next = info->next;
+    struct allocinfo_s **pprev = info->pprev;
+    *pprev = next;
+    if (next) {
+        if (next->allocend == info->data)
+            next->allocend = info->allocend;
+        next->pprev = pprev;
+    }
+}
+
+// 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 **pprev = &zone->info, *info;
+    for (;;) {
+        info = *pprev;
+        if (!info || info->data < start)
+            break;
+        pprev = &info->next;
+    }
+
+    // Add space using temporary allocation info.
+    struct allocdetail_s tempdetail;
+    tempdetail.datainfo.next = info;
+    tempdetail.datainfo.pprev = pprev;
+    tempdetail.datainfo.data = tempdetail.datainfo.dataend = start;
+    tempdetail.datainfo.allocend = end;
+    *pprev = &tempdetail.datainfo;
+    if (info)
+        info->pprev = &tempdetail.datainfo.next;
+
+    // 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) {
+            *tempdetail.datainfo.pprev = tempdetail.datainfo.next;
+            if (tempdetail.datainfo.next)
+                tempdetail.datainfo.next->pprev = tempdetail.datainfo.pprev;
+            warn_noalloc();
+            return;
+        }
+    }
+
+    // Replace temp alloc space with final alloc space
+    memcpy(&detail->datainfo, &tempdetail.datainfo, sizeof(detail->datainfo));
+    detail->handle = PMM_DEFAULT_HANDLE;
+
+    *tempdetail.datainfo.pprev = &detail->datainfo;
+    if (tempdetail.datainfo.next)
+        tempdetail.datainfo.next->pprev = &detail->datainfo.next;
+}
+
+// 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 zone_s *zone = Zones[i];
+        struct allocinfo_s *info;
+        for (info = zone->info; info; info = info->next)
+            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 = zone->info;
+    if (!info)
+        return NULL;
+    for (;;) {
+        struct allocinfo_s *next = info->next;
+        if (!next)
+            return info;
+        info = next;
+    }
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+void
+malloc_setup(void)
+{
+    ASSERT32FLAT();
+    dprintf(3, "malloc setup\n");
+
+    // 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 - CONFIG_MAX_HIGHTABLE, MALLOC_MIN_ALIGN);
+            if (newe <= e && newe >= s) {
+                highram = newe;
+                e = newe;
+            }
+        }
+        addSpace(&ZoneTmpHigh, (void*)s, (void*)e);
+    }
+
+    // Populate other regions
+    addSpace(&ZoneTmpLow, (void*)BUILD_STACK_ADDR, (void*)BUILD_EBDA_MINIMUM);
+    addSpace(&ZoneFSeg, BiosTableSpace, &BiosTableSpace[CONFIG_MAX_BIOSTABLE]);
+    addSpace(&ZoneLow, (void*)BUILD_LOWRAM_END, (void*)BUILD_LOWRAM_END);
+    if (highram) {
+        addSpace(&ZoneHigh, (void*)highram
+                 , (void*)highram + CONFIG_MAX_HIGHTABLE);
+        add_e820(highram, CONFIG_MAX_HIGHTABLE, E820_RESERVED);
+    }
+}
+
+// Update pointers after code relocation.
+void
+malloc_fixupreloc(void)
+{
+    ASSERT32FLAT();
+    if (!CONFIG_RELOCATE_INIT)
+        return;
+    dprintf(3, "malloc fixup reloc\n");
+
+    int i;
+    for (i=0; i<ARRAY_SIZE(Zones); i++) {
+        struct zone_s *zone = Zones[i];
+        zone->info->pprev = &zone->info;
+    }
+
+    // Add space free'd during relocation in f-segment to ZoneFSeg
+    extern u8 code32init_end[];
+    if ((u32)code32init_end > BUILD_BIOS_ADDR) {
+        memset((void*)BUILD_BIOS_ADDR, 0, (u32)code32init_end - BUILD_BIOS_ADDR);
+        addSpace(&ZoneFSeg, (void*)BUILD_BIOS_ADDR, code32init_end);
+    }
+}
+
+void
+malloc_finalize(void)
+{
+    ASSERT32FLAT();
+    dprintf(3, "malloc finalize\n");
+
+    // Reserve more low-mem if needed.
+    u32 endlow = GET_BDA(mem_size_kb)*1024;
+    add_e820(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED);
+
+    // Give back unused high ram.
+    struct allocinfo_s *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);
+    }
+}
+
+
+/****************************************************************
+ * 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 *info = findLast(&ZoneLow);
+    if (!info)
+        return;
+    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;
+    u16 ebda_seg = get_ebda_seg();
+    u32 ebda_pos = (u32)MAKE_FLATPTR(ebda_seg, 0);
+    u8 ebda_size = GET_EBDA2(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;
+
+    // Move ebda
+    int ret = relocate_ebda(newebda, ebda_pos, ebda_size);
+    if (ret)
+        return;
+
+    // Update zone
+    if (ebda_end == bottom) {
+        info->data = (void*)newbottom;
+        info->dataend = (void*)newbottom;
+    } else
+        addSpace(&ZoneLow, (void*)newbottom, (void*)ebda_end);
+}
+
+// Check if can expand the given zone to fulfill an allocation
+static void *
+allocExpandSpace(struct zone_s *zone, u32 size, u32 align
+                 , struct allocinfo_s *fill)
+{
+    void *data = allocSpace(zone, size, align, fill);
+    if (data || zone != &ZoneLow)
+        return data;
+
+    // Make sure to not move ebda while an optionrom is running.
+    if (unlikely(wait_preempt())) {
+        data = allocSpace(zone, size, align, fill);
+        if (data)
+            return data;
+    }
+
+    zonelow_expand(size, align);
+    return allocSpace(zone, size, align, fill);
+}
+
+
+/****************************************************************
+ * tracked memory allocations
+ ****************************************************************/
+
+// Allocate memory from the given zone and track it as a PMM allocation
+void * __malloc
+pmm_malloc(struct zone_s *zone, u32 handle, 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;
+    }
+
+    // Find and reserve space for main allocation
+    void *data = allocExpandSpace(zone, size, align, &detail->datainfo);
+    if (!data) {
+        freeSpace(&detail->detailinfo);
+        return NULL;
+    }
+
+    dprintf(8, "pmm_malloc zone=%p handle=%x size=%d align=%x"
+            " ret=%p (detail=%p)\n"
+            , zone, handle, size, align
+            , data, detail);
+    detail->handle = handle;
+
+    return data;
+}
+
+// Free a data block allocated with pmm_malloc
+int
+pmm_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, "pmm_free %p (detail=%p)\n", data, detail);
+    freeSpace(info);
+    freeSpace(&detail->detailinfo);
+    return 0;
+}
+
+// Find the amount of free space in a given zone.
+static u32
+pmm_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;
+    for (info = zone->info; info; info = info->next) {
+        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;
+}
+
+// Find the data block allocated with pmm_malloc with a given handle.
+static void *
+pmm_find(u32 handle)
+{
+    int i;
+    for (i=0; i<ARRAY_SIZE(Zones); i++) {
+        struct zone_s *zone = Zones[i];
+        struct allocinfo_s *info;
+        for (info = zone->info; info; info = info->next) {
+            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;
+}
+
+
+/****************************************************************
+ * pmm interface
+ ****************************************************************/
+
+struct pmmheader {
+    u32 signature;
+    u8 version;
+    u8 length;
+    u8 checksum;
+    u16 entry_offset;
+    u16 entry_seg;
+    u8 reserved[5];
+} PACKED;
+
+extern struct pmmheader PMMHEADER;
+
+#define PMM_SIGNATURE 0x4d4d5024 // $PMM
+
+#if CONFIG_PMM
+struct pmmheader PMMHEADER __aligned(16) VAR16EXPORT = {
+    .version = 0x01,
+    .length = sizeof(PMMHEADER),
+    .entry_seg = SEG_BIOS,
+};
+#endif
+
+#define PMM_FUNCTION_NOT_SUPPORTED 0xffffffff
+
+// 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 pmm_getspace(lowzone);
+        case 2:
+            return pmm_getspace(highzone);
+        case 3: {
+            u32 spacelow = pmm_getspace(lowzone);
+            u32 spacehigh = pmm_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;
+    }
+    switch (flags & 3) {
+    default:
+    case 0:
+        return 0;
+    case 1:
+        return (u32)pmm_malloc(lowzone, handle, size, align);
+    case 2:
+        return (u32)pmm_malloc(highzone, handle, size, align);
+    case 3: {
+        void *data = pmm_malloc(lowzone, handle, size, align);
+        if (data)
+            return (u32)data;
+        return (u32)pmm_malloc(highzone, handle, size, align);
+    }
+    }
+}
+
+// PMM - find
+static u32
+handle_pmm01(u16 *args)
+{
+    u32 handle = *(u32*)&args[1];
+    dprintf(3, "pmm01: handle=%x\n", handle);
+    if (handle == PMM_DEFAULT_HANDLE)
+        return 0;
+    return (u32)pmm_find(handle);
+}
+
+// PMM - deallocate
+static u32
+handle_pmm02(u16 *args)
+{
+    u32 buffer = *(u32*)&args[1];
+    dprintf(3, "pmm02: buffer=%x\n", buffer);
+    int ret = pmm_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);
+
+    int oldpreempt;
+    if (CONFIG_THREAD_OPTIONROMS) {
+        // Not a preemption event - don't wait in wait_preempt()
+        oldpreempt = CanPreempt;
+        CanPreempt = 0;
+    }
+
+    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;
+    }
+
+    if (CONFIG_THREAD_OPTIONROMS)
+        CanPreempt = oldpreempt;
+
+    return ret;
+}
+
+// romlayout.S
+extern void entry_pmm(void);
+
+void
+pmm_setup(void)
+{
+    if (! CONFIG_PMM)
+        return;
+
+    dprintf(3, "init PMM\n");
+
+    PMMHEADER.signature = PMM_SIGNATURE;
+    PMMHEADER.entry_offset = (u32)entry_pmm - BUILD_BIOS_ADDR;
+    PMMHEADER.checksum -= checksum(&PMMHEADER, sizeof(PMMHEADER));
+}
+
+void
+pmm_finalize(void)
+{
+    if (! CONFIG_PMM)
+        return;
+
+    dprintf(3, "finalize PMM\n");
+
+    PMMHEADER.signature = 0;
+    PMMHEADER.entry_offset = 0;
+}
diff --git a/bios/seabios/src/pnpbios.c b/bios/seabios/src/pnpbios.c
new file mode 100644 (file)
index 0000000..b1bebc9
--- /dev/null
@@ -0,0 +1,103 @@
+// 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 "util.h" // checksum
+#include "config.h" // BUILD_BIOS_ADDR
+#include "farptr.h" // SET_FARVAR
+
+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;
+
+extern struct pnpheader PNPHEADER;
+extern char pnp_string[];
+
+#if CONFIG_PNPBIOS
+struct pnpheader PNPHEADER __aligned(16) VAR16EXPORT = {
+    .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) VAR16VISIBLE = " $PnP";
+#endif
+
+#define FUNCTION_NOT_SUPPORTED 0x82
+
+// 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_setup(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/bios/seabios/src/post.c b/bios/seabios/src/post.c
new file mode 100644 (file)
index 0000000..b4ad1fa
--- /dev/null
@@ -0,0 +1,377 @@
+// 32bit code to Power On Self Test (POST) a machine.
+//
+// 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 "ioport.h" // PORT_*
+#include "config.h" // CONFIG_*
+#include "cmos.h" // CMOS_*
+#include "util.h" // memset
+#include "biosvar.h" // struct bios_data_area_s
+#include "disk.h" // floppy_drive_setup
+#include "ata.h" // ata_setup
+#include "ahci.h" // ahci_setup
+#include "memmap.h" // add_e820
+#include "pic.h" // pic_setup
+#include "pci.h" // create_pirtable
+#include "acpi.h" // acpi_bios_init
+#include "bregs.h" // struct bregs
+#include "mptable.h" // mptable_init
+#include "boot.h" // IPL
+#include "usb.h" // usb_setup
+#include "smbios.h" // smbios_init
+#include "paravirt.h" // qemu_cfg_port_probe
+#include "xen.h" // xen_probe_hvm_info
+#include "ps2port.h" // ps2port_setup
+#include "virtio-blk.h" // virtio_blk_setup
+
+
+/****************************************************************
+ * BIOS init
+ ****************************************************************/
+
+static void
+init_ivt(void)
+{
+    dprintf(3, "init ivt\n");
+
+    // Initialize all vectors to the default handler.
+    int i;
+    for (i=0; i<256; i++)
+        SET_IVT(i, FUNC16(entry_iret_official));
+
+    // Initialize all hw vectors to a default hw handler.
+    for (i=0x08; i<=0x0f; i++)
+        SET_IVT(i, FUNC16(entry_hwpic1));
+    for (i=0x70; i<=0x77; 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));
+    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));
+    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));
+
+    SET_IVT(0x1E, SEGOFF(SEG_BIOS, (u32)&diskette_param_table2 - BUILD_BIOS_ADDR));
+}
+
+static void
+init_bda(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;
+    SET_BDA(mem_size_kb, BUILD_LOWRAM_END/1024 - esize);
+    u16 ebda_seg = EBDA_SEGMENT_START;
+    SET_BDA(ebda_seg, ebda_seg);
+
+    // Init ebda
+    struct extended_bios_data_area_s *ebda = get_ebda_ptr();
+    memset(ebda, 0, sizeof(*ebda));
+    ebda->size = esize;
+
+    add_e820((u32)MAKE_FLATPTR(ebda_seg, 0), GET_EBDA2(ebda_seg, size) * 1024
+             , E820_RESERVED);
+}
+
+static void
+ram_probe(void)
+{
+    dprintf(3, "Find memory size\n");
+    if (CONFIG_COREBOOT) {
+        coreboot_setup();
+    } else if (usingXen()) {
+       xen_setup();
+    } else {
+        // On emulators, get memory size from nvram.
+        u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16)
+                  | (inb_cmos(CMOS_MEM_EXTMEM2_HIGH) << 24));
+        if (rs)
+            rs += 16 * 1024 * 1024;
+        else
+            rs = (((inb_cmos(CMOS_MEM_EXTMEM_LOW) << 10)
+                   | (inb_cmos(CMOS_MEM_EXTMEM_HIGH) << 18))
+                  + 1 * 1024 * 1024);
+        RamSize = rs;
+        add_e820(0, rs, E820_RAM);
+
+        // Check for memory over 4Gig
+        u64 high = ((inb_cmos(CMOS_MEM_HIGHMEM_LOW) << 16)
+                    | ((u32)inb_cmos(CMOS_MEM_HIGHMEM_MID) << 24)
+                    | ((u64)inb_cmos(CMOS_MEM_HIGHMEM_HIGH) << 32));
+        RamSizeOver4G = high;
+        add_e820(0x100000000ull, high, E820_RAM);
+
+        /* reserve 256KB BIOS area at the end of 4 GB */
+        add_e820(0xfffc0000, 256*1024, E820_RESERVED);
+    }
+
+    // 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);
+
+    u32 count = qemu_cfg_e820_entries();
+    if (count) {
+        struct e820_reservation entry;
+        int i;
+
+        for (i = 0; i < count; i++) {
+            qemu_cfg_e820_load_next(&entry);
+            add_e820(entry.address, entry.length, entry.type);
+        }
+    } else if (kvm_para_available()) {
+        // 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);
+    }
+
+    dprintf(1, "Ram Size=0x%08x (0x%08x%08x high)\n"
+            , RamSize, (u32)(RamSizeOver4G >> 32), (u32)RamSizeOver4G);
+}
+
+static void
+init_bios_tables(void)
+{
+    if (CONFIG_COREBOOT) {
+        coreboot_copy_biostable();
+        return;
+    }
+    if (usingXen()) {
+       xen_copy_biostables();
+       return;
+    }
+
+    create_pirtable();
+
+    mptable_init();
+
+    smbios_init();
+
+    acpi_bios_init();
+}
+
+// Initialize hardware devices
+static void
+init_hw(void)
+{
+    usb_setup();
+    ps2port_setup();
+    lpt_setup();
+    serial_setup();
+
+    floppy_setup();
+    ata_setup();
+    ahci_setup();
+    cbfs_payload_setup();
+    ramdisk_setup();
+    virtio_blk_setup();
+}
+
+// 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)
+{
+    // Running at new code address - do code relocation fixups
+    malloc_fixupreloc();
+
+    // Setup ivt/bda/ebda
+    init_ivt();
+    init_bda();
+
+    // Init base pc hardware.
+    pic_setup();
+    timer_setup();
+    mathcp_setup();
+
+    // Initialize mtrr
+    mtrr_setup();
+
+    // Initialize pci
+    pci_setup();
+    smm_init();
+
+    // Setup Xen hypercalls
+    xen_init_hypercalls();
+
+    // Initialize internal tables
+    boot_setup();
+
+    // Start hardware initialization (if optionrom threading)
+    if (CONFIG_THREADS && CONFIG_THREAD_OPTIONROMS)
+        init_hw();
+
+    // Find and initialize other cpus
+    smp_probe();
+
+    // Setup interfaces that option roms may need
+    bios32_setup();
+    pmm_setup();
+    pnp_setup();
+    kbd_setup();
+    mouse_setup();
+    init_bios_tables();
+
+    // Run vga option rom
+    vga_setup();
+
+    // Do hardware initialization (if running synchronously)
+    if (!CONFIG_THREADS || !CONFIG_THREAD_OPTIONROMS) {
+        init_hw();
+        wait_threads();
+    }
+
+    // Run option roms
+    optionrom_setup();
+
+    // Run BCVs and show optional boot menu
+    boot_prep();
+
+    // Finalize data structures before boot
+    cdemu_setup();
+    pmm_finalize();
+    malloc_finalize();
+    memmap_finalize();
+
+    // Setup bios checksum.
+    BiosChecksum -= checksum((u8*)BUILD_BIOS_ADDR, BUILD_BIOS_SIZE);
+
+    // 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 maininit() at new address.
+static void
+reloc_init(void)
+{
+    if (!CONFIG_RELOCATE_INIT) {
+        maininit();
+        return;
+    }
+    // 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 align = (u32)&_reloc_min_align;
+    void *dest = memalign_tmp(align, initsize);
+    if (!dest)
+        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, dest, initsize);
+    s32 delta = dest - (void*)code32init_start;
+    memcpy(dest, code32init_start, initsize);
+    updateRelocs(dest, _reloc_abs_start, _reloc_abs_end, delta);
+    updateRelocs(dest, _reloc_rel_start, _reloc_rel_end, -delta);
+    updateRelocs(code32flat_start, _reloc_init_start, _reloc_init_end, delta);
+
+    // Call maininit() in relocated code.
+    void (*func)(void) = (void*)maininit + delta;
+    barrier();
+    func();
+}
+
+// Setup for code relocation and then call reloc_init
+void VISIBLE32INIT
+dopost(void)
+{
+    HaveRunPost = 1;
+
+    // Detect ram and setup internal malloc.
+    qemu_cfg_port_probe();
+    ram_probe();
+    malloc_setup();
+
+    // Relocate initialization code and call maininit().
+    reloc_init();
+}
+
+// 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)
+{
+    debug_serial_setup();
+    dprintf(1, "Start bios (version %s)\n", VERSION);
+
+    // Enable CPU caching
+    setcr0(getcr0() & ~(CR0_CD|CR0_NW));
+
+    // Clear CMOS reboot flag.
+    outb_cmos(0, CMOS_RESET_CODE);
+
+    // Make sure legacy DMA isn't running.
+    init_dma();
+
+    // Check if we are running under Xen.
+    xen_probe();
+
+    // Allow writes to modify bios area (0xf0000)
+    make_bios_writable();
+
+    // Now that memory is read/writable - start post process.
+    dopost();
+}
diff --git a/bios/seabios/src/ps2port.c b/bios/seabios/src/ps2port.c
new file mode 100644 (file)
index 0000000..58335af
--- /dev/null
@@ -0,0 +1,494 @@
+// 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 "ioport.h" // inb
+#include "util.h" // dprintf
+#include "paravirt.h" // romfile_loadint
+#include "biosvar.h" // GET_EBDA
+#include "ps2port.h" // ps2_kbd_command
+#include "pic.h" // eoi_pic1
+
+
+/****************************************************************
+ * 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)
+{
+    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)
+{
+    u64 end = calc_future_tsc(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 (check_tsc(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;
+}
+
+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_EBDA(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)
+{
+    return ps2_command(0, command, param);
+}
+
+int
+ps2_mouse_command(int command, u8 *param)
+{
+    // Update ps2ctr for mouse enable/disable.
+    if (command == PSMOUSE_CMD_ENABLE || command == PSMOUSE_CMD_DISABLE) {
+        u16 ebda_seg = get_ebda_seg();
+        u8 ps2ctr = GET_EBDA2(ebda_seg, ps2ctr);
+        if (command == PSMOUSE_CMD_ENABLE)
+            ps2ctr = (ps2ctr | I8042_CTR_AUXINT) & ~I8042_CTR_AUXDIS;
+        else
+            ps2ctr = (ps2ctr | I8042_CTR_AUXDIS) & ~I8042_CTR_AUXINT;
+        SET_EBDA2(ebda_seg, 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_EBDA(ps2ctr) & I8042_CTR_AUXINT))
+        // Interrupts not enabled.
+        goto done;
+
+    process_mouse(v);
+
+done:
+    eoi_pic2();
+}
+
+// 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_EBDA(ps2ctr) & I8042_CTR_KBDINT))
+        // Interrupts not enabled.
+        goto done;
+
+    process_key(v);
+
+done:
+    eoi_pic1();
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static void
+keyboard_init(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_EBDA(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);
+    u64 end = calc_future_tsc(spinupdelay);
+    for (;;) {
+        ret = ps2_kbd_command(ATKBD_CMD_RESET_BAT, param);
+        if (!ret)
+            break;
+        if (check_tsc(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_EBDA(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(keyboard_init, NULL);
+}
diff --git a/bios/seabios/src/ps2port.h b/bios/seabios/src/ps2port.h
new file mode 100644 (file)
index 0000000..dcae391
--- /dev/null
@@ -0,0 +1,63 @@
+// Basic ps2 port (keyboard/mouse) command handling.
+#ifndef __PS2PORT_H
+#define __PS2PORT_H
+
+#include "types.h" // u8
+
+// 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
+
+// functions
+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/bios/seabios/src/ramdisk.c b/bios/seabios/src/ramdisk.c
new file mode 100644 (file)
index 0000000..bae30e2
--- /dev/null
@@ -0,0 +1,105 @@
+// 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 "disk.h" // process_ramdisk_op
+#include "util.h" // dprintf
+#include "memmap.h" // add_e820
+#include "biosvar.h" // GET_GLOBAL
+#include "bregs.h" // struct bregs
+#include "boot.h" // boot_add_floppy
+
+void
+ramdisk_setup(void)
+{
+    if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !CONFIG_FLASH_FLOPPY)
+        return;
+
+    // Find image.
+    struct cbfs_file *file = cbfs_findprefix("floppyimg/", NULL);
+    if (!file)
+        return;
+    const char *filename = cbfs_filename(file);
+    u32 size = cbfs_datasize(file);
+    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.
+    cbfs_copyfile(file, pos, size);
+
+    // Setup driver.
+    struct drive_s *drive_g = init_floppy((u32)pos, ftype);
+    if (!drive_g)
+        return;
+    drive_g->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_g, desc, bootprio_find_named_rom(filename, 0));
+}
+
+static int
+ramdisk_copy(struct disk_op_s *op, int iswrite)
+{
+    u32 offset = GET_GLOBAL(op->drive_g->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_COREBOOT || !CONFIG_COREBOOT_FLASH || !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:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
diff --git a/bios/seabios/src/resume.c b/bios/seabios/src/resume.c
new file mode 100644 (file)
index 0000000..4390fb5
--- /dev/null
@@ -0,0 +1,160 @@
+// 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 "util.h" // dprintf
+#include "ioport.h" // outb
+#include "pic.h" // eoi_pic2
+#include "biosvar.h" // struct bios_data_area_s
+#include "bregs.h" // struct bregs
+#include "acpi.h" // find_resume_vector
+#include "ps2port.h" // i8042_reboot
+#include "pci.h" // pci_reboot
+#include "cmos.h" // inb_cmos
+
+// Indicator if POST phase has been run.
+int HaveRunPost VAR16VISIBLE;
+
+// Reset DMA controller
+void
+init_dma(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);
+}
+
+// Handler for post calls that look like a resume.
+void VISIBLE16
+handle_resume(void)
+{
+    debug_serial_setup();
+    int status = inb_cmos(CMOS_RESET_CODE);
+    outb_cmos(0, CMOS_RESET_CODE);
+    dprintf(1, "In resume (status=%d)\n", status);
+
+    init_dma();
+
+    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
+        eoi_pic2();
+        // 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;
+    }
+
+    smm_init();
+
+    s3_resume_vga_init();
+
+    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);
+    call16big(&br);
+}
+
+// Attempt to invoke a hard-reboot.
+static void
+tryReboot(void)
+{
+    dprintf(1, "Attempting a hard reboot\n");
+
+    // Setup for reset on qemu.
+    if (! CONFIG_COREBOOT) {
+        qemu_prep_reset();
+        if (HaveRunPost)
+            apm_shutdown();
+    }
+
+    // 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/bios/seabios/src/romlayout.S b/bios/seabios/src/romlayout.S
new file mode 100644 (file)
index 0000000..5983a4a
--- /dev/null
@@ -0,0 +1,554 @@
+// Rom layout and bios assembler to C interface.
+//
+// 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 of 16bit C code
+ ****************************************************************/
+
+        .code16gcc
+#include "ccode.16.s"
+
+#include "config.h" // CONFIG_*
+#include "ioport.h" // PORT_A20
+#include "bregs.h" // CR0_*
+#include "cmos.h" // CMOS_RESET_CODE
+#include "asm-offsets.h" // BREGS_*
+#include "entryfuncs.S" // ENTRY_*
+
+
+/****************************************************************
+ * 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:
+        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
+        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 + 1f)
+
+        .code32
+1:
+        // init data segments
+        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
+
+// 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
+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
+
+        .code16gcc
+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
+
+// Call a 16bit function from 16bit mode with a specified cpu register state
+// %eax = address of struct bregs
+// Clobbers: %e[bcd]x, %e[ds]i, flags
+        DECLFUNC __call16
+__call16:
+        // Save %eax, %ebp
+        pushl %ebp
+        pushl %eax
+
+        // Setup for iretw call
+        pushw %cs
+        pushw $1f               // return point
+        pushw BREGS_flags(%eax) // flags
+        pushl BREGS_code(%eax)  // CS:IP
+
+        // Load calling registers.
+        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
+        movw BREGS_ds(%eax), %ds
+        movl %ss:BREGS_eax(%eax), %eax
+
+        // Invoke call
+        iretw                   // XXX - just do a lcalll
+1:
+        // Store flags, eax, ecx
+        pushfw
+        pushl %eax
+        movl 0x06(%esp), %eax
+        movl %ecx, %ss:BREGS_ecx(%eax)
+        movw %ds, %ss:BREGS_ds(%eax)
+        movw %ss, %cx
+        movw %cx, %ds           // Restore %ds == %ss
+        popl %ecx
+        movl %ecx, BREGS_eax(%eax)
+        popw %cx
+        movw %cx, BREGS_flags(%eax)
+
+        // Store remaining registers
+        movw %es, BREGS_es(%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)
+
+        // Remove %eax, restore %ebp
+        popl %eax
+        popl %ebp
+
+        retl
+
+// Call a 16bit function from 32bit mode.
+// %eax = address of struct bregs
+// Clobbers: %e[bcd]x, %e[ds]i, flags, segment registers, idt/gdt
+        DECLFUNC __call16_from32
+        .global __call16big_from32
+        .code32
+__call16_from32:
+        movl $1f, %edx
+        jmp transition16
+__call16big_from32:
+        movl $1f, %edx
+        jmp transition16big
+
+        // Make call.
+        .code16gcc
+1:      calll __call16
+        // Return via transition32
+        movl $(2f + BUILD_BIOS_ADDR), %edx
+        jmp transition32
+        .code32
+2:      retl
+
+        .code16gcc
+// IRQ trampolines
+        .macro IRQ_TRAMPOLINE num
+        DECLFUNC irq_trampoline_0x\num
+        irq_trampoline_0x\num :
+        int $0x\num
+        lretw
+        .endm
+
+        IRQ_TRAMPOLINE 10
+        IRQ_TRAMPOLINE 13
+        IRQ_TRAMPOLINE 15
+        IRQ_TRAMPOLINE 16
+        IRQ_TRAMPOLINE 18
+        IRQ_TRAMPOLINE 19
+
+
+/****************************************************************
+ * Misc. entry points.
+ ****************************************************************/
+
+// Resume (and reboot) entry point - called from entry_post
+        DECLFUNC entry_resume
+entry_resume:
+        // Disable interrupts
+        cli
+        cld
+        // Use a stack in EBDA
+        movw $SEG_BDA, %ax
+        movw %ax, %ds
+        movw BDA_ebda_seg, %ax
+        movw %ax, %ds
+        movw %ax, %ss
+        movl $EBDA_OFFSET_TOP_STACK, %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
+        pushl %eax
+        pushl %ecx
+        pushl %edx
+        pushw %es
+        pushw %ds
+        movw %ss, %cx           // Move %ss to %ds
+        movw %cx, %ds
+        movl $_cfunc32flat_handle_pmm, %eax // Setup: call32(handle_pmm, args, -1)
+        leal 28(%esp), %edx     // %edx points to start of args
+        movl $-1, %ecx
+        calll call32
+        movw %ax, 12(%esp)      // Modify %ax:%dx to return %eax
+        shrl $16, %eax
+        movw %ax, 4(%esp)
+        popw %ds                // Restore saved registers
+        popw %es
+        popl %edx
+        popl %ecx
+        popl %eax
+        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
+        pushl %eax
+        pushl %ecx
+        pushl %edx
+        pushw %es
+        pushw %ds
+        movw %ss, %cx           // Move %ss to %ds
+        movw %cx, %ds
+        leal 28(%esp), %eax     // %eax points to start of u16 args
+        calll handle_pnp
+        movw %ax, 12(%esp)      // Modify %eax to return %ax
+        popw %ds
+        popw %es
+        popl %edx
+        popl %ecx
+        popl %eax
+        popfl
+        popl %esp
+        lretw
+
+// APM entry points
+        DECLFUNC entry_apm16
+entry_apm16:
+        pushfw          // save flags
+        pushl %eax      // dummy
+        ENTRY_ARG handle_apm16
+        addw $4, %sp    // pop dummy
+        popfw           // restore flags
+        lretw
+
+        .code32
+        DECLFUNC entry_apm32
+entry_apm32:
+        pushfl
+        pushl %gs
+        pushl %cs               // Move second descriptor after %cs to %gs
+        addl $16, (%esp)
+        popl %gs
+        ENTRY_ARG_ESP _cfunc32seg_handle_apm32
+        popl %gs
+        popfl
+        lretl
+
+// PCI-BIOS 32bit entry point
+        DECLFUNC entry_pcibios32
+entry_pcibios32:
+        pushfl
+        pushl %gs               // Backup %gs and set %gs=%ds
+        pushl %ds
+        popl %gs
+        ENTRY_ARG_ESP _cfunc32seg_handle_pcibios32
+        popl %gs
+        popfl
+        lretl
+
+// BIOS32 support
+        EXPORTFUNC entry_bios32
+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
+
+// 32bit elf entry point
+        EXPORTFUNC entry_elf
+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
+
+        .code16gcc
+
+
+/****************************************************************
+ * Interrupt entry points
+ ****************************************************************/
+
+        // Main entry point for interrupts without args
+        DECLFUNC irqentry
+irqentry:
+        ENTRY_ST
+        iretw
+
+        // Main entry point for interrupts with args
+        DECLFUNC irqentryarg
+irqentryarg:
+        ENTRY_ARG_ST
+        iretw
+
+        // Define an entry point for an interrupt (no args passed).
+        .macro IRQ_ENTRY num
+        .global entry_\num
+        entry_\num :
+        pushl $ handle_\num
+        jmp irqentry
+        .endm
+
+        .macro DECL_IRQ_ENTRY num
+        DECLFUNC entry_\num
+        IRQ_ENTRY \num
+        .endm
+
+        // Define an entry point for an interrupt (can read/modify args).
+        .macro IRQ_ENTRY_ARG num
+        .global entry_\num
+        entry_\num :
+        pushl $ handle_\num
+        jmp irqentryarg
+        .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 disk.c
+
+        ORG 0xe6f2
+        .global entry_19_official
+entry_19_official:
+        jmp entry_19
+
+        // 0xe6f5 - BIOS_CONFIG_TABLE in misc.c
+
+        // 0xe729 - BaudTable in serial.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 floppy.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
+        IRQ_ENTRY_ARG 15
+
+        // 0xfa6e - vgafont8 in font.c
+
+        ORG 0xfe6e
+        IRQ_ENTRY_ARG 1a
+
+        ORG 0xfea5
+        IRQ_ENTRY 08
+
+        // 0xfef3 - InitVectors in misc.c
+
+        // 0xff00 - BiosCopyright 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/bios/seabios/src/serial.c b/bios/seabios/src/serial.c
new file mode 100644 (file)
index 0000000..21b4bd0
--- /dev/null
@@ -0,0 +1,315 @@
+// 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 "util.h" // debug_enter
+#include "bregs.h" // struct bregs
+
+
+/****************************************************************
+ * COM ports
+ ****************************************************************/
+
+static u16
+detect_serial(u16 port, u8 timeout, u8 count)
+{
+    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
+    u16 eqb = GET_BDA(equipment_list_flags);
+    SET_BDA(equipment_list_flags, (eqb & 0xf1ff) | (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 = calc_future_timer_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 (check_timer(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 = calc_future_timer_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 (check_timer(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;
+    }
+}
+
+// XXX - Baud Rate Generator Table
+u8 BaudTable[16] VAR16FIXED(0xe729);
+
+
+/****************************************************************
+ * 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
+    u16 eqb = GET_BDA(equipment_list_flags);
+    SET_BDA(equipment_list_flags, (eqb & 0x3fff) | (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 = calc_future_timer_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 (check_timer(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/bios/seabios/src/shadow.c b/bios/seabios/src/shadow.c
new file mode 100644 (file)
index 0000000..c0c8cc2
--- /dev/null
@@ -0,0 +1,158 @@
+// 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 "util.h" // memcpy
+#include "pci.h" // pci_config_writeb
+#include "config.h" // CONFIG_*
+#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "xen.h" // usingXen
+
+// On the emulators, the bios at 0xf0000 is also at 0xffff0000
+#define BIOS_SRC_OFFSET 0xfff00000
+
+#define I440FX_PAM0     0x59
+
+// 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
+    int i;
+    for (i=0; i<6; i++) {
+        u32 mem = BUILD_ROM_START + i * 32*1024;
+        u32 pam = pam0 + 1 + i;
+        if (RomEnd <= mem + 16*1024) {
+            if (RomEnd > mem)
+                pci_config_writeb(bdf, pam, 0x31);
+            break;
+        }
+        pci_config_writeb(bdf, pam, 0x11);
+    }
+
+    // Write protect 0xf0000-0x100000
+    pci_config_writeb(bdf, pam0, 0x10);
+}
+
+static void i440fx_bios_make_readonly(struct pci_device *pci, void *arg)
+{
+    make_bios_readonly_intel(pci->bdf, I440FX_PAM0);
+}
+
+static const struct pci_device_id dram_controller_make_readonly_tbl[] = {
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
+               i440fx_bios_make_readonly),
+    PCI_DEVICE_END
+};
+
+// Make the 0xc0000-0x100000 area read/writable.
+void
+make_bios_writable(void)
+{
+    if (CONFIG_COREBOOT || usingXen())
+        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);
+            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_COREBOOT || usingXen())
+        return;
+
+    dprintf(3, "locking shadow ram\n");
+    struct pci_device *pci = pci_find_init_device(
+        dram_controller_make_readonly_tbl, NULL);
+    if (!pci)
+        dprintf(1, "Unable to lock ram - bridge not found\n");
+}
+
+void
+qemu_prep_reset(void)
+{
+    if (CONFIG_COREBOOT)
+        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/bios/seabios/src/smbios.c b/bios/seabios/src/smbios.c
new file mode 100644 (file)
index 0000000..fe1e183
--- /dev/null
@@ -0,0 +1,524 @@
+// smbios table generation (on emulators)
+//
+// 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 "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "paravirt.h" // qemu_cfg_smbios_load_field
+#include "smbios.h" // struct smbios_entry_point
+
+struct smbios_entry_point *SMBiosAddr;
+
+static void
+smbios_entry_point_init(u16 max_structure_size,
+                        u16 structure_table_length,
+                        void *structure_table_address,
+                        u16 number_of_structures)
+{
+    struct smbios_entry_point *ep = malloc_fseg(sizeof(*ep));
+    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 (!ep || !finaltable) {
+        warn_noalloc();
+        free(ep);
+        free(finaltable);
+        return;
+    }
+    memcpy(finaltable, structure_table_address, structure_table_length);
+
+    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;
+    ep->entry_point_revision = 0;
+    memset(ep->formatted_area, 0, 5);
+    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);
+
+    SMBiosAddr = ep;
+    dprintf(1, "SMBIOS ptr=%p table=%p size=%d\n"
+            , ep, finaltable, structure_table_length);
+}
+
+#define load_str_field_with_default(type, field, def)                   \
+    do {                                                                \
+        size = qemu_cfg_smbios_load_field(type,                         \
+                                 offsetof(struct smbios_type_##type,    \
+                                          field), end);                 \
+        if (size > 0) {                                                 \
+            end += size;                                                \
+        } 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 = qemu_cfg_smbios_load_field(type,                         \
+                                 offsetof(struct smbios_type_##type,    \
+                                          field), end);                 \
+        if (size > 0) {                                                 \
+            end += size;                                                \
+            p->field = ++str_index;                                     \
+        } else {                                                        \
+            p->field = 0;                                               \
+        }                                                               \
+    } while (0)
+
+#define set_field_with_default(type, field, def)                        \
+    do {                                                                \
+        if (!qemu_cfg_smbios_load_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/2007"
+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, CONFIG_APPNAME);
+    load_str_field_with_default(0, bios_version_str, CONFIG_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 (!qemu_cfg_smbios_load_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 (!qemu_cfg_smbios_load_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, CONFIG_APPNAME);
+    load_str_field_with_default(1, product_name_str, CONFIG_APPNAME);
+    load_str_field_or_skip(1, version_str);
+    load_str_field_or_skip(1, serial_number_str);
+
+    if (!qemu_cfg_smbios_load_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, CONFIG_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 = qemu_cfg_smbios_load_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, CONFIG_APPNAME);
+
+    if (!qemu_cfg_smbios_load_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 = qemu_cfg_smbios_load_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_init(void)
+{
+    if (! CONFIG_SMBIOS)
+        return;
+
+    dprintf(3, "init SMBIOS tables\n");
+
+    char *start = malloc_tmphigh(TEMPSMBIOSSIZE);
+    if (! start) {
+        warn_noalloc();
+        return;
+    }
+
+    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 (!qemu_cfg_smbios_load_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++)
+        qemu_cfg_smbios_load_external(i, &p, &nr_structs, &max_struct_size,
+                                      end);
+    add_struct(127, p);
+
+#undef add_struct
+
+    smbios_entry_point_init(max_struct_size, p - start, start, nr_structs);
+    free(start);
+}
diff --git a/bios/seabios/src/smbios.h b/bios/seabios/src/smbios.h
new file mode 100644 (file)
index 0000000..9d54e80
--- /dev/null
@@ -0,0 +1,168 @@
+#ifndef __SMBIOS_H
+#define __SMBIOS_H
+
+// smbios.c
+void smbios_init(void);
+
+/* 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;
+
+extern struct smbios_entry_point *SMBiosAddr;
+
+/* 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/bios/seabios/src/smm.c b/bios/seabios/src/smm.c
new file mode 100644 (file)
index 0000000..72e5e88
--- /dev/null
@@ -0,0 +1,157 @@
+// System Management Mode support (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 "pci.h" // pci_config_writel
+#include "util.h" // wbinvd
+#include "config.h" // CONFIG_*
+#include "ioport.h" // outb
+#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
+
+ASM32FLAT(
+    ".global smm_relocation_start\n"
+    ".global smm_relocation_end\n"
+    ".global smm_code_start\n"
+    ".global smm_code_end\n"
+    "  .code16\n"
+
+    /* code to relocate SMBASE to 0xa0000 */
+    "smm_relocation_start:\n"
+    "  mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7efc, %ebx\n"
+    "  addr32 mov (%ebx), %al\n"  /* revision ID to see if x86_64 or x86 */
+    "  cmp $0x64, %al\n"
+    "  je 1f\n"
+    "  mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7ef8, %ebx\n"
+    "  jmp 2f\n"
+    "1:\n"
+    "  mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7f00, %ebx\n"
+    "2:\n"
+    "  movl $" __stringify(BUILD_SMM_ADDR) " - 0x8000, %eax\n"
+    "  addr32 movl %eax, (%ebx)\n"
+    /* indicate to the BIOS that the SMM code was executed */
+    "  mov $0x00, %al\n"
+    "  movw $" __stringify(PORT_SMI_STATUS) ", %dx\n"
+    "  outb %al, %dx\n"
+    "  rsm\n"
+    "smm_relocation_end:\n"
+
+    /* minimal SMM code to enable or disable ACPI */
+    "smm_code_start:\n"
+    "  movw $" __stringify(PORT_SMI_CMD) ", %dx\n"
+    "  inb %dx, %al\n"
+    "  cmp $0xf0, %al\n"
+    "  jne 1f\n"
+
+    /* ACPI disable */
+    "  mov $" __stringify(PORT_ACPI_PM_BASE) " + 0x04, %dx\n" /* PMCNTRL */
+    "  inw %dx, %ax\n"
+    "  andw $~1, %ax\n"
+    "  outw %ax, %dx\n"
+
+    "  jmp 2f\n"
+
+    "1:\n"
+    "  cmp $0xf1, %al\n"
+    "  jne 2f\n"
+
+    /* ACPI enable */
+    "  mov $" __stringify(PORT_ACPI_PM_BASE) " + 0x04, %dx\n" /* PMCNTRL */
+    "  inw %dx, %ax\n"
+    "  orw $1, %ax\n"
+    "  outw %ax, %dx\n"
+
+    "2:\n"
+    "  rsm\n"
+    "smm_code_end:\n"
+    "  .code32\n"
+    );
+
+extern u8 smm_relocation_start, smm_relocation_end;
+extern u8 smm_code_start, smm_code_end;
+
+static void
+smm_save_and_copy(void)
+{
+    /* save original memory content */
+    memcpy((void *)BUILD_SMM_ADDR, (void *)BUILD_SMM_INIT_ADDR, BUILD_SMM_SIZE);
+
+    /* copy the SMM relocation code */
+    memcpy((void *)BUILD_SMM_INIT_ADDR, &smm_relocation_start,
+           &smm_relocation_end - &smm_relocation_start);
+}
+
+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 */
+    memcpy((void *)BUILD_SMM_INIT_ADDR, (void *)BUILD_SMM_ADDR, BUILD_SMM_SIZE);
+
+    /* copy the SMM code */
+    memcpy((void *)BUILD_SMM_ADDR, &smm_code_start
+           , &smm_code_end - &smm_code_start);
+    wbinvd();
+}
+
+#define I440FX_SMRAM    0x72
+#define PIIX_DEVACTB    0x58
+#define PIIX_APMC_EN    (1 << 25)
+
+// This code is hardcoded for PIIX4 Power Management device.
+static void piix4_apmc_smm_init(struct pci_device *pci, void *arg)
+{
+    struct pci_device *i440_pci = pci_find_device(PCI_VENDOR_ID_INTEL
+                                                  , PCI_DEVICE_ID_INTEL_82441);
+    if (!i440_pci)
+        return;
+
+    /* check if SMM init is already done */
+    u32 value = pci_config_readl(pci->bdf, PIIX_DEVACTB);
+    if (value & PIIX_APMC_EN)
+        return;
+
+    /* enable the SMM memory window */
+    pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x48);
+
+    smm_save_and_copy();
+
+    /* enable SMI generation when writing to the APMC register */
+    pci_config_writel(pci->bdf, PIIX_DEVACTB, value | PIIX_APMC_EN);
+
+    smm_relocate_and_restore();
+
+    /* close the SMM memory window and enable normal SMM */
+    pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x08);
+}
+
+static const struct pci_device_id smm_init_tbl[] = {
+    PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+               piix4_apmc_smm_init),
+
+    PCI_DEVICE_END,
+};
+
+void
+smm_init(void)
+{
+    if (CONFIG_COREBOOT)
+        // SMM only supported on emulators.
+        return;
+    if (!CONFIG_USE_SMM)
+        return;
+
+    dprintf(3, "init smm\n");
+    pci_find_init_device(smm_init_tbl, NULL);
+}
diff --git a/bios/seabios/src/smp.c b/bios/seabios/src/smp.c
new file mode 100644 (file)
index 0000000..8c077a1
--- /dev/null
@@ -0,0 +1,131 @@
+// CPU count detection
+//
+// 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 "util.h" // dprintf
+#include "config.h" // CONFIG_*
+#include "cmos.h" // CMOS_BIOS_SMP_COUNT
+#include "paravirt.h"
+
+#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
+
+struct { u32 ecx, eax, edx; } smp_mtrr[32] VAR16VISIBLE;
+u32 smp_mtrr_count VAR16VISIBLE;
+
+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].ecx = index;
+    smp_mtrr[smp_mtrr_count].eax = val;
+    smp_mtrr[smp_mtrr_count].edx = val >> 32;
+    smp_mtrr_count++;
+}
+
+u32 CountCPUs VAR16VISIBLE;
+u32 MaxCountCPUs VAR16VISIBLE;
+extern void smp_ap_boot_code(void);
+ASM16(
+    "  .global smp_ap_boot_code\n"
+    "smp_ap_boot_code:\n"
+
+    // Setup data segment
+    "  movw $" __stringify(SEG_BIOS) ", %ax\n"
+    "  movw %ax, %ds\n"
+
+    // MTRR setup
+    "  movl $smp_mtrr, %esi\n"
+    "  movl smp_mtrr_count, %ebx\n"
+    "1:testl %ebx, %ebx\n"
+    "  jz 2f\n"
+    "  movl 0(%esi), %ecx\n"
+    "  movl 4(%esi), %eax\n"
+    "  movl 8(%esi), %edx\n"
+    "  wrmsr\n"
+    "  addl $12, %esi\n"
+    "  decl %ebx\n"
+    "  jmp 1b\n"
+    "2:\n"
+
+    // Increment the cpu counter
+    "  lock incl CountCPUs\n"
+
+    // Halt the processor.
+    "1:hlt\n"
+    "  jmp 1b\n"
+    );
+
+// find and initialize the CPUs by launching a SIPI to them
+void
+smp_probe(void)
+{
+    ASSERT32FLAT();
+    u32 eax, ebx, ecx, cpuid_features;
+    cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+    if (eax < 1 || !(cpuid_features & CPUID_APIC)) {
+        // No apic - only the main cpu is present.
+        dprintf(1, "No apic - only the main cpu is present.\n");
+        CountCPUs= 1;
+        MaxCountCPUs = 1;
+        return;
+    }
+
+    // Init the counter.
+    writel(&CountCPUs, 1);
+
+    // Setup jump trampoline to counter code.
+    u64 old = *(u64*)BUILD_AP_BOOT_ADDR;
+    // ljmpw $SEG_BIOS, $(smp_ap_boot_code - BUILD_BIOS_ADDR)
+    u64 new = (0xea | ((u64)SEG_BIOS<<24)
+               | (((u32)smp_ap_boot_code - BUILD_BIOS_ADDR) << 8));
+    *(u64*)BUILD_AP_BOOT_ADDR = new;
+
+    // enable local APIC
+    u32 val = readl(APIC_SVR);
+    writel(APIC_SVR, val | APIC_ENABLED);
+
+    if (! CONFIG_COREBOOT) {
+        /* Set LINT0 as Ext_INT, level triggered */
+        writel(APIC_LINT0, 0x8700);
+
+        /* Set LINT1 as NMI, level triggered */
+        writel(APIC_LINT1, 0x8400);
+    }
+
+    // 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.
+    if (CONFIG_COREBOOT) {
+        msleep(10);
+    } else {
+        u8 cmos_smp_count = inb_cmos(CMOS_BIOS_SMP_COUNT);
+        while (cmos_smp_count + 1 != readl(&CountCPUs))
+            yield();
+    }
+
+    // Restore memory.
+    *(u64*)BUILD_AP_BOOT_ADDR = old;
+
+    MaxCountCPUs = qemu_cfg_get_max_cpus();
+    if (!MaxCountCPUs || MaxCountCPUs < CountCPUs)
+        MaxCountCPUs = CountCPUs;
+
+    dprintf(1, "Found %d cpu(s) max supported %d cpu(s)\n", readl(&CountCPUs),
+        MaxCountCPUs);
+}
diff --git a/bios/seabios/src/ssdt-proc.dsl b/bios/seabios/src/ssdt-proc.dsl
new file mode 100644 (file)
index 0000000..358afa8
--- /dev/null
@@ -0,0 +1,50 @@
+/* This file is the basis for the ssdt_proc[] variable 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.
+ *
+ * To generate a new ssdt_proc[], run the commands:
+ *   cpp -P src/ssdt-proc.dsl > out/ssdt-proc.dsl.i
+ *   iasl -ta -p out/ssdt-proc out/ssdt-proc.dsl.i
+ *   tail -c +37 < out/ssdt-proc.aml | hexdump -e '"    " 8/1 "0x%02x," "\n"'
+ * and then cut-and-paste the output into the src/acpi.c ssdt_proc[]
+ * array.
+ *
+ * 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, ... })
+ */
+DefinitionBlock ("ssdt-proc.aml", "SSDT", 0x01, "BXPC", "BXSSDT", 0x1)
+/*  v------------------ DO NOT EDIT ------------------v */
+{
+    Processor (CPAA, 0xAA, 0x0000b010, 0x06) {
+        Name (ID, 0xAA)
+/*  ^------------------ DO NOT EDIT ------------------^
+ *
+ * The src/acpi.c code requires the above layout 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/bios/seabios/src/stacks.c b/bios/seabios/src/stacks.c
new file mode 100644 (file)
index 0000000..17f1a4a
--- /dev/null
@@ -0,0 +1,390 @@
+// Code for manipulating stack locations.
+//
+// Copyright (C) 2009-2010  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // get_ebda_seg
+#include "util.h" // dprintf
+#include "bregs.h" // CR0_PE
+
+// Thread info - stored at bottom of each thread stack - don't change
+// without also updating the inline assembler below.
+struct thread_info {
+    struct thread_info *next;
+    void *stackpos;
+    struct thread_info **pprev;
+};
+struct thread_info VAR32FLATVISIBLE MainThread = {
+    &MainThread, NULL, &MainThread.next
+};
+
+
+/****************************************************************
+ * Low level helpers
+ ****************************************************************/
+
+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");
+}
+
+// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function.
+u32 VISIBLE16
+call32(void *func, u32 eax, u32 errret)
+{
+    ASSERT16();
+    u32 cr0 = getcr0();
+    if (cr0 & CR0_PE)
+        // Called in 16bit protected mode?!
+        return errret;
+
+    // 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);
+
+    // Backup fs/gs and gdt
+    u16 fs = GET_SEG(FS), gs = GET_SEG(GS);
+    struct descloc_s gdt;
+    sgdt(&gdt);
+
+    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"
+        "  .code32\n"
+        "1:calll *%3\n"
+        "  movl $2f, %%edx\n"
+        "  jmp transition16big\n"
+
+        // Restore ds/ss/esp
+        "  .code16gcc\n"
+        "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");
+
+    // Restore gdt and fs/gs
+    lgdt(&gdt);
+    SET_SEG(FS, fs);
+    SET_SEG(GS, gs);
+
+    // Restore cmos index register
+    outb(cmosindex, PORT_CMOS_INDEX);
+    inb(PORT_CMOS_DATA);
+    return eax;
+}
+
+// 16bit trampoline for enabling irqs from 32bit mode.
+ASM16(
+    "  .global trampoline_checkirqs\n"
+    "trampoline_checkirqs:\n"
+    "  rep ; nop\n"
+    "  lretw"
+    );
+
+static void
+check_irqs(void)
+{
+    if (MODESEGMENT) {
+        asm volatile(
+            "sti\n"
+            "nop\n"
+            "rep ; nop\n"
+            "cli\n"
+            "cld\n"
+            : : :"memory");
+        return;
+    }
+    extern void trampoline_checkirqs();
+    struct bregs br;
+    br.flags = F_IF;
+    br.code.seg = SEG_BIOS;
+    br.code.offset = (u32)&trampoline_checkirqs;
+    call16big(&br);
+}
+
+// 16bit trampoline for waiting for an irq from 32bit mode.
+ASM16(
+    "  .global trampoline_waitirq\n"
+    "trampoline_waitirq:\n"
+    "  sti\n"
+    "  hlt\n"
+    "  lretw"
+    );
+
+// Wait for next irq to occur.
+void
+wait_irq(void)
+{
+    if (MODESEGMENT) {
+        asm volatile("sti ; hlt ; cli ; cld": : :"memory");
+        return;
+    }
+    if (CONFIG_THREADS && MainThread.next != &MainThread) {
+        // Threads still active - do a yield instead.
+        yield();
+        return;
+    }
+    extern void trampoline_waitirq();
+    struct bregs br;
+    br.flags = 0;
+    br.code.seg = SEG_BIOS;
+    br.code.offset = (u32)&trampoline_waitirq;
+    call16big(&br);
+}
+
+
+/****************************************************************
+ * Stack in EBDA
+ ****************************************************************/
+
+// Switch to the extra stack in ebda and call a function.
+inline u32
+stack_hop(u32 eax, u32 edx, void *func)
+{
+    ASSERT16();
+    u16 ebda_seg = get_ebda_seg(), bkup_ss;
+    u32 bkup_esp;
+    asm volatile(
+        // Backup current %ss/%esp values.
+        "movw %%ss, %w3\n"
+        "movl %%esp, %4\n"
+        // Copy ebda seg to %ds/%ss and set %esp
+        "movw %w6, %%ds\n"
+        "movw %w6, %%ss\n"
+        "movl %5, %%esp\n"
+        // Call func
+        "calll *%2\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)
+        : "i" (EBDA_OFFSET_TOP_STACK), "r" (ebda_seg)
+        : "cc", "memory");
+    return eax;
+}
+
+
+/****************************************************************
+ * Threads
+ ****************************************************************/
+
+#define THREADSTACKSIZE 4096
+int VAR16VISIBLE CanPreempt;
+
+// Return the 'struct thread_info' for the currently running thread.
+struct thread_info *
+getCurThread(void)
+{
+    u32 esp = getesp();
+    if (esp <= BUILD_STACK_ADDR)
+        return &MainThread;
+    return (void*)ALIGN_DOWN(esp, THREADSTACKSIZE);
+}
+
+// Switch to next thread stack.
+static void
+switch_next(struct thread_info *cur)
+{
+    struct thread_info *next = cur->next;
+    if (cur == next)
+        // Nothing to do.
+        return;
+    asm volatile(
+        "  pushl $1f\n"                 // store return pc
+        "  pushl %%ebp\n"               // backup %ebp
+        "  movl %%esp, 4(%%eax)\n"      // cur->stackpos = %esp
+        "  movl 4(%%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");
+}
+
+// Briefly permit irqs to occur.
+void
+yield(void)
+{
+    if (MODESEGMENT || !CONFIG_THREADS) {
+        // Just directly check irqs.
+        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);
+}
+
+// Last thing called from a thread (called on "next" stack).
+static void
+__end_thread(struct thread_info *old)
+{
+    old->next->pprev = old->pprev;
+    *old->pprev = old->next;
+    free(old);
+    dprintf(DEBUG_thread, "\\%08x/ End thread\n", (u32)old);
+    if (MainThread.next == &MainThread)
+        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)
+        goto fail;
+    struct thread_info *thread;
+    thread = memalign_tmphigh(THREADSTACKSIZE, THREADSTACKSIZE);
+    if (!thread)
+        goto fail;
+
+    thread->stackpos = (void*)thread + THREADSTACKSIZE;
+    struct thread_info *cur = getCurThread();
+    thread->next = cur;
+    thread->pprev = cur->pprev;
+    cur->pprev = &thread->next;
+    *thread->pprev = thread;
+
+    dprintf(DEBUG_thread, "/%08x\\ Start thread\n", (u32)thread);
+    asm volatile(
+        // Start thread
+        "  pushl $1f\n"                 // store return pc
+        "  pushl %%ebp\n"               // backup %ebp
+        "  movl %%esp, 4(%%edx)\n"      // cur->stackpos = %esp
+        "  movl 4(%%ebx), %%esp\n"      // %esp = thread->stackpos
+        "  calll *%%ecx\n"              // Call func
+
+        // End thread
+        "  movl (%%ebx), %%ecx\n"       // %ecx = thread->next
+        "  movl 4(%%ecx), %%esp\n"      // %esp = next->stackpos
+        "  movl %%ebx, %%eax\n"
+        "  calll %4\n"                  // call __end_thread(thread)
+        "  popl %%ebp\n"                // restore %ebp
+        "  retl\n"                      // restore pc
+        "1:\n"
+        : "+a"(data), "+c"(func), "+b"(thread), "+d"(cur)
+        : "m"(*(u8*)__end_thread)
+        : "esi", "edi", "cc", "memory");
+    return;
+
+fail:
+    func(data);
+}
+
+// Wait for all threads (other than the main thread) to complete.
+void
+wait_threads(void)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_THREADS)
+        return;
+    while (MainThread.next != &MainThread)
+        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
+ ****************************************************************/
+
+static u32 PreemptCount;
+
+// Turn on RTC irqs and arrange for them to check the 32bit threads.
+void
+start_preempt(void)
+{
+    if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS)
+        return;
+    CanPreempt = 1;
+    PreemptCount = 0;
+    useRTC();
+}
+
+// Turn off RTC irqs / stop checking for thread execution.
+void
+finish_preempt(void)
+{
+    if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS) {
+        yield();
+        return;
+    }
+    CanPreempt = 0;
+    releaseRTC();
+    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 || !CONFIG_THREAD_OPTIONROMS
+        || !CanPreempt)
+        return 0;
+    while (CanPreempt)
+        yield();
+    return 1;
+}
+
+// Try to execute 32bit threads.
+void VISIBLE32INIT
+yield_preempt(void)
+{
+    PreemptCount++;
+    switch_next(&MainThread);
+}
+
+// 16bit code that checks if threads are pending and executes them if so.
+void
+check_preempt(void)
+{
+    if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS
+        || !GET_GLOBAL(CanPreempt)
+        || GET_FLATPTR(MainThread.next) == &MainThread)
+        return;
+
+    extern void _cfunc32flat_yield_preempt(void);
+    call32(_cfunc32flat_yield_preempt, 0, 0);
+}
diff --git a/bios/seabios/src/system.c b/bios/seabios/src/system.c
new file mode 100644 (file)
index 0000000..898c3cc
--- /dev/null
@@ -0,0 +1,365 @@
+// 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 "util.h" // memcpy_far
+#include "biosvar.h" // BIOS_CONFIG_TABLE
+#include "ioport.h" // inb
+#include "memmap.h" // E820_RAM
+#include "pic.h" // eoi_pic2
+#include "bregs.h" // struct bregs
+
+// Use PS2 System Control port A to set A20 enable
+static inline u8
+set_a20(u8 cond)
+{
+    // get current setting first
+    u8 newval, oldval = inb(PORT_A20);
+    if (cond)
+        newval = oldval | A20_ENABLE_BIT;
+    else
+        newval = oldval & ~A20_ENABLE_BIT;
+    outb(newval, PORT_A20);
+
+    return (oldval & A20_ENABLE_BIT) != 0;
+}
+
+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 = (inb(PORT_A20) & A20_ENABLE_BIT) != 0;
+    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
+    u32 si = regs->si;
+    u64 *gdt_far = (void*)si;
+    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
+    SET_FARVAR(gdt_seg, gdt_far[4], GDT_CODE | GDT_LIMIT(BUILD_BIOS_SIZE-1)
+               | 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 | GDT_LIMIT(0x0ffff)
+               | GDT_BASE(loc));
+
+    u16 count = regs->cx;
+    asm volatile(
+        // Load new descriptor tables
+        "  lgdtw %%es:(1<<3)(%%si)\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"
+
+        // move CX words from DS:SI to ES:DI
+        "  xorw %%si, %%si\n"
+        "  xorw %%di, %%di\n"
+        "  rep movsw\n"
+
+        // Restore DS and ES segment limits to 0xffff
+        "  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) ", $2f\n"
+
+        // restore IDT to normal real-mode defaults
+        "2:lidtw %%cs:rmode_IDT_info\n"
+
+        // Restore %ds (from %ss)
+        "  movw %%ss, %%ax\n"
+        "  movw %%ax, %%ds\n"
+        : "+c"(count), "+S"(si)
+        : : "eax", "di", "cc"); // XXX - also clobbers %es
+
+    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(RamSize);
+
+    // 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
+static void
+handle_1589(struct bregs *regs)
+{
+    set_a20(1);
+
+    set_pics(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)
+        : "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(RamSize);
+
+    // 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);
+}
+
+// Info on e820 map location and size.
+struct e820entry e820_list[CONFIG_MAX_E820] VAR16VISIBLE;
+int e820_count VAR16VISIBLE;
+
+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 0x83: handle_1583(regs); break;
+    case 0x86: handle_1586(regs); break;
+    case 0x87: handle_1587(regs); break;
+    case 0x88: handle_1588(regs); break;
+    case 0x89: handle_1589(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/bios/seabios/src/types.h b/bios/seabios/src/types.h
new file mode 100644 (file)
index 0000000..c0c6d26
--- /dev/null
@@ -0,0 +1,142 @@
+// 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 hi, lo; };
+    u64 val;
+};
+
+#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 __section(".discard.func32flat." UNIQSEC) noinline
+// Notes a 32bit flat function that will only be called during init.
+# define VISIBLE32INIT VISIBLE32FLAT
+// Notes a function as externally visible in the 32bit segmented code chunk.
+# define VISIBLE32SEG __section(".discard.func32seg." UNIQSEC) noinline
+// Designate a variable as (only) visible to 16bit code.
+# define VAR16 __section(".data16." UNIQSEC)
+// Designate a variable as visible to 16bit, 32bit, and assembler code.
+# define VAR16VISIBLE VAR16 __VISIBLE
+// Designate a variable as externally visible (in addition to all internal code).
+# define VAR16EXPORT __section(".data16.export." UNIQSEC) __VISIBLE
+// Designate a variable at a specific 16bit address
+# define VAR16FIXED(addr) __aligned(1) __VISIBLE __section(".fixedaddr." __stringify(addr))
+// Designate a variable as (only) visible to 32bit segmented code.
+# define VAR32SEG __section(".discard.var32seg." UNIQSEC)
+// Designate a 32bit variable also available in 16bit "big real" mode.
+# define VAR32FLATVISIBLE __section(".discard.var32flat." UNIQSEC) __VISIBLE __weak
+// 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 __section(".discard.func16." UNIQSEC) noinline
+# define VISIBLE32FLAT __section(".discard.func32flat." UNIQSEC) noinline
+# define VISIBLE32INIT VISIBLE32FLAT
+# define VISIBLE32SEG __VISIBLE
+# define VAR16 __section(".discard.var16." UNIQSEC)
+# define VAR16VISIBLE VAR16 __VISIBLE __weak
+# define VAR16EXPORT VAR16VISIBLE
+# define VAR16FIXED(addr) VAR16VISIBLE
+# define VAR32SEG __section(".data32seg." UNIQSEC)
+# define VAR32FLATVISIBLE __section(".discard.var32flat." UNIQSEC) __VISIBLE __weak
+# 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 __section(".discard.func16." UNIQSEC) noinline
+# define VISIBLE32FLAT __section(".text.runtime." UNIQSEC) __VISIBLE
+# define VISIBLE32INIT __section(".text.init." UNIQSEC) __VISIBLE
+# define VISIBLE32SEG __section(".discard.func32seg." UNIQSEC) noinline
+# define VAR16 __section(".discard.var16." UNIQSEC)
+# define VAR16VISIBLE VAR16 __VISIBLE __weak
+# define VAR16EXPORT VAR16VISIBLE
+# define VAR16FIXED(addr) VAR16VISIBLE
+# define VAR32SEG __section(".discard.var32seg." UNIQSEC)
+# define VAR32FLATVISIBLE __section(".data.runtime." UNIQSEC) __VISIBLE
+# 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 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/bios/seabios/src/usb-ehci.c b/bios/seabios/src/usb-ehci.c
new file mode 100644 (file)
index 0000000..a60c607
--- /dev/null
@@ -0,0 +1,758 @@
+// Code for handling EHCI USB controllers.
+//
+// Copyright (C) 2010  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // pci_bdf_to_bus
+#include "config.h" // CONFIG_*
+#include "ioport.h" // outw
+#include "usb-ehci.h" // struct ehci_qh
+#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI
+#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "usb.h" // struct usb_s
+#include "farptr.h" // GET_FLATPTR
+#include "usb-uhci.h" // init_uhci
+#include "usb-ohci.h" // init_ohci
+
+struct usb_ehci_s {
+    struct usb_s usb;
+    struct ehci_caps *caps;
+    struct ehci_regs *regs;
+    struct ehci_qh *async_qh;
+    struct pci_device *companion[8];
+    int checkports;
+    int legacycount;
+};
+
+
+/****************************************************************
+ * Root hub
+ ****************************************************************/
+
+#define EHCI_TIME_POSTPOWER 20
+#define EHCI_TIME_POSTRESET 2
+
+// Check if need companion controllers for full/low speed devices
+static void
+ehci_note_port(struct usb_ehci_s *cntl)
+{
+    if (--cntl->checkports)
+        // Ports still being detected.
+        return;
+    if (! cntl->legacycount)
+        // No full/low speed devices found.
+        return;
+    // Start companion controllers.
+    int i;
+    for (i=0; i<ARRAY_SIZE(cntl->companion); i++) {
+        struct pci_device *pci = cntl->companion[i];
+        if (!pci)
+            break;
+
+        // ohci/uhci_init call pci_config_XXX - don't run from irq handler.
+        wait_preempt();
+
+        if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_UHCI)
+            uhci_init(pci, cntl->usb.busid + i);
+        else if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_OHCI)
+            ohci_init(pci, cntl->usb.busid + i);
+    }
+}
+
+// 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);
+
+    // Power up port.
+    if (!(portsc & PORT_POWER)) {
+        portsc |= PORT_POWER;
+        writel(portreg, portsc);
+        msleep(EHCI_TIME_POSTPOWER);
+    } else {
+        msleep(1); // XXX - time for connect to be detected.
+    }
+    portsc = readl(portreg);
+
+    if (!(portsc & PORT_CONNECT))
+        // No device present
+        goto doneearly;
+
+    if ((portsc & PORT_LINESTATUS_MASK) == PORT_LINESTATUS_KSTATE) {
+        // low speed device
+        cntl->legacycount++;
+        writel(portreg, portsc | PORT_OWNER);
+        goto doneearly;
+    }
+
+    // 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 0;
+
+doneearly:
+    ehci_note_port(cntl);
+    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);
+
+    int rv = -1;
+    portsc = readl(portreg);
+    if (!(portsc & PORT_CONNECT))
+        // No longer connected
+        goto resetfail;
+    if (!(portsc & PORT_PE)) {
+        // full speed device
+        cntl->legacycount++;
+        writel(portreg, portsc | PORT_OWNER);
+        goto resetfail;
+    }
+
+    rv = USB_HIGHSPEED;
+resetfail:
+    ehci_note_port(cntl);
+    return rv;
+}
+
+// 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)
+{
+    ASSERT32FLAT();
+    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
+ ****************************************************************/
+
+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();
+        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);
+    u64 end = calc_future_tsc(250);
+    for (;;) {
+        cmd = readl(&cntl->regs->usbcmd);
+        if (!(cmd & CMD_HCRESET))
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            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);
+    cntl->checkports = readl(&cntl->caps->hcsparams) & HCS_N_PORTS_MASK;
+
+    // Find devices
+    int count = check_ehci_ports(cntl);
+    free_pipe(cntl->usb.defaultpipe);
+    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);
+}
+
+int
+ehci_init(struct pci_device *pci, int busid, struct pci_device *comppci)
+{
+    if (! CONFIG_USB_EHCI)
+        return -1;
+
+    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);
+    if (hcc_params & HCC_64BIT_ADDR) {
+        dprintf(1, "No support for 64bit EHCI\n");
+        return -1;
+    }
+
+    struct usb_ehci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+    if (!cntl) {
+        warn_noalloc();
+        return -1;
+    }
+    memset(cntl, 0, sizeof(*cntl));
+    cntl->usb.busid = busid;
+    cntl->usb.pci = pci;
+    cntl->usb.type = USB_TYPE_EHCI;
+    cntl->caps = caps;
+    cntl->regs = (void*)caps + readb(&caps->caplength);
+
+    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?
+
+    // Find companion controllers.
+    int count = 0;
+    for (;;) {
+        if (!comppci || comppci == pci)
+            break;
+        if (pci_classprog(comppci) == PCI_CLASS_SERIAL_USB_UHCI)
+            cntl->companion[count++] = comppci;
+        else if (pci_classprog(comppci) == PCI_CLASS_SERIAL_USB_OHCI)
+            cntl->companion[count++] = comppci;
+        comppci = comppci->next;
+    }
+
+    run_thread(configure_ehci, cntl);
+    return 0;
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+static int
+ehci_wait_qh(struct usb_ehci_s *cntl, struct ehci_qh *qh)
+{
+    // XXX - 500ms just a guess
+    u64 end = calc_future_tsc(500);
+    for (;;) {
+        if (qh->qtd_next & EHCI_PTR_TERM)
+            // XXX - confirm
+            return 0;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return -1;
+        }
+        yield();
+    }
+}
+
+// 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;
+    u64 end = calc_future_tsc(100);
+    for (;;) {
+        sts = readl(&cntl->regs->usbsts);
+        if (!(sts & STS_IAA)) {
+            cmd = readl(&cntl->regs->usbcmd);
+            if (!(cmd & CMD_IAAD))
+                break;
+        }
+        if (check_tsc(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 (check_tsc(end)) {
+            warn_timeout();
+            return;
+        }
+        yield();
+    }
+    // Ack completion
+    writel(&cntl->regs->usbsts, STS_IAA);
+}
+
+struct ehci_pipe {
+    struct ehci_qh qh;
+    struct ehci_qtd *next_td, *tds;
+    void *data;
+    struct usb_pipe pipe;
+};
+
+void
+ehci_free_pipe(struct usb_pipe *p)
+{
+    if (! CONFIG_USB_EHCI)
+        return;
+    dprintf(7, "ehci_free_pipe %p\n", p);
+    struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
+    struct usb_ehci_s *cntl = container_of(
+        pipe->pipe.cntl, struct usb_ehci_s, usb);
+
+    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) {
+            // Not found?!  Exit without freeing.
+            warn_internalerror();
+            return;
+        }
+        if (next == &pipe->qh) {
+            pos->next = next->next;
+            ehci_waittick(cntl);
+            free(pipe);
+            return;
+        }
+        pos = next;
+    }
+}
+
+struct usb_pipe *
+ehci_alloc_control_pipe(struct usb_pipe *dummy)
+{
+    if (! CONFIG_USB_EHCI)
+        return NULL;
+    struct usb_ehci_s *cntl = container_of(
+        dummy->cntl, struct usb_ehci_s, usb);
+    dprintf(7, "ehci_alloc_control_pipe %p\n", &cntl->usb);
+
+    // Allocate a queue head.
+    struct ehci_pipe *pipe = memalign_tmphigh(EHCI_QH_ALIGN, sizeof(*pipe));
+    if (!pipe) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(pipe, 0, sizeof(*pipe));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM;
+    pipe->qh.token = QTD_STS_HALT;
+
+    // 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 int
+fillTDbuffer(struct ehci_qtd *td, u16 maxpacket, const void *buf, int bytes)
+{
+    u32 dest = (u32)buf;
+    u32 *pos = td->buf;
+    while (bytes) {
+        if (pos >= &td->buf[ARRAY_SIZE(td->buf)])
+            // More data than can transfer in a single qtd - only use
+            // full packets to prevent a babble error.
+            return ALIGN_DOWN(dest - (u32)buf, maxpacket);
+        u32 count = bytes;
+        u32 max = 0x1000 - (dest & 0xfff);
+        if (count > max)
+            count = max;
+        *pos = dest;
+        bytes -= count;
+        dest += count;
+        pos++;
+    }
+    return dest - (u32)buf;
+}
+
+int
+ehci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+             , void *data, int datasize)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_USB_EHCI)
+        return -1;
+    dprintf(5, "ehci_control %p\n", p);
+    if (datasize > 4*4096 || cmdsize > 4*4096) {
+        // XXX - should support larger sizes.
+        warn_noalloc();
+        return -1;
+    }
+    struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
+    struct usb_ehci_s *cntl = container_of(
+        pipe->pipe.cntl, struct usb_ehci_s, usb);
+
+    u16 maxpacket = pipe->pipe.maxpacket;
+    int speed = pipe->pipe.speed;
+
+    // Setup fields in qh
+    pipe->qh.info1 = (
+        (1 << QH_MULT_SHIFT) | (speed != USB_HIGHSPEED ? QH_CONTROL : 0)
+        | (maxpacket << QH_MAXPACKET_SHIFT)
+        | QH_TOGGLECONTROL
+        | (speed << QH_SPEED_SHIFT)
+        | (pipe->pipe.ep << QH_EP_SHIFT)
+        | (pipe->pipe.devaddr << QH_DEVADDR_SHIFT));
+    pipe->qh.info2 = ((1 << QH_MULT_SHIFT)
+                      | (pipe->pipe.tt_port << QH_HUBPORT_SHIFT)
+                      | (pipe->pipe.tt_devaddr << QH_HUBADDR_SHIFT));
+
+    // Setup transfer descriptors
+    struct ehci_qtd *tds = memalign_tmphigh(EHCI_QTD_ALIGN, sizeof(*tds) * 3);
+    if (!tds) {
+        warn_noalloc();
+        return -1;
+    }
+    memset(tds, 0, sizeof(*tds) * 3);
+    struct ehci_qtd *td = tds;
+
+    td->qtd_next = (u32)&td[1];
+    td->alt_next = EHCI_PTR_TERM;
+    td->token = (ehci_explen(cmdsize) | QTD_STS_ACTIVE
+                 | QTD_PID_SETUP | ehci_maxerr(3));
+    fillTDbuffer(td, maxpacket, cmd, cmdsize);
+    td++;
+
+    if (datasize) {
+        td->qtd_next = (u32)&td[1];
+        td->alt_next = EHCI_PTR_TERM;
+        td->token = (QTD_TOGGLE | ehci_explen(datasize) | QTD_STS_ACTIVE
+                     | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3));
+        fillTDbuffer(td, maxpacket, data, datasize);
+        td++;
+    }
+
+    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));
+
+    // Transfer data
+    barrier();
+    pipe->qh.qtd_next = (u32)tds;
+    barrier();
+    pipe->qh.token = 0;
+    int ret = ehci_wait_qh(cntl, &pipe->qh);
+    pipe->qh.token = QTD_STS_HALT;
+    if (ret) {
+        pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM;
+        // XXX - halt qh?
+        ehci_waittick(cntl);
+    }
+    free(tds);
+    return ret;
+}
+
+struct usb_pipe *
+ehci_alloc_bulk_pipe(struct usb_pipe *dummy)
+{
+    // XXX - this func is same as alloc_control except for malloc_low
+    if (! CONFIG_USB_EHCI)
+        return NULL;
+    struct usb_ehci_s *cntl = container_of(
+        dummy->cntl, struct usb_ehci_s, usb);
+    dprintf(7, "ehci_alloc_bulk_pipe %p\n", &cntl->usb);
+
+    // Allocate a queue head.
+    struct ehci_pipe *pipe = memalign_low(EHCI_QH_ALIGN, sizeof(*pipe));
+    if (!pipe) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(pipe, 0, sizeof(*pipe));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM;
+    pipe->qh.token = QTD_STS_HALT;
+
+    // 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 int
+ehci_wait_td(struct ehci_qtd *td)
+{
+    u64 end = calc_future_tsc(5000); // XXX - lookup real time.
+    u32 status;
+    for (;;) {
+        status = td->token;
+        if (!(status & QTD_STS_ACTIVE))
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return -1;
+        }
+        yield();
+    }
+    if (status & QTD_STS_HALT) {
+        dprintf(1, "ehci_wait_td error - status=%x\n", status);
+        return -2;
+    }
+    return 0;
+}
+
+#define STACKQTDS 4
+
+int
+ehci_send_bulk(struct usb_pipe *p, int dir, 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_bulk qh=%p dir=%d data=%p size=%d\n"
+            , &pipe->qh, dir, data, datasize);
+
+    // Allocate 4 tds on stack (16byte aligned)
+    u8 tdsbuf[sizeof(struct ehci_qtd) * STACKQTDS + EHCI_QTD_ALIGN - 1];
+    struct ehci_qtd *tds = (void*)ALIGN((u32)tdsbuf, EHCI_QTD_ALIGN);
+    memset(tds, 0, sizeof(*tds) * STACKQTDS);
+
+    // Setup fields in qh
+    u16 maxpacket = GET_FLATPTR(pipe->pipe.maxpacket);
+    SET_FLATPTR(pipe->qh.info1
+                , ((1 << QH_MULT_SHIFT)
+                   | (maxpacket << QH_MAXPACKET_SHIFT)
+                   | (GET_FLATPTR(pipe->pipe.speed) << QH_SPEED_SHIFT)
+                   | (GET_FLATPTR(pipe->pipe.ep) << QH_EP_SHIFT)
+                   | (GET_FLATPTR(pipe->pipe.devaddr) << QH_DEVADDR_SHIFT)));
+    SET_FLATPTR(pipe->qh.info2
+                , ((1 << QH_MULT_SHIFT)
+                   | (GET_FLATPTR(pipe->pipe.tt_port) << QH_HUBPORT_SHIFT)
+                   | (GET_FLATPTR(pipe->pipe.tt_devaddr) << QH_HUBADDR_SHIFT)));
+    barrier();
+    SET_FLATPTR(pipe->qh.qtd_next, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
+    barrier();
+    SET_FLATPTR(pipe->qh.token, GET_FLATPTR(pipe->qh.token) & QTD_TOGGLE);
+
+    int tdpos = 0;
+    while (datasize) {
+        struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS];
+        int ret = ehci_wait_td(td);
+        if (ret)
+            goto fail;
+
+        struct ehci_qtd *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS)
+                                                 , &tds[tdpos % STACKQTDS]);
+
+        int transfer = fillTDbuffer(td, maxpacket, data, datasize);
+        td->qtd_next = (transfer==datasize ? EHCI_PTR_TERM : (u32)nexttd_fl);
+        td->alt_next = EHCI_PTR_TERM;
+        barrier();
+        td->token = (ehci_explen(transfer) | QTD_STS_ACTIVE
+                     | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3));
+
+        data += transfer;
+        datasize -= transfer;
+    }
+    int i;
+    for (i=0; i<STACKQTDS; i++) {
+        struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS];
+        int ret = ehci_wait_td(td);
+        if (ret)
+            goto fail;
+    }
+
+    return 0;
+fail:
+    dprintf(1, "ehci_send_bulk failed\n");
+    SET_FLATPTR(pipe->qh.qtd_next, EHCI_PTR_TERM);
+    SET_FLATPTR(pipe->qh.alt_next, EHCI_PTR_TERM);
+    // XXX - halt qh?
+    struct usb_ehci_s *cntl = container_of(
+        GET_FLATPTR(pipe->pipe.cntl), struct usb_ehci_s, usb);
+    ehci_waittick(cntl);
+    return -1;
+}
+
+struct usb_pipe *
+ehci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp)
+{
+    if (! CONFIG_USB_EHCI)
+        return NULL;
+    struct usb_ehci_s *cntl = container_of(
+        dummy->cntl, struct usb_ehci_s, usb);
+    dprintf(7, "ehci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
+
+    if (frameexp > 10)
+        frameexp = 10;
+    int maxpacket = dummy->maxpacket;
+    // Determine number of entries needed for 2 timer ticks.
+    int ms = 1<<frameexp;
+    int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * 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));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    pipe->next_td = pipe->tds = tds;
+    pipe->data = data;
+
+    pipe->qh.info1 = (
+        (1 << QH_MULT_SHIFT)
+        | (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)
+                      | (pipe->pipe.tt_port << QH_HUBPORT_SHIFT)
+                      | (pipe->pipe.tt_devaddr << QH_HUBADDR_SHIFT)
+                      | (0x01 << QH_SMASK_SHIFT)
+                      | (0x1c << QH_CMASK_SHIFT));
+    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;
+}
+
+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_FLATPTR(pipe->next_td);
+    u32 token = GET_FLATPTR(td->token);
+    if (token & QTD_STS_ACTIVE)
+        // No intrs found.
+        return -1;
+    // XXX - check for errors.
+
+    // Copy data.
+    int maxpacket = GET_FLATPTR(pipe->pipe.maxpacket);
+    int pos = td - GET_FLATPTR(pipe->tds);
+    void *tddata = GET_FLATPTR(pipe->data) + maxpacket * pos;
+    memcpy_far(GET_SEG(SS), data
+               , FLATPTR_TO_SEG(tddata), (void*)FLATPTR_TO_OFFSET(tddata)
+               , maxpacket);
+
+    // Reenable this td.
+    struct ehci_qtd *next = (void*)(GET_FLATPTR(td->qtd_next) & ~EHCI_PTR_BITS);
+    SET_FLATPTR(pipe->next_td, next);
+    SET_FLATPTR(td->buf[0], (u32)tddata);
+    barrier();
+    SET_FLATPTR(td->token, (ehci_explen(maxpacket) | QTD_STS_ACTIVE
+                            | QTD_PID_IN | ehci_maxerr(3)));
+
+    return 0;
+}
diff --git a/bios/seabios/src/usb-ehci.h b/bios/seabios/src/usb-ehci.h
new file mode 100644 (file)
index 0000000..1a2c6c7
--- /dev/null
@@ -0,0 +1,173 @@
+#ifndef __USB_EHCI_H
+#define __USB_EHCI_H
+
+// usb-ehci.c
+int ehci_init(struct pci_device *pci, int busid, struct pci_device *comppci);
+struct usb_pipe;
+void ehci_free_pipe(struct usb_pipe *p);
+struct usb_pipe *ehci_alloc_control_pipe(struct usb_pipe *dummy);
+int ehci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+                 , void *data, int datasize);
+struct usb_pipe *ehci_alloc_bulk_pipe(struct usb_pipe *dummy);
+int ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize);
+struct usb_pipe *ehci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp);
+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 64 // Can't span a 4K boundary, so increase to 64
+
+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 32
+
+struct ehci_qtd {
+    u32 qtd_next;
+    u32 alt_next;
+    u32 token;
+    u32 buf[5];
+    //u32 buf_hi[5];
+} PACKED;
+
+#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/bios/seabios/src/usb-hid.c b/bios/seabios/src/usb-hid.c
new file mode 100644 (file)
index 0000000..168b7fa
--- /dev/null
@@ -0,0 +1,418 @@
+// 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 "util.h" // dprintf
+#include "usb-hid.h" // usb_keyboard_setup
+#include "config.h" // CONFIG_*
+#include "usb.h" // usb_ctrlrequest
+#include "biosvar.h" // GET_GLOBAL
+#include "ps2port.h" // ATKBD_CMD_GETID
+
+struct usb_pipe *keyboard_pipe VAR16VISIBLE;
+struct usb_pipe *mouse_pipe VAR16VISIBLE;
+
+
+/****************************************************************
+ * 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 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 send_default_control(pipe, &req, NULL);
+}
+
+#define KEYREPEATWAITMS 500
+#define KEYREPEATMS 33
+
+static int
+usb_kbd_init(struct usb_pipe *pipe, 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(pipe, 0);
+    if (ret)
+        return -1;
+    // Periodically send reports to enable key repeat.
+    ret = set_idle(pipe, KEYREPEATMS);
+    if (ret)
+        return -1;
+
+    keyboard_pipe = alloc_intr_pipe(pipe, epdesc);
+    if (!keyboard_pipe)
+        return -1;
+
+    dprintf(1, "USB keyboard initialized\n");
+    return 0;
+}
+
+static int
+usb_mouse_init(struct usb_pipe *pipe, 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(pipe, 0);
+    if (ret)
+        return -1;
+
+    mouse_pipe = alloc_intr_pipe(pipe, 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_init(struct usb_pipe *pipe
+             , struct usb_interface_descriptor *iface, int imax)
+{
+    if (! CONFIG_USB_KEYBOARD || ! CONFIG_USB_MOUSE)
+        return -1;
+    dprintf(2, "usb_hid_init %p\n", pipe);
+
+    if (iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT)
+        // Doesn't support boot protocol.
+        return -1;
+
+    // Find intr in endpoint.
+    struct usb_endpoint_descriptor *epdesc = findEndPointDesc(
+        iface, imax, 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_init(pipe, epdesc);
+    if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
+        return usb_mouse_init(pipe, 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);
+        }
+}
+
+// Process USB keyboard data.
+static void noinline
+handle_key(struct keyevent *data)
+{
+    dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
+
+    // Load old keys.
+    u16 ebda_seg = get_ebda_seg();
+    struct usbkeyinfo old;
+    old.data = GET_EBDA2(ebda_seg, usbkey_last.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_EBDA2(ebda_seg, usbkey_last.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/bios/seabios/src/usb-hid.h b/bios/seabios/src/usb-hid.h
new file mode 100644 (file)
index 0000000..7fbcf4b
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __USB_HID_H
+#define __USB_HID_H
+
+// usb-hid.c
+struct usb_interface_descriptor;
+struct usb_pipe;
+int usb_hid_init(struct usb_pipe *pipe
+                 , struct usb_interface_descriptor *iface, int imax);
+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/bios/seabios/src/usb-hub.c b/bios/seabios/src/usb-hub.c
new file mode 100644 (file)
index 0000000..b2d9ff2
--- /dev/null
@@ -0,0 +1,185 @@
+// 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 "util.h" // dprintf
+#include "config.h" // CONFIG_USB_HUB
+#include "usb-hub.h" // struct usb_hub_descriptor
+#include "usb.h" // struct usb_s
+
+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;
+    req.wValue = USB_DT_HUB<<8;
+    req.wIndex = 0;
+    req.wLength = sizeof(*desc);
+    return send_default_control(pipe, &req, desc);
+}
+
+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 = send_default_control(hub->pipe, &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 = send_default_control(hub->pipe, &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 = send_default_control(hub->pipe, &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)
+{
+    // Turn on power to port.
+    int ret = set_port_feature(hub, port, USB_PORT_FEAT_POWER);
+    if (ret)
+        goto fail;
+
+    // Wait for port power to stabilize.
+    msleep(hub->powerwait);
+
+    // Check periodically for a device connect.
+    struct usb_port_status sts;
+    u64 end = calc_future_tsc(USB_TIME_SIGATT);
+    for (;;) {
+        ret = get_port_status(hub, port, &sts);
+        if (ret)
+            goto fail;
+        if (sts.wPortStatus & USB_PORT_STAT_CONNECTION)
+            // Device connected.
+            break;
+        if (check_tsc(end))
+            // No device found.
+            return -1;
+        msleep(5);
+    }
+
+    // XXX - wait USB_TIME_ATTDB time?
+
+    return 0;
+
+fail:
+    dprintf(1, "Failure on hub port %d detect\n", port);
+    return -1;
+}
+
+// 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;
+    u64 end = calc_future_tsc(USB_TIME_DRST * 2);
+    for (;;) {
+        ret = get_port_status(hub, port, &sts);
+        if (ret)
+            goto fail;
+        if (!(sts.wPortStatus & USB_PORT_STAT_RESET))
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            goto fail;
+        }
+        msleep(5);
+    }
+
+    // Reset complete.
+    if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION))
+        // Device no longer present
+        return -1;
+
+    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_init(struct usb_pipe *pipe)
+{
+    ASSERT32FLAT();
+    if (!CONFIG_USB_HUB)
+        return -1;
+
+    struct usb_hub_descriptor desc;
+    int ret = get_hub_desc(pipe, &desc);
+    if (ret)
+        return ret;
+
+    struct usbhub_s hub;
+    memset(&hub, 0, sizeof(hub));
+    hub.pipe = pipe;
+    hub.cntl = pipe->cntl;
+    hub.powerwait = desc.bPwrOn2PwrGood * 2;
+    hub.portcount = desc.bNbrPorts;
+    hub.op = &HubOp;
+    usb_enumerate(&hub);
+
+    dprintf(1, "Initialized USB HUB (%d ports used)\n", hub.devcount);
+    if (hub.devcount)
+        return 0;
+    return -1;
+}
diff --git a/bios/seabios/src/usb-hub.h b/bios/seabios/src/usb-hub.h
new file mode 100644 (file)
index 0000000..7672028
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __USB_HUB_H
+#define __USB_HUB_H
+
+// usb-hub.c
+struct usb_pipe;
+int usb_hub_init(struct usb_pipe *pipe);
+
+
+/****************************************************************
+ * hub flags
+ ****************************************************************/
+
+#define USB_DT_HUB                      (USB_TYPE_CLASS | 0x09)
+
+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_L1                0x0020
+#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/bios/seabios/src/usb-msc.c b/bios/seabios/src/usb-msc.c
new file mode 100644 (file)
index 0000000..13ef93e
--- /dev/null
@@ -0,0 +1,260 @@
+// 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 "util.h" // dprintf
+#include "config.h" // CONFIG_USB_MSC
+#include "usb-msc.h" // usb_msc_init
+#include "usb.h" // struct usb_s
+#include "biosvar.h" // GET_GLOBAL
+#include "blockcmd.h" // cdb_read
+#include "disk.h" // DTYPE_USB
+#include "boot.h" // boot_add_hd
+
+struct usbdrive_s {
+    struct drive_s drive;
+    struct usb_pipe *bulkin, *bulkout;
+};
+
+
+/****************************************************************
+ * 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;
+
+// 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_g, 0, op->count, blocksize, op->buf_fl);
+    struct usbdrive_s *udrive_g = container_of(
+        op->drive_g, struct usbdrive_s, drive);
+    struct usb_pipe *bulkin = GET_GLOBAL(udrive_g->bulkin);
+    struct usb_pipe *bulkout = GET_GLOBAL(udrive_g->bulkout);
+
+    // Setup command block wrapper.
+    u32 bytes = blocksize * op->count;
+    struct cbw_s cbw;
+    memset(&cbw, 0, sizeof(cbw));
+    cbw.dCBWSignature = CBW_SIGNATURE;
+    cbw.dCBWTag = 999; // XXX
+    cbw.dCBWDataTransferLength = bytes;
+    cbw.bmCBWFlags = USB_DIR_IN; // XXX
+    cbw.bCBWLUN = 0; // XXX
+    cbw.bCBWCBLength = USB_CDB_SIZE;
+    memcpy(cbw.CBWCB, cdbcmd, USB_CDB_SIZE);
+
+    // Transfer cbw to device.
+    int ret = usb_send_bulk(bulkout, USB_DIR_OUT
+                            , MAKE_FLATPTR(GET_SEG(SS), &cbw), sizeof(cbw));
+    if (ret)
+        goto fail;
+
+    // Transfer data from device.
+    ret = usb_send_bulk(bulkin, USB_DIR_IN, op->buf_fl, bytes);
+    if (ret)
+        goto fail;
+
+    // Transfer csw info.
+    struct csw_s csw;
+    ret = usb_send_bulk(bulkin, 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;
+
+    op->count -= csw.dCSWDataResidue / blocksize;
+    return DISK_RET_EBADTRACK;
+
+fail:
+    // XXX - reset connection
+    dprintf(1, "USB transmission failed\n");
+    op->count = 0;
+    return DISK_RET_EBADTRACK;
+}
+
+
+/****************************************************************
+ * Drive ops
+ ****************************************************************/
+
+// 16bit command demuxer for ATAPI cdroms.
+int
+process_usb_op(struct disk_op_s *op)
+{
+    if (!CONFIG_USB_MSC)
+        return 0;
+    switch (op->command) {
+    case CMD_READ:
+        return cdb_read(op);
+    case CMD_FORMAT:
+    case CMD_WRITE:
+        return DISK_RET_EWRITEPROTECT;
+    case CMD_RESET:
+    case CMD_ISREADY:
+    case CMD_VERIFY:
+    case CMD_SEEK:
+        return DISK_RET_SUCCESS;
+    default:
+        op->count = 0;
+        return DISK_RET_EPARAM;
+    }
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static int
+setup_drive_cdrom(struct disk_op_s *op, char *desc)
+{
+    op->drive_g->blksize = CDROM_SECTOR_SIZE;
+    op->drive_g->sectors = (u64)-1;
+    struct usb_pipe *pipe = container_of(
+        op->drive_g, struct usbdrive_s, drive)->bulkout;
+    int prio = bootprio_find_usb(pipe->cntl->pci, pipe->path);
+    boot_add_cd(op->drive_g, desc, prio);
+    return 0;
+}
+
+static int
+setup_drive_hd(struct disk_op_s *op, char *desc)
+{
+    struct cdbres_read_capacity info;
+    int ret = cdb_read_capacity(op, &info);
+    if (ret)
+        return ret;
+    // XXX - retry for some timeout?
+
+    u32 blksize = ntohl(info.blksize), sectors = ntohl(info.sectors);
+    if (blksize != DISK_SECTOR_SIZE) {
+        if (blksize == CDROM_SECTOR_SIZE)
+            return setup_drive_cdrom(op, desc);
+        dprintf(1, "Unsupported USB MSC block size %d\n", blksize);
+        return -1;
+    }
+    op->drive_g->blksize = blksize;
+    op->drive_g->sectors = sectors;
+    dprintf(1, "USB MSC blksize=%d sectors=%d\n", blksize, sectors);
+
+    // Register with bcv system.
+    struct usb_pipe *pipe = container_of(
+        op->drive_g, struct usbdrive_s, drive)->bulkout;
+    int prio = bootprio_find_usb(pipe->cntl->pci, pipe->path);
+    boot_add_hd(op->drive_g, desc, prio);
+
+    return 0;
+}
+
+// Configure a usb msc device.
+int
+usb_msc_init(struct usb_pipe *pipe
+             , struct usb_interface_descriptor *iface, int imax)
+{
+    if (!CONFIG_USB_MSC)
+        return -1;
+
+    // Verify right kind of device
+    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;
+    }
+
+    // Allocate drive structure.
+    struct usbdrive_s *udrive_g = malloc_fseg(sizeof(*udrive_g));
+    if (!udrive_g) {
+        warn_noalloc();
+        goto fail;
+    }
+    memset(udrive_g, 0, sizeof(*udrive_g));
+    udrive_g->drive.type = DTYPE_USB;
+
+    // Find bulk in and bulk out endpoints.
+    struct usb_endpoint_descriptor *indesc = findEndPointDesc(
+        iface, imax, USB_ENDPOINT_XFER_BULK, USB_DIR_IN);
+    struct usb_endpoint_descriptor *outdesc = findEndPointDesc(
+        iface, imax, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT);
+    if (!indesc || !outdesc)
+        goto fail;
+    udrive_g->bulkin = alloc_bulk_pipe(pipe, indesc);
+    udrive_g->bulkout = alloc_bulk_pipe(pipe, outdesc);
+    if (!udrive_g->bulkin || !udrive_g->bulkout)
+        goto fail;
+
+    // Validate drive and find block size and sector count.
+    struct disk_op_s dop;
+    memset(&dop, 0, sizeof(dop));
+    dop.drive_g = &udrive_g->drive;
+    struct cdbres_inquiry data;
+    int ret = cdb_get_inquiry(&dop, &data);
+    if (ret)
+        goto fail;
+    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, "USB MSC vendor='%s' product='%s' rev='%s' type=%d removable=%d\n"
+            , vendor, product, rev, pdt, removable);
+    udrive_g->drive.removable = removable;
+
+    if (pdt == USB_MSC_TYPE_CDROM) {
+        char *desc = znprintf(MAXDESCSIZE, "DVD/CD [USB Drive %s %s %s]"
+                              , vendor, product, rev);
+        ret = setup_drive_cdrom(&dop, desc);
+    } else {
+        char *desc = znprintf(MAXDESCSIZE, "USB Drive %s %s %s"
+                              , vendor, product, rev);
+        ret = setup_drive_hd(&dop, desc);
+    }
+    if (ret)
+        goto fail;
+
+    return 0;
+fail:
+    dprintf(1, "Unable to configure USB MSC device.\n");
+    free(udrive_g);
+    return -1;
+}
diff --git a/bios/seabios/src/usb-msc.h b/bios/seabios/src/usb-msc.h
new file mode 100644 (file)
index 0000000..71adb20
--- /dev/null
@@ -0,0 +1,27 @@
+#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 usb_interface_descriptor;
+struct usb_pipe;
+int usb_msc_init(struct usb_pipe *pipe
+                 , struct usb_interface_descriptor *iface, int imax);
+int process_usb_op(struct disk_op_s *op);
+
+
+/****************************************************************
+ * MSC flags
+ ****************************************************************/
+
+#define US_SC_ATAPI_8020   0x02
+#define US_SC_ATAPI_8070   0x05
+#define US_SC_SCSI         0x06
+
+#define US_PR_BULK         0x50
+
+#define USB_MSC_TYPE_DISK  0x00
+#define USB_MSC_TYPE_CDROM 0x05
+
+#endif // ush-msc.h
diff --git a/bios/seabios/src/usb-ohci.c b/bios/seabios/src/usb-ohci.c
new file mode 100644 (file)
index 0000000..9107db2
--- /dev/null
@@ -0,0 +1,537 @@
+// 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 "util.h" // dprintf
+#include "pci.h" // pci_bdf_to_bus
+#include "config.h" // CONFIG_*
+#include "usb-ohci.h" // struct ohci_hcca
+#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "usb.h" // struct usb_s
+#include "farptr.h" // GET_FLATPTR
+
+#define FIT                     (1 << 31)
+
+struct usb_ohci_s {
+    struct usb_s usb;
+    struct ohci_regs *regs;
+};
+
+
+/****************************************************************
+ * 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]);
+    if (!(sts & RH_PS_CCS))
+        // No device.
+        return -1;
+
+    // XXX - need to wait for USB_TIME_ATTDB if just powered up?
+
+    return 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;
+    u64 end = calc_future_tsc(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 (check_tsc(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
+ ****************************************************************/
+
+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)
+    u64 end = calc_future_tsc_usec(10);
+    writel(&cntl->regs->cmdstatus, OHCI_HCR);
+    for (;;) {
+        u32 status = readl(&cntl->regs->cmdstatus);
+        if (! status & OHCI_HCR)
+            break;
+        if (check_tsc(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_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);
+    free_pipe(cntl->usb.defaultpipe);
+    if (! count)
+        goto err;
+    return;
+
+err:
+    stop_ohci(cntl);
+free:
+    free(hcca);
+    free(intr_ed);
+}
+
+void
+ohci_init(struct pci_device *pci, int busid)
+{
+    if (! CONFIG_USB_OHCI)
+        return;
+    struct usb_ohci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+    if (!cntl) {
+        warn_noalloc();
+        return;
+    }
+    memset(cntl, 0, sizeof(*cntl));
+    cntl->usb.busid = busid;
+    cntl->usb.pci = pci;
+    cntl->usb.type = USB_TYPE_OHCI;
+
+    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);
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+static int
+wait_ed(struct ohci_ed *ed)
+{
+    // XXX - 500ms just a guess
+    u64 end = calc_future_tsc(500);
+    for (;;) {
+        if (ed->hwHeadP == ed->hwTailP)
+            return 0;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return -1;
+        }
+        yield();
+    }
+}
+
+// Wait for next USB frame to start - for ensuring safe memory release.
+static void
+ohci_waittick(struct usb_ohci_s *cntl)
+{
+    barrier();
+    struct ohci_hcca *hcca = (void*)cntl->regs->hcca;
+    u32 startframe = hcca->frame_no;
+    u64 end = calc_future_tsc(1000 * 5);
+    for (;;) {
+        if (hcca->frame_no != startframe)
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return;
+        }
+        yield();
+    }
+}
+
+static void
+signal_freelist(struct usb_ohci_s *cntl)
+{
+    u32 v = readl(&cntl->regs->control);
+    if (v & OHCI_CTRL_CLE) {
+        writel(&cntl->regs->control, v & ~(OHCI_CTRL_CLE|OHCI_CTRL_BLE));
+        ohci_waittick(cntl);
+        writel(&cntl->regs->ed_controlcurrent, 0);
+        writel(&cntl->regs->ed_bulkcurrent, 0);
+        writel(&cntl->regs->control, v);
+    } else {
+        ohci_waittick(cntl);
+    }
+}
+
+struct ohci_pipe {
+    struct ohci_ed ed;
+    struct usb_pipe pipe;
+    void *data;
+    int count;
+    struct ohci_td *tds;
+};
+
+void
+ohci_free_pipe(struct usb_pipe *p)
+{
+    if (! CONFIG_USB_OHCI)
+        return;
+    dprintf(7, "ohci_free_pipe %p\n", p);
+    struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+    struct usb_ohci_s *cntl = container_of(
+        pipe->pipe.cntl, struct usb_ohci_s, usb);
+
+    u32 *pos = &cntl->regs->ed_controlhead;
+    for (;;) {
+        struct ohci_ed *next = (void*)*pos;
+        if (!next) {
+            // Not found?!  Exit without freeing.
+            warn_internalerror();
+            return;
+        }
+        if (next == &pipe->ed) {
+            *pos = next->hwNextED;
+            signal_freelist(cntl);
+            free(pipe);
+            return;
+        }
+        pos = &next->hwNextED;
+    }
+}
+
+struct usb_pipe *
+ohci_alloc_control_pipe(struct usb_pipe *dummy)
+{
+    if (! CONFIG_USB_OHCI)
+        return NULL;
+    struct usb_ohci_s *cntl = container_of(
+        dummy->cntl, struct usb_ohci_s, usb);
+    dprintf(7, "ohci_alloc_control_pipe %p\n", &cntl->usb);
+
+    // Allocate a queue head.
+    struct ohci_pipe *pipe = malloc_tmphigh(sizeof(*pipe));
+    if (!pipe) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(pipe, 0, sizeof(*pipe));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    pipe->ed.hwINFO = ED_SKIP;
+
+    // Add queue head to controller list.
+    pipe->ed.hwNextED = cntl->regs->ed_controlhead;
+    barrier();
+    cntl->regs->ed_controlhead = (u32)&pipe->ed;
+    return &pipe->pipe;
+}
+
+int
+ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+             , void *data, int datasize)
+{
+    if (! CONFIG_USB_OHCI)
+        return -1;
+    dprintf(5, "ohci_control %p\n", p);
+    if (datasize > 4096) {
+        // XXX - should support larger sizes.
+        warn_noalloc();
+        return -1;
+    }
+    struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+    struct usb_ohci_s *cntl = container_of(
+        pipe->pipe.cntl, struct usb_ohci_s, usb);
+    int maxpacket = pipe->pipe.maxpacket;
+    int lowspeed = pipe->pipe.speed;
+    int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7);
+
+    // Setup transfer descriptors
+    struct ohci_td *tds = malloc_tmphigh(sizeof(*tds) * 3);
+    if (!tds) {
+        warn_noalloc();
+        return -1;
+    }
+    struct ohci_td *td = tds;
+    td->hwINFO = TD_DP_SETUP | TD_T_DATA0 | TD_CC;
+    td->hwCBP = (u32)cmd;
+    td->hwNextTD = (u32)&td[1];
+    td->hwBE = (u32)cmd + cmdsize - 1;
+    td++;
+    if (datasize) {
+        td->hwINFO = (dir ? TD_DP_IN : TD_DP_OUT) | TD_T_DATA1 | TD_CC;
+        td->hwCBP = (u32)data;
+        td->hwNextTD = (u32)&td[1];
+        td->hwBE = (u32)data + datasize - 1;
+        td++;
+    }
+    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.hwINFO = ED_SKIP;
+    barrier();
+    pipe->ed.hwHeadP = (u32)tds;
+    pipe->ed.hwTailP = (u32)td;
+    barrier();
+    pipe->ed.hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0);
+    writel(&cntl->regs->cmdstatus, OHCI_CLF);
+
+    int ret = wait_ed(&pipe->ed);
+    pipe->ed.hwINFO = ED_SKIP;
+    if (ret)
+        ohci_waittick(cntl);
+    free(tds);
+    return ret;
+}
+
+struct usb_pipe *
+ohci_alloc_bulk_pipe(struct usb_pipe *dummy)
+{
+    if (! CONFIG_USB_OHCI)
+        return NULL;
+    dprintf(1, "OHCI Bulk transfers not supported.\n");
+    return NULL;
+}
+
+int
+ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
+{
+    return -1;
+}
+
+struct usb_pipe *
+ohci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp)
+{
+    if (! CONFIG_USB_OHCI)
+        return NULL;
+    struct usb_ohci_s *cntl = container_of(
+        dummy->cntl, struct usb_ohci_s, usb);
+    dprintf(7, "ohci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
+
+    if (frameexp > 5)
+        frameexp = 5;
+    int maxpacket = dummy->maxpacket;
+    int lowspeed = dummy->speed;
+    int devaddr = dummy->devaddr | (dummy->ep << 7);
+    // Determine number of entries needed for 2 timer ticks.
+    int ms = 1<<frameexp;
+    int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * 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));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    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];
+    ed->hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0);
+
+    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.
+    barrier();
+    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;
+        intr_ed->hwNextED = (u32)ed;
+    } else {
+        int startpos = 1<<(frameexp-1);
+        ed->hwNextED = hcca->int_table[startpos];
+        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;
+}
+
+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_FLATPTR(pipe->tds);
+    struct ohci_td *head = (void*)(GET_FLATPTR(pipe->ed.hwHeadP) & ~(ED_C|ED_H));
+    struct ohci_td *tail = (void*)GET_FLATPTR(pipe->ed.hwTailP);
+    int count = GET_FLATPTR(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_FLATPTR(pipe->pipe.maxpacket);
+    void *pipedata = GET_FLATPTR(pipe->data);
+    void *intrdata = pipedata + maxpacket * pos;
+    memcpy_far(GET_SEG(SS), data
+               , FLATPTR_TO_SEG(intrdata), (void*)FLATPTR_TO_OFFSET(intrdata)
+               , maxpacket);
+
+    // Reenable this td.
+    SET_FLATPTR(tail->hwINFO, TD_DP_IN | TD_T_TOGGLE | TD_CC);
+    intrdata = pipedata + maxpacket * (tail-tds);
+    SET_FLATPTR(tail->hwCBP, (u32)intrdata);
+    SET_FLATPTR(tail->hwNextTD, (u32)next);
+    SET_FLATPTR(tail->hwBE, (u32)intrdata + maxpacket - 1);
+    barrier();
+    SET_FLATPTR(pipe->ed.hwTailP, (u32)next);
+
+    return 0;
+}
diff --git a/bios/seabios/src/usb-ohci.h b/bios/seabios/src/usb-ohci.h
new file mode 100644 (file)
index 0000000..c7670ff
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef __USB_OHCI_H
+#define __USB_OHCI_H
+
+// usb-ohci.c
+void ohci_init(struct pci_device *pci, int busid);
+struct usb_pipe;
+void ohci_free_pipe(struct usb_pipe *p);
+struct usb_pipe *ohci_alloc_control_pipe(struct usb_pipe *dummy);
+int ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+                 , void *data, int datasize);
+struct usb_pipe *ohci_alloc_bulk_pipe(struct usb_pipe *dummy);
+int ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize);
+struct usb_pipe *ohci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp);
+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_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/bios/seabios/src/usb-uhci.c b/bios/seabios/src/usb-uhci.c
new file mode 100644 (file)
index 0000000..f3680d3
--- /dev/null
@@ -0,0 +1,609 @@
+// 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 "util.h" // dprintf
+#include "pci.h" // pci_bdf_to_bus
+#include "config.h" // CONFIG_*
+#include "ioport.h" // outw
+#include "usb-uhci.h" // USBLEGSUP
+#include "pci_regs.h" // PCI_BASE_ADDRESS_4
+#include "usb.h" // struct usb_s
+#include "farptr.h" // GET_FLATPTR
+
+struct usb_uhci_s {
+    struct usb_s usb;
+    u16 iobase;
+    struct uhci_qh *control_qh, *bulk_qh;
+    struct uhci_framelist *framelist;
+};
+
+
+/****************************************************************
+ * 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
+        return -1;
+
+    // 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 0;
+}
+
+// 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
+ ****************************************************************/
+
+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_qh *intr_qh = malloc_high(sizeof(*intr_qh));
+    struct uhci_qh *term_qh = malloc_high(sizeof(*term_qh));
+    if (!term_td || !fl || !intr_qh || !term_qh) {
+        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_qh, 0, sizeof(*term_qh));
+    term_qh->element = (u32)term_td;
+    term_qh->link = UHCI_PTR_TERM;
+
+    // Set schedule to point to primary intr queue head
+    memset(intr_qh, 0, sizeof(*intr_qh));
+    intr_qh->element = UHCI_PTR_TERM;
+    intr_qh->link = (u32)term_qh | UHCI_PTR_QH;
+    int i;
+    for (i=0; i<ARRAY_SIZE(fl->links); i++)
+        fl->links[i] = (u32)intr_qh | UHCI_PTR_QH;
+    cntl->framelist = fl;
+    cntl->control_qh = cntl->bulk_qh = intr_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);
+    free_pipe(cntl->usb.defaultpipe);
+    if (count)
+        // Success
+        return;
+
+    // No devices found - shutdown and free controller.
+    outw(0, cntl->iobase + USBCMD);
+fail:
+    free(term_td);
+    free(fl);
+    free(intr_qh);
+    free(term_qh);
+    free(cntl);
+}
+
+void
+uhci_init(struct pci_device *pci, int busid)
+{
+    if (! CONFIG_USB_UHCI)
+        return;
+    u16 bdf = pci->bdf;
+    struct usb_uhci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+    if (!cntl) {
+        warn_noalloc();
+        return;
+    }
+    memset(cntl, 0, sizeof(*cntl));
+    cntl->usb.busid = busid;
+    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);
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+static int
+wait_qh(struct usb_uhci_s *cntl, struct uhci_qh *qh)
+{
+    // XXX - 500ms just a guess
+    u64 end = calc_future_tsc(500);
+    for (;;) {
+        if (qh->element & UHCI_PTR_TERM)
+            return 0;
+        if (check_tsc(end)) {
+            warn_timeout();
+            struct uhci_td *td = (void*)(qh->element & ~UHCI_PTR_BITS);
+            dprintf(1, "Timeout on wait_qh %p (td=%p s=%x c=%x/%x)\n"
+                    , qh, td, td->status
+                    , inw(cntl->iobase + USBCMD)
+                    , inw(cntl->iobase + USBSTS));
+            return -1;
+        }
+        yield();
+    }
+}
+
+// Wait for next USB frame to start - for ensuring safe memory release.
+static void
+uhci_waittick(u16 iobase)
+{
+    barrier();
+    u16 startframe = inw(iobase + USBFRNUM);
+    u64 end = calc_future_tsc(1000 * 5);
+    for (;;) {
+        if (inw(iobase + USBFRNUM) != startframe)
+            break;
+        if (check_tsc(end)) {
+            warn_timeout();
+            return;
+        }
+        yield();
+    }
+}
+
+struct uhci_pipe {
+    struct uhci_qh qh;
+    struct uhci_td *next_td;
+    struct usb_pipe pipe;
+    u16 iobase;
+    u8 toggle;
+};
+
+void
+uhci_free_pipe(struct usb_pipe *p)
+{
+    if (! CONFIG_USB_UHCI)
+        return;
+    dprintf(7, "uhci_free_pipe %p\n", p);
+    struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+    struct usb_uhci_s *cntl = container_of(
+        pipe->pipe.cntl, struct usb_uhci_s, usb);
+
+    struct uhci_qh *pos = (void*)(cntl->framelist->links[0] & ~UHCI_PTR_BITS);
+    for (;;) {
+        u32 link = pos->link;
+        if (link == UHCI_PTR_TERM) {
+            // Not found?!  Exit without freeing.
+            warn_internalerror();
+            return;
+        }
+        struct uhci_qh *next = (void*)(link & ~UHCI_PTR_BITS);
+        if (next == &pipe->qh) {
+            pos->link = next->link;
+            if (cntl->control_qh == next)
+                cntl->control_qh = pos;
+            if (cntl->bulk_qh == next)
+                cntl->bulk_qh = pos;
+            uhci_waittick(cntl->iobase);
+            free(pipe);
+            return;
+        }
+        pos = next;
+    }
+}
+
+struct usb_pipe *
+uhci_alloc_control_pipe(struct usb_pipe *dummy)
+{
+    if (! CONFIG_USB_UHCI)
+        return NULL;
+    struct usb_uhci_s *cntl = container_of(
+        dummy->cntl, struct usb_uhci_s, usb);
+    dprintf(7, "uhci_alloc_control_pipe %p\n", &cntl->usb);
+
+    // Allocate a queue head.
+    struct uhci_pipe *pipe = malloc_tmphigh(sizeof(*pipe));
+    if (!pipe) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(pipe, 0, sizeof(*pipe));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    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 (cntl->bulk_qh == control_qh)
+        cntl->bulk_qh = &pipe->qh;
+    return &pipe->pipe;
+}
+
+int
+uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+             , void *data, int datasize)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_USB_UHCI)
+        return -1;
+    dprintf(5, "uhci_control %p\n", p);
+    struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+    struct usb_uhci_s *cntl = container_of(
+        pipe->pipe.cntl, struct usb_uhci_s, usb);
+
+    int maxpacket = pipe->pipe.maxpacket;
+    int lowspeed = pipe->pipe.speed;
+    int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7);
+
+    // Setup transfer descriptors
+    int count = 2 + DIV_ROUND_UP(datasize, maxpacket);
+    struct uhci_td *tds = malloc_tmphigh(sizeof(*tds) * count);
+    if (!tds) {
+        warn_noalloc();
+        return -1;
+    }
+
+    tds[0].link = (u32)&tds[1] | UHCI_PTR_DEPTH;
+    tds[0].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+                     | TD_CTRL_ACTIVE);
+    tds[0].token = (uhci_explen(cmdsize) | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+                    | USB_PID_SETUP);
+    tds[0].buffer = (void*)cmd;
+    int toggle = TD_TOKEN_TOGGLE;
+    int i;
+    for (i=1; i<count-1; i++) {
+        tds[i].link = (u32)&tds[i+1] | UHCI_PTR_DEPTH;
+        tds[i].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+                         | TD_CTRL_ACTIVE);
+        int len = (i == count-2 ? (datasize - (i-1)*maxpacket) : maxpacket);
+        tds[i].token = (uhci_explen(len) | toggle
+                        | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+                        | (dir ? USB_PID_IN : USB_PID_OUT));
+        tds[i].buffer = data + (i-1) * maxpacket;
+        toggle ^= TD_TOKEN_TOGGLE;
+    }
+    tds[i].link = UHCI_PTR_TERM;
+    tds[i].status = (uhci_maxerr(0) | (lowspeed ? TD_CTRL_LS : 0)
+                     | TD_CTRL_ACTIVE);
+    tds[i].token = (uhci_explen(0) | TD_TOKEN_TOGGLE
+                    | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+                    | (dir ? USB_PID_OUT : USB_PID_IN));
+    tds[i].buffer = 0;
+
+    // Transfer data
+    barrier();
+    pipe->qh.element = (u32)&tds[0];
+    int ret = wait_qh(cntl, &pipe->qh);
+    if (ret) {
+        pipe->qh.element = UHCI_PTR_TERM;
+        uhci_waittick(pipe->iobase);
+    }
+    free(tds);
+    return ret;
+}
+
+struct usb_pipe *
+uhci_alloc_bulk_pipe(struct usb_pipe *dummy)
+{
+    if (! CONFIG_USB_UHCI)
+        return NULL;
+    struct usb_uhci_s *cntl = container_of(
+        dummy->cntl, struct usb_uhci_s, usb);
+    dprintf(7, "uhci_alloc_bulk_pipe %p\n", &cntl->usb);
+
+    // Allocate a queue head.
+    struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
+    if (!pipe) {
+        warn_noalloc();
+        return NULL;
+    }
+    memset(pipe, 0, sizeof(*pipe));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    pipe->qh.element = UHCI_PTR_TERM;
+    pipe->iobase = cntl->iobase;
+
+    // Add queue head to controller list.
+    struct uhci_qh *bulk_qh = cntl->bulk_qh;
+    pipe->qh.link = bulk_qh->link;
+    barrier();
+    bulk_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+
+    return &pipe->pipe;
+}
+
+static int
+wait_td(struct uhci_td *td)
+{
+    u64 end = calc_future_tsc(5000); // XXX - lookup real time.
+    u32 status;
+    for (;;) {
+        status = td->status;
+        if (!(status & TD_CTRL_ACTIVE))
+            break;
+        if (check_tsc(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 4
+#define TDALIGN 16
+
+int
+uhci_send_bulk(struct usb_pipe *p, int dir, 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_bulk qh=%p dir=%d data=%p size=%d\n"
+            , &pipe->qh, dir, data, datasize);
+    int maxpacket = GET_FLATPTR(pipe->pipe.maxpacket);
+    int lowspeed = GET_FLATPTR(pipe->pipe.speed);
+    int devaddr = (GET_FLATPTR(pipe->pipe.devaddr)
+                   | (GET_FLATPTR(pipe->pipe.ep) << 7));
+    int toggle = GET_FLATPTR(pipe->toggle) ? TD_TOKEN_TOGGLE : 0;
+
+    // Allocate 4 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);
+
+    // Enable tds
+    barrier();
+    SET_FLATPTR(pipe->qh.element, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
+
+    int tdpos = 0;
+    while (datasize) {
+        struct uhci_td *td = &tds[tdpos++ % STACKTDS];
+        int ret = wait_td(td);
+        if (ret)
+            goto fail;
+
+        int transfer = datasize;
+        if (transfer > maxpacket)
+            transfer = maxpacket;
+        struct uhci_td *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS)
+                                                 , &tds[tdpos % STACKTDS]);
+        td->link = (transfer==datasize ? UHCI_PTR_TERM : (u32)nexttd_fl);
+        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;
+    }
+    int i;
+    for (i=0; i<STACKTDS; i++) {
+        struct uhci_td *td = &tds[tdpos++ % STACKTDS];
+        int ret = wait_td(td);
+        if (ret)
+            goto fail;
+    }
+
+    SET_FLATPTR(pipe->toggle, !!toggle);
+    return 0;
+fail:
+    dprintf(1, "uhci_send_bulk failed\n");
+    SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM);
+    uhci_waittick(GET_FLATPTR(pipe->iobase));
+    return -1;
+}
+
+struct usb_pipe *
+uhci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp)
+{
+    if (! CONFIG_USB_UHCI)
+        return NULL;
+    struct usb_uhci_s *cntl = container_of(
+        dummy->cntl, struct usb_uhci_s, usb);
+    dprintf(7, "uhci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
+
+    if (frameexp > 10)
+        frameexp = 10;
+    int maxpacket = dummy->maxpacket;
+    int lowspeed = dummy->speed;
+    int devaddr = dummy->devaddr | (dummy->ep << 7);
+    // Determine number of entries needed for 2 timer ticks.
+    int ms = 1<<frameexp;
+    int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * 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));
+    memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+    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;
+        if (cntl->bulk_qh == intr_qh)
+            cntl->bulk_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;
+}
+
+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_FLATPTR(pipe->next_td);
+    u32 status = GET_FLATPTR(td->status);
+    u32 token = GET_FLATPTR(td->token);
+    if (status & TD_CTRL_ACTIVE)
+        // No intrs found.
+        return -1;
+    // XXX - check for errors.
+
+    // Copy data.
+    void *tddata = GET_FLATPTR(td->buffer);
+    memcpy_far(GET_SEG(SS), data
+               , FLATPTR_TO_SEG(tddata), (void*)FLATPTR_TO_OFFSET(tddata)
+               , uhci_expected_length(token));
+
+    // Reenable this td.
+    struct uhci_td *next = (void*)(GET_FLATPTR(td->link) & ~UHCI_PTR_BITS);
+    SET_FLATPTR(pipe->next_td, next);
+    barrier();
+    SET_FLATPTR(td->status, (uhci_maxerr(0) | (status & TD_CTRL_LS)
+                             | TD_CTRL_ACTIVE));
+
+    return 0;
+}
diff --git a/bios/seabios/src/usb-uhci.h b/bios/seabios/src/usb-uhci.h
new file mode 100644 (file)
index 0000000..b5f70f7
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef __USB_UHCI_H
+#define __USB_UHCI_H
+
+// usb-uhci.c
+void uhci_init(struct pci_device *pci, int busid);
+struct usb_pipe;
+void uhci_free_pipe(struct usb_pipe *p);
+struct usb_pipe *uhci_alloc_control_pipe(struct usb_pipe *dummy);
+int uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+                 , void *data, int datasize);
+struct usb_pipe *uhci_alloc_bulk_pipe(struct usb_pipe *dummy);
+int uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize);
+struct usb_pipe *uhci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp);
+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/bios/seabios/src/usb.c b/bios/seabios/src/usb.c
new file mode 100644 (file)
index 0000000..1f69d16
--- /dev/null
@@ -0,0 +1,468 @@
+// Main code for handling USB controllers and devices.
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // foreachpci
+#include "config.h" // CONFIG_*
+#include "pci_regs.h" // PCI_CLASS_REVISION
+#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI
+#include "usb-uhci.h" // uhci_init
+#include "usb-ohci.h" // ohci_init
+#include "usb-ehci.h" // ehci_init
+#include "usb-hid.h" // usb_keyboard_setup
+#include "usb-hub.h" // usb_hub_init
+#include "usb-msc.h" // usb_msc_init
+#include "usb.h" // struct usb_s
+#include "biosvar.h" // GET_GLOBAL
+
+
+/****************************************************************
+ * Controller function wrappers
+ ****************************************************************/
+
+// Free an allocated control or bulk pipe.
+void
+free_pipe(struct usb_pipe *pipe)
+{
+    ASSERT32FLAT();
+    if (!pipe)
+        return;
+    switch (pipe->type) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_free_pipe(pipe);
+    case USB_TYPE_OHCI:
+        return ohci_free_pipe(pipe);
+    case USB_TYPE_EHCI:
+        return ehci_free_pipe(pipe);
+    }
+}
+
+// Allocate a control pipe to a default endpoint (which can only be
+// used by 32bit code)
+static struct usb_pipe *
+alloc_default_control_pipe(struct usb_pipe *dummy)
+{
+    switch (dummy->type) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_alloc_control_pipe(dummy);
+    case USB_TYPE_OHCI:
+        return ohci_alloc_control_pipe(dummy);
+    case USB_TYPE_EHCI:
+        return ehci_alloc_control_pipe(dummy);
+    }
+}
+
+// Send a message on a control pipe using the default control descriptor.
+static int
+send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize
+             , void *data, int datasize)
+{
+    ASSERT32FLAT();
+    switch (pipe->type) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_control(pipe, dir, cmd, cmdsize, data, datasize);
+    case USB_TYPE_OHCI:
+        return ohci_control(pipe, dir, cmd, cmdsize, data, datasize);
+    case USB_TYPE_EHCI:
+        return ehci_control(pipe, dir, cmd, cmdsize, data, datasize);
+    }
+}
+
+// Fill "pipe" endpoint info from an endpoint descriptor.
+static void
+desc2pipe(struct usb_pipe *newpipe, struct usb_pipe *origpipe
+          , struct usb_endpoint_descriptor *epdesc)
+{
+    memcpy(newpipe, origpipe, sizeof(*newpipe));
+    newpipe->ep = epdesc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+    newpipe->maxpacket = epdesc->wMaxPacketSize;
+}
+
+struct usb_pipe *
+alloc_bulk_pipe(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
+{
+    struct usb_pipe dummy;
+    desc2pipe(&dummy, pipe, epdesc);
+    switch (pipe->type) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_alloc_bulk_pipe(&dummy);
+    case USB_TYPE_OHCI:
+        return ohci_alloc_bulk_pipe(&dummy);
+    case USB_TYPE_EHCI:
+        return ehci_alloc_bulk_pipe(&dummy);
+    }
+}
+
+int
+usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize)
+{
+    switch (GET_FLATPTR(pipe_fl->type)) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_send_bulk(pipe_fl, dir, data, datasize);
+    case USB_TYPE_OHCI:
+        return ohci_send_bulk(pipe_fl, dir, data, datasize);
+    case USB_TYPE_EHCI:
+        return ehci_send_bulk(pipe_fl, dir, data, datasize);
+    }
+}
+
+struct usb_pipe *
+alloc_intr_pipe(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
+{
+    struct usb_pipe dummy;
+    desc2pipe(&dummy, pipe, epdesc);
+    // Find the exponential period of the requested time.
+    int period = epdesc->bInterval;
+    int frameexp;
+    if (pipe->speed != USB_HIGHSPEED)
+        frameexp = (period <= 0) ? 0 : __fls(period);
+    else
+        frameexp = (period <= 4) ? 0 : period - 4;
+    switch (pipe->type) {
+    default:
+    case USB_TYPE_UHCI:
+        return uhci_alloc_intr_pipe(&dummy, frameexp);
+    case USB_TYPE_OHCI:
+        return ohci_alloc_intr_pipe(&dummy, frameexp);
+    case USB_TYPE_EHCI:
+        return ehci_alloc_intr_pipe(&dummy, frameexp);
+    }
+}
+
+int noinline
+usb_poll_intr(struct usb_pipe *pipe_fl, void *data)
+{
+    switch (GET_FLATPTR(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);
+    }
+}
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Find the first endpoing of a given type in an interface description.
+struct usb_endpoint_descriptor *
+findEndPointDesc(struct usb_interface_descriptor *iface, int imax
+                 , int type, int dir)
+{
+    struct usb_endpoint_descriptor *epdesc = (void*)&iface[1];
+    for (;;) {
+        if ((void*)epdesc >= (void*)iface + 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;
+    }
+}
+
+// Send a message to the default control pipe of a device.
+int
+send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
+                     , void *data)
+{
+    return send_control(pipe, req->bRequestType & USB_DIR_IN
+                        , req, sizeof(*req), data, req->wLength);
+}
+
+// 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 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 = 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 = send_default_control(pipe, &req, config);
+    if (ret)
+        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 send_default_control(pipe, &req, NULL);
+}
+
+
+/****************************************************************
+ * Initialization and enumeration
+ ****************************************************************/
+
+// Assign an address to a device in the default state on the given
+// controller.
+static struct usb_pipe *
+usb_set_address(struct usbhub_s *hub, int port, int speed)
+{
+    ASSERT32FLAT();
+    struct usb_s *cntl = hub->cntl;
+    dprintf(3, "set_address %p\n", cntl);
+    if (cntl->maxaddr >= USB_MAXADDR)
+        return NULL;
+
+    struct usb_pipe *defpipe = cntl->defaultpipe;
+    if (!defpipe) {
+        // Create a pipe for the default address.
+        struct usb_pipe dummy;
+        memset(&dummy, 0, sizeof(dummy));
+        dummy.cntl = cntl;
+        dummy.type = cntl->type;
+        dummy.maxpacket = 8;
+        dummy.path = (u64)-1;
+        cntl->defaultpipe = defpipe = alloc_default_control_pipe(&dummy);
+        if (!defpipe)
+            return NULL;
+    }
+    defpipe->speed = speed;
+    if (hub->pipe) {
+        if (hub->pipe->speed == USB_HIGHSPEED) {
+            defpipe->tt_devaddr = hub->pipe->devaddr;
+            defpipe->tt_port = port;
+        } else {
+            defpipe->tt_devaddr = hub->pipe->tt_devaddr;
+            defpipe->tt_port = hub->pipe->tt_port;
+        }
+    } else {
+        defpipe->tt_devaddr = defpipe->tt_port = 0;
+    }
+
+    msleep(USB_TIME_RSTRCY);
+
+    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 = send_default_control(defpipe, &req, NULL);
+    if (ret)
+        return NULL;
+
+    msleep(USB_TIME_SETADDR_RECOVERY);
+
+    cntl->maxaddr++;
+    defpipe->devaddr = cntl->maxaddr;
+    struct usb_pipe *pipe = alloc_default_control_pipe(defpipe);
+    defpipe->devaddr = 0;
+    if (hub->pipe)
+        pipe->path = hub->pipe->path;
+    pipe->path = (pipe->path << 8) | port;
+    return pipe;
+}
+
+// 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 usb_pipe *pipe)
+{
+    ASSERT32FLAT();
+    dprintf(3, "config_usb: %p\n", pipe);
+
+    // Set the max packet size for endpoint 0 of this device.
+    struct usb_device_descriptor dinfo;
+    int ret = get_device_info8(pipe, &dinfo);
+    if (ret)
+        return 0;
+    dprintf(3, "device rev=%04x cls=%02x sub=%02x proto=%02x size=%02x\n"
+            , dinfo.bcdUSB, dinfo.bDeviceClass, dinfo.bDeviceSubClass
+            , dinfo.bDeviceProtocol, dinfo.bMaxPacketSize0);
+    if (dinfo.bMaxPacketSize0 < 8 || dinfo.bMaxPacketSize0 > 64)
+        return 0;
+    pipe->maxpacket = dinfo.bMaxPacketSize0;
+
+    // Get configuration
+    struct usb_config_descriptor *config = get_device_config(pipe);
+    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(pipe, config->bConfigurationValue);
+    if (ret)
+        goto fail;
+
+    // Configure driver.
+    int imax = (void*)config + config->wTotalLength - (void*)iface;
+    if (iface->bInterfaceClass == USB_CLASS_HUB)
+        ret = usb_hub_init(pipe);
+    else if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE)
+        ret = usb_msc_init(pipe, iface, imax);
+    else
+        ret = usb_hid_init(pipe, iface, imax);
+    if (ret)
+        goto fail;
+
+    free(config);
+    return 1;
+fail:
+    free(config);
+    return 0;
+}
+
+static void
+usb_init_hub_port(void *data)
+{
+    struct usbhub_s *hub = data;
+    u32 port = hub->port; // XXX - find better way to pass port
+
+    // Detect if device present (and possibly start reset)
+    int ret = hub->op->detect(hub, port);
+    if (ret)
+        // No device present
+        goto done;
+
+    // Reset port and determine device speed
+    mutex_lock(&hub->cntl->resetlock);
+    ret = hub->op->reset(hub, port);
+    if (ret < 0)
+        // Reset failed
+        goto resetfail;
+
+    // Set address of port
+    struct usb_pipe *pipe = usb_set_address(hub, port, ret);
+    if (!pipe) {
+        hub->op->disconnect(hub, port);
+        goto resetfail;
+    }
+    mutex_unlock(&hub->cntl->resetlock);
+
+    // Configure the device
+    int count = configure_usb_device(pipe);
+    free_pipe(pipe);
+    if (!count)
+        hub->op->disconnect(hub, port);
+    hub->devcount += count;
+done:
+    hub->threads--;
+    return;
+
+resetfail:
+    mutex_unlock(&hub->cntl->resetlock);
+    goto done;
+}
+
+void
+usb_enumerate(struct usbhub_s *hub)
+{
+    u32 portcount = hub->portcount;
+    hub->threads = portcount;
+
+    // Launch a thread for every port.
+    int i;
+    for (i=0; i<portcount; i++) {
+        hub->port = i;
+        run_thread(usb_init_hub_port, hub);
+    }
+
+    // Wait for threads to complete.
+    while (hub->threads)
+        yield();
+}
+
+void
+usb_setup(void)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_USB)
+        return;
+
+    dprintf(3, "init usb\n");
+
+    // Look for USB controllers
+    int count = 0;
+    struct pci_device *ehcipci = PCIDevices;
+    struct pci_device *pci;
+    foreachpci(pci) {
+        if (pci->class != PCI_CLASS_SERIAL_USB)
+            continue;
+
+        if (pci->bdf >= ehcipci->bdf) {
+            // Check to see if this device has an ehci controller
+            int found = 0;
+            ehcipci = pci;
+            for (;;) {
+                if (pci_classprog(ehcipci) == PCI_CLASS_SERIAL_USB_EHCI) {
+                    // Found an ehci controller.
+                    int ret = ehci_init(ehcipci, count++, pci);
+                    if (ret)
+                        // Error
+                        break;
+                    count += found;
+                    pci = ehcipci;
+                    break;
+                }
+                if (ehcipci->class == PCI_CLASS_SERIAL_USB)
+                    found++;
+                ehcipci = ehcipci->next;
+                if (!ehcipci || (pci_bdf_to_busdev(ehcipci->bdf)
+                                 != pci_bdf_to_busdev(pci->bdf)))
+                    // No ehci controller found.
+                    break;
+            }
+        }
+
+        if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_UHCI)
+            uhci_init(pci, count++);
+        else if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_OHCI)
+            ohci_init(pci, count++);
+    }
+}
diff --git a/bios/seabios/src/usb.h b/bios/seabios/src/usb.h
new file mode 100644 (file)
index 0000000..8b2af40
--- /dev/null
@@ -0,0 +1,216 @@
+// USB functions and data.
+#ifndef __USB_H
+#define __USB_H
+
+#include "util.h" // struct mutex_s
+
+// Information on a USB end point.
+struct usb_pipe {
+    struct usb_s *cntl;
+    u64 path;
+    u8 type;
+    u8 ep;
+    u8 devaddr;
+    u8 speed;
+    u16 maxpacket;
+    u8 tt_devaddr;
+    u8 tt_port;
+};
+
+// Common information for usb controllers.
+struct usb_s {
+    struct usb_pipe *defaultpipe;
+    struct mutex_s resetlock;
+    struct pci_device *pci;
+    int busid;
+    u8 type;
+    u8 maxaddr;
+};
+
+// Information for enumerating USB hubs
+struct usbhub_s {
+    struct usbhub_op_s *op;
+    struct usb_pipe *pipe;
+    struct usb_s *cntl;
+    struct mutex_s lock;
+    u32 powerwait;
+    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_FULLSPEED 0
+#define USB_LOWSPEED  1
+#define USB_HIGHSPEED 2
+
+#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_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
+
+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
+
+
+/****************************************************************
+ * function defs
+ ****************************************************************/
+
+// usb.c
+void usb_setup(void);
+void usb_enumerate(struct usbhub_s *hub);
+int send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
+                         , void *data);
+int usb_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize);
+void free_pipe(struct usb_pipe *pipe);
+struct usb_pipe *alloc_bulk_pipe(struct usb_pipe *pipe
+                                 , struct usb_endpoint_descriptor *epdesc);
+struct usb_pipe *alloc_intr_pipe(struct usb_pipe *pipe
+                                 , struct usb_endpoint_descriptor *epdesc);
+int usb_poll_intr(struct usb_pipe *pipe, void *data);
+struct usb_endpoint_descriptor *findEndPointDesc(
+    struct usb_interface_descriptor *iface, int imax, int type, int dir);
+u32 mkendpFromDesc(struct usb_pipe *pipe
+                   , struct usb_endpoint_descriptor *epdesc);
+
+#endif // usb.h
diff --git a/bios/seabios/src/util.c b/bios/seabios/src/util.c
new file mode 100644 (file)
index 0000000..ed73d63
--- /dev/null
@@ -0,0 +1,324 @@
+// Misc utility functions.
+//
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // call16
+#include "bregs.h" // struct bregs
+#include "config.h" // BUILD_STACK_ADDR
+
+
+/****************************************************************
+ * 16bit calls
+ ****************************************************************/
+
+// Call a function with a specified register state.  Note that on
+// return, the interrupt enable/disable flag may be altered.
+inline void
+call16(struct bregs *callregs)
+{
+    if (!MODESEGMENT && getesp() > BUILD_STACK_ADDR)
+        panic("call16 with invalid stack\n");
+    asm volatile(
+#if MODE16 == 1
+        "calll __call16\n"
+        "cli\n"
+        "cld"
+#else
+        "calll __call16_from32"
+#endif
+        : "+a" (callregs), "+m" (*callregs)
+        :
+        : "ebx", "ecx", "edx", "esi", "edi", "cc", "memory");
+}
+
+inline void
+call16big(struct bregs *callregs)
+{
+    ASSERT32FLAT();
+    if (getesp() > BUILD_STACK_ADDR)
+        panic("call16 with invalid stack\n");
+    asm volatile(
+        "calll __call16big_from32"
+        : "+a" (callregs), "+m" (*callregs)
+        :
+        : "ebx", "ecx", "edx", "esi", "edi", "cc", "memory");
+}
+
+inline void
+__call16_int(struct bregs *callregs, u16 offset)
+{
+    if (MODESEGMENT)
+        callregs->code.seg = GET_SEG(CS);
+    else
+        callregs->code.seg = SEG_BIOS;
+    callregs->code.offset = offset;
+    call16(callregs);
+}
+
+
+/****************************************************************
+ * 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;
+}
+
+// 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)
+        : "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)
+        : "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)
+        : "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)
+            : : "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)
+        : : "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)
+{
+    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)
+void
+nullTrailingSpace(char *buf)
+{
+    int len = strlen(buf);
+    char *end = &buf[len-1];
+    while (end >= buf && *end <= ' ')
+        *(end--) = '\0';
+}
+
+/****************************************************************
+ * 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;
+    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.
+int
+get_keystroke(int msec)
+{
+    u32 end = calc_future_timer(msec);
+    for (;;) {
+        if (check_for_keystroke())
+            return get_raw_keystroke();
+        if (check_timer(end))
+            return -1;
+        wait_irq();
+    }
+}
diff --git a/bios/seabios/src/util.h b/bios/seabios/src/util.h
new file mode 100644 (file)
index 0000000..174e94b
--- /dev/null
@@ -0,0 +1,484 @@
+// Basic x86 asm functions and function defs.
+//
+// Copyright (C) 2008-2010  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __UTIL_H
+#define __UTIL_H
+
+#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 unsigned long irq_save(void)
+{
+    unsigned long flags;
+    asm volatile("pushfl ; popl %0" : "=g" (flags): :"memory");
+    irq_disable();
+    return flags;
+}
+
+static inline void irq_restore(unsigned long 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_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 u16 __htons_constant(u16 val) {
+    return (val<<8) | (val>>8);
+}
+static inline u32 __htonl_constant(u32 val) {
+    return (val<<24) | ((val&0xff00)<<8) | ((val&0xff0000)>>8) | (val>>24);
+}
+static inline u32 __htonl(u32 val) {
+    asm("bswapl %0" : "+r"(val));
+    return val;
+}
+#define htonl(x) (__builtin_constant_p((u32)(x)) ? __htonl_constant(x) : __htonl(x))
+#define ntohl(x) htonl(x)
+#define htons(x) __htons_constant(x)
+#define ntohs(x) htons(x)
+
+static inline u16 cpu_to_le16(u16 x)
+{
+    return x;
+}
+
+static inline u32 cpu_to_le32(u32 x)
+{
+    return x;
+}
+
+static inline u32 getesp(void) {
+    u32 esp;
+    asm("movl %%esp, %0" : "=rm"(esp));
+    return esp;
+}
+
+static inline void writel(void *addr, u32 val) {
+    *(volatile u32 *)addr = val;
+}
+static inline void writew(void *addr, u16 val) {
+    *(volatile u16 *)addr = val;
+}
+static inline void writeb(void *addr, u8 val) {
+    *(volatile u8 *)addr = val;
+}
+static inline u32 readl(const void *addr) {
+    return *(volatile const u32 *)addr;
+}
+static inline u16 readw(const void *addr) {
+    return *(volatile const u16 *)addr;
+}
+static inline u8 readb(const void *addr) {
+    return *(volatile const u8 *)addr;
+}
+
+#define call16_simpint(nr, peax, pflags) do {                           \
+        ASSERT16();                                                     \
+        asm volatile(                                                   \
+            "pushl %%ebp\n"                                             \
+            "sti\n"                                                     \
+            "stc\n"                                                     \
+            "int %2\n"                                                  \
+            "pushfl\n"                                                  \
+            "popl %1\n"                                                 \
+            "cli\n"                                                     \
+            "cld\n"                                                     \
+            "popl %%ebp"                                                \
+            : "+a"(*peax), "=c"(*pflags)                                \
+            : "i"(nr)                                                   \
+            : "ebx", "edx", "esi", "edi", "cc", "memory");              \
+    } while (0)
+
+// 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;
+
+// util.c
+struct bregs;
+inline void call16(struct bregs *callregs);
+inline void call16big(struct bregs *callregs);
+inline 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)
+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(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);
+void nullTrailingSpace(char *buf);
+int get_keystroke(int msec);
+
+// stacks.c
+u32 call32(void *func, u32 eax, u32 errret);
+inline u32 stack_hop(u32 eax, u32 edx, void *func);
+extern struct thread_info MainThread;
+extern int CanPreempt;
+struct thread_info *getCurThread(void);
+void yield(void);
+void wait_irq(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);
+
+// output.c
+void debug_serial_setup(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)));
+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__)
+
+// kbd.c
+void kbd_setup(void);
+void handle_15c2(struct bregs *regs);
+void process_key(u8 key);
+
+// mouse.c
+void mouse_setup(void);
+void process_mouse(u8 data);
+
+// system.c
+extern u32 RamSize;
+extern u64 RamSizeOver4G;
+void mathcp_setup(void);
+
+// serial.c
+void serial_setup(void);
+void lpt_setup(void);
+
+// clock.c
+#define PIT_TICK_RATE 1193180   // Underlying HZ of PIT
+#define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer
+static inline int check_tsc(u64 end) {
+    return (s64)(rdtscll() - end) > 0;
+}
+void timer_setup(void);
+void ndelay(u32 count);
+void udelay(u32 count);
+void mdelay(u32 count);
+void nsleep(u32 count);
+void usleep(u32 count);
+void msleep(u32 count);
+u64 calc_future_tsc(u32 msecs);
+u64 calc_future_tsc_usec(u32 usecs);
+u32 calc_future_timer_ticks(u32 count);
+u32 calc_future_timer(u32 msecs);
+int check_timer(u32 end);
+void handle_1583(struct bregs *regs);
+void handle_1586(struct bregs *regs);
+void useRTC(void);
+void releaseRTC(void);
+
+// apm.c
+void apm_shutdown(void);
+void handle_1553(struct bregs *regs);
+
+// pcibios.c
+void handle_1ab1(struct bregs *regs);
+void bios32_setup(void);
+
+// shadow.c
+void make_bios_writable(void);
+void make_bios_readonly(void);
+void qemu_prep_reset(void);
+
+// pciinit.c
+extern const u8 pci_irqs[4];
+void pci_setup(void);
+
+// smm.c
+void smm_init(void);
+
+// smp.c
+extern u32 CountCPUs;
+extern u32 MaxCountCPUs;
+void wrmsr_smp(u32 index, u64 val);
+void smp_probe(void);
+
+// coreboot.c
+extern const char *CBvendor, *CBpart;
+struct cbfs_file;
+struct cbfs_file *cbfs_finddatafile(const char *fname);
+struct cbfs_file *cbfs_findprefix(const char *prefix, struct cbfs_file *last);
+u32 cbfs_datasize(struct cbfs_file *file);
+const char *cbfs_filename(struct cbfs_file *file);
+int cbfs_copyfile(struct cbfs_file *file, void *dst, u32 maxlen);
+void cbfs_run_payload(struct cbfs_file *file);
+void coreboot_copy_biostable(void);
+void cbfs_payload_setup(void);
+void coreboot_setup(void);
+
+// biostable.c
+void copy_pir(void *pos);
+void copy_mptable(void *pos);
+void copy_acpi_rsdp(void *pos);
+void copy_smbios(void *pos);
+
+// vgahooks.c
+void handle_155f(struct bregs *regs);
+struct pci_device;
+void vgahook_setup(struct pci_device *pci);
+
+// optionroms.c
+void call_bcv(u16 seg, u16 ip);
+void optionrom_setup(void);
+void vga_setup(void);
+void s3_resume_vga_init(void);
+extern u32 RomEnd;
+extern int ScreenAndDebug;
+
+// bootsplash.c
+void enable_vga_console(void);
+void enable_bootsplash(void);
+void disable_bootsplash(void);
+
+// resume.c
+extern int HaveRunPost;
+void init_dma(void);
+
+// pnpbios.c
+#define PNP_SIGNATURE 0x506e5024 // $PnP
+u16 get_pnp_offset(void);
+void pnp_setup(void);
+
+// pmm.c
+extern struct zone_s ZoneLow, ZoneHigh, ZoneFSeg, ZoneTmpLow, ZoneTmpHigh;
+void malloc_setup(void);
+void malloc_fixupreloc(void);
+void malloc_finalize(void);
+void *pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align);
+int pmm_free(void *data);
+void pmm_setup(void);
+void pmm_finalize(void);
+#define PMM_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 pmm_malloc(&ZoneLow, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_high(u32 size) {
+    return pmm_malloc(&ZoneHigh, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_fseg(u32 size) {
+    return pmm_malloc(&ZoneFSeg, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_tmplow(u32 size) {
+    return pmm_malloc(&ZoneTmpLow, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_tmphigh(u32 size) {
+    return pmm_malloc(&ZoneTmpHigh, PMM_DEFAULT_HANDLE, 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 pmm_malloc(&ZoneLow, PMM_DEFAULT_HANDLE, size, align);
+}
+static inline void *memalign_high(u32 align, u32 size) {
+    return pmm_malloc(&ZoneHigh, PMM_DEFAULT_HANDLE, size, align);
+}
+static inline void *memalign_tmplow(u32 align, u32 size) {
+    return pmm_malloc(&ZoneTmpLow, PMM_DEFAULT_HANDLE, size, align);
+}
+static inline void *memalign_tmphigh(u32 align, u32 size) {
+    return pmm_malloc(&ZoneTmpHigh, PMM_DEFAULT_HANDLE, 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) {
+    pmm_free(data);
+}
+
+// mtrr.c
+void mtrr_setup(void);
+
+// romlayout.S
+void reset_vector(void) __noreturn;
+
+// misc.c
+extern u8 BiosChecksum;
+
+// version (auto generated file out/version.c)
+extern const char VERSION[];
+
+#endif // util.h
diff --git a/bios/seabios/src/vgahooks.c b/bios/seabios/src/vgahooks.c
new file mode 100644 (file)
index 0000000..a8f667c
--- /dev/null
@@ -0,0 +1,268 @@
+// 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 "bregs.h" // set_code_invalid
+#include "biosvar.h" // GET_GLOBAL
+#include "pci.h" // pci_find_device
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "pci_ids.h" // PCI_VENDOR_ID_VIA
+#include "util.h" // handle_155f
+#include "config.h" // CONFIG_*
+
+#define VH_VIA 1
+#define VH_INTEL 2
+
+int VGAHookHandlerType VAR16VISIBLE;
+
+static void
+handle_155fXX(struct bregs *regs)
+{
+    set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+
+/****************************************************************
+ * Via hooks
+ ****************************************************************/
+
+int ViaFBsize VAR16VISIBLE, ViaRamSpeed VAR16VISIBLE;
+
+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 VAR16VISIBLE, IntelDisplayId VAR16VISIBLE;
+
+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_155f(struct bregs *regs)
+{
+    switch (regs->al) {
+    case 0x35: intel_155f35(regs); break;
+    case 0x40: intel_155f40(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
+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)
+{
+}
+
+
+/****************************************************************
+ * 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;
+    }
+}
+
+// Setup
+void
+vgahook_setup(struct pci_device *pci)
+{
+    if (!CONFIG_VGAHOOKS || !CBvendor || !CBpart)
+        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 (pci->vendor == PCI_VENDOR_ID_VIA)
+        via_setup(pci);
+}
diff --git a/bios/seabios/src/virtio-blk.c b/bios/seabios/src/virtio-blk.c
new file mode 100644 (file)
index 0000000..b1274fc
--- /dev/null
@@ -0,0 +1,184 @@
+// 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 "util.h" // dprintf
+#include "pci.h" // foreachpci
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+#include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "boot.h" // boot_add_hd
+#include "virtio-pci.h"
+#include "virtio-ring.h"
+#include "virtio-blk.h"
+#include "disk.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_g =
+        container_of(op->drive_g, struct virtiodrive_s, drive);
+    struct vring_virtqueue *vq = GET_GLOBAL(vdrive_g->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_GLOBAL(vdrive_g->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_GLOBAL(vdrive_g->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_GLOBAL(vdrive_g->ioaddr));
+
+    return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
+}
+
+int
+process_virtio_op(struct disk_op_s *op)
+{
+    if (! CONFIG_VIRTIO_BLK || CONFIG_COREBOOT)
+        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:
+        op->count = 0;
+        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_g = malloc_fseg(sizeof(*vdrive_g));
+    struct vring_virtqueue *vq = memalign_low(PAGE_SIZE, sizeof(*vq));
+    if (!vdrive_g || !vq) {
+        warn_noalloc();
+        goto fail;
+    }
+    memset(vdrive_g, 0, sizeof(*vdrive_g));
+    memset(vq, 0, sizeof(*vq));
+    vdrive_g->drive.type = DTYPE_VIRTIO;
+    vdrive_g->drive.cntl_id = bdf;
+    vdrive_g->vq = vq;
+
+    u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) &
+        PCI_BASE_ADDRESS_IO_MASK;
+
+    vdrive_g->ioaddr = ioaddr;
+
+    vp_reset(ioaddr);
+    vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+                  VIRTIO_CONFIG_S_DRIVER );
+
+    if (vp_find_vq(ioaddr, 0, vdrive_g->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_g->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ?
+        cfg.blk_size : DISK_SECTOR_SIZE;
+
+    vdrive_g->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_g->drive.blksize, (u32)vdrive_g->drive.sectors);
+
+    if (vdrive_g->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_g->drive.blksize);
+        goto fail;
+    }
+
+    vdrive_g->drive.pchs.cylinders = cfg.cylinders;
+    vdrive_g->drive.pchs.heads = cfg.heads;
+    vdrive_g->drive.pchs.spt = 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_g->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:
+    free(vdrive_g);
+    free(vq);
+}
+
+void
+virtio_blk_setup(void)
+{
+    ASSERT32FLAT();
+    if (! CONFIG_VIRTIO_BLK || CONFIG_COREBOOT)
+        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/bios/seabios/src/virtio-blk.h b/bios/seabios/src/virtio-blk.h
new file mode 100644 (file)
index 0000000..7243704
--- /dev/null
@@ -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_op(struct disk_op_s *op);
+void virtio_blk_setup(void);
+
+#endif /* _VIRTIO_BLK_H */
diff --git a/bios/seabios/src/virtio-pci.c b/bios/seabios/src/virtio-pci.c
new file mode 100644 (file)
index 0000000..db19e97
--- /dev/null
@@ -0,0 +1,69 @@
+/* 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 "virtio-ring.h"
+#include "virtio-pci.h"
+#include "config.h" // CONFIG_DEBUG_LEVEL
+#include "util.h" // dprintf
+
+int vp_find_vq(unsigned int ioaddr, int queue_index,
+               struct vring_virtqueue *vq)
+{
+   struct vring * vr = &vq->vring;
+   u16 num;
+
+   ASSERT32FLAT();
+   /* 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");
+       return -1;
+   }
+
+   if (num > MAX_QUEUE_NUM) {
+       dprintf(1, "ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
+       return -1;
+   }
+
+   /* check if the queue is already active */
+
+   if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
+       dprintf(1, "ERROR: queue already active\n");
+       return -1;
+   }
+
+   vq->queue_index = queue_index;
+
+   /* initialize the queue */
+
+   vring_init(vr, num, (unsigned char*)&vq->queue);
+
+   /* activate the queue
+    *
+    * NOTE: vr->desc is initialized by vring_init()
+    */
+
+   outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
+        ioaddr + VIRTIO_PCI_QUEUE_PFN);
+
+   return num;
+}
diff --git a/bios/seabios/src/virtio-pci.h b/bios/seabios/src/virtio-pci.h
new file mode 100644 (file)
index 0000000..d21d5a5
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef _VIRTIO_PCI_H
+#define _VIRTIO_PCI_H
+
+#include "ioport.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;
+int vp_find_vq(unsigned int ioaddr, int queue_index,
+               struct vring_virtqueue *vq);
+#endif /* _VIRTIO_PCI_H_ */
diff --git a/bios/seabios/src/virtio-ring.c b/bios/seabios/src/virtio-ring.c
new file mode 100644 (file)
index 0000000..97a3ffe
--- /dev/null
@@ -0,0 +1,151 @@
+/* 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 "virtio-ring.h"
+#include "virtio-pci.h"
+#include "biosvar.h" // GET_GLOBAL
+#include "util.h" // dprintf
+
+#define BUG() do {                                      \
+        dprintf(1, "BUG: failure at %s:%d/%s()!\n",     \
+                __FILE__, __LINE__, __func__);          \
+                while(1);                               \
+        } 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_FLATPTR(vq->vring.used);
+    int more = GET_FLATPTR(vq->last_used_idx) != GET_FLATPTR(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_FLATPTR(vr->desc);
+    unsigned int i;
+
+    /* find end of given descriptor */
+
+    i = head;
+    while (GET_FLATPTR(desc[i].flags) & VRING_DESC_F_NEXT)
+        i = GET_FLATPTR(desc[i].next);
+
+    /* link it with free list and point to it */
+
+    SET_FLATPTR(desc[i].next, GET_FLATPTR(vq->free_head));
+    SET_FLATPTR(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_FLATPTR(vq->vring.used);
+    u32 id;
+    int ret;
+
+//    BUG_ON(!vring_more_used(vq));
+
+    elem = &used->ring[GET_FLATPTR(vq->last_used_idx) % GET_FLATPTR(vr->num)];
+    id = GET_FLATPTR(elem->id);
+    if (len != NULL)
+        *len = GET_FLATPTR(elem->len);
+
+    ret = GET_FLATPTR(vq->vdata[id]);
+
+    vring_detach(vq, id);
+
+    SET_FLATPTR(vq->last_used_idx, GET_FLATPTR(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_FLATPTR(vr->desc);
+    struct vring_avail *avail = GET_FLATPTR(vr->avail);
+
+    BUG_ON(out + in == 0);
+
+    prev = 0;
+    head = GET_FLATPTR(vq->free_head);
+    for (i = head; out; i = GET_FLATPTR(desc[i].next), out--) {
+        SET_FLATPTR(desc[i].flags, VRING_DESC_F_NEXT);
+        SET_FLATPTR(desc[i].addr, (u64)virt_to_phys(list->addr));
+        SET_FLATPTR(desc[i].len, list->length);
+        prev = i;
+        list++;
+    }
+    for ( ; in; i = GET_FLATPTR(desc[i].next), in--) {
+        SET_FLATPTR(desc[i].flags, VRING_DESC_F_NEXT|VRING_DESC_F_WRITE);
+        SET_FLATPTR(desc[i].addr, (u64)virt_to_phys(list->addr));
+        SET_FLATPTR(desc[i].len, list->length);
+        prev = i;
+        list++;
+    }
+    SET_FLATPTR(desc[prev].flags,
+                GET_FLATPTR(desc[prev].flags) & ~VRING_DESC_F_NEXT);
+
+    SET_FLATPTR(vq->free_head, i);
+
+    SET_FLATPTR(vq->vdata[head], index);
+
+    av = (GET_FLATPTR(avail->idx) + num_added) % GET_FLATPTR(vr->num);
+    SET_FLATPTR(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_FLATPTR(vr->avail);
+
+    /* Make sure idx update is done after ring write. */
+    smp_wmb();
+    SET_FLATPTR(avail->idx, GET_FLATPTR(avail->idx) + num_added);
+
+    vp_notify(ioaddr, GET_FLATPTR(vq->queue_index));
+}
diff --git a/bios/seabios/src/virtio-ring.h b/bios/seabios/src/virtio-ring.h
new file mode 100644 (file)
index 0000000..b7a7aaf
--- /dev/null
@@ -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/bios/seabios/src/xen.c b/bios/seabios/src/xen.c
new file mode 100644 (file)
index 0000000..4072793
--- /dev/null
@@ -0,0 +1,149 @@
+// Xen HVM support
+//
+// Copyright (C) 2011 Citrix Systems.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h"
+#include "xen.h"
+
+#include "memmap.h" // add_e820
+#include "types.h" // ASM32FLAT
+#include "util.h" // copy_acpi_rsdp
+
+#define INFO_PHYSICAL_ADDRESS 0x00001000
+
+u32 xen_cpuid_base = 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_probe(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(1, "Found hypervisor signature \"%s\" at %x\n",
+                signature, base);
+        if (strcmp(signature, "XenVMMXenVMM") == 0) {
+            if ((eax - base) < 2)
+                panic("Insufficient Xen cpuid leaves. eax=%x at base %x\n",
+                      eax, base);
+            xen_cpuid_base = base;
+            break;
+        }
+    }
+}
+
+static int hypercall_xen_version( int cmd, void *arg)
+{
+    return _hypercall2(int, xen_version, cmd, arg);
+}
+
+/* Fill in hypercall transfer pages. */
+void xen_init_hypercalls(void)
+{
+    u32 eax, ebx, ecx, edx;
+    xen_extraversion_t extraversion;
+    unsigned long i;
+
+    if (!usingXen())
+        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_copy_biostables(void)
+{
+    struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS;
+    u32 *tables = (u32 *)info->tables;
+    int i;
+
+    dprintf(1, "xen: copy BIOS tables...\n");
+    for (i=0; i<info->tables_nr; i++) {
+        void *table = (void *)tables[i];
+        copy_acpi_rsdp(table);
+        copy_mptable(table);
+        copy_pir(table);
+        copy_smbios(table);
+    }
+}
+
+void xen_setup(void)
+{
+    u64 maxram = 0, maxram_over4G = 0;
+    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];
+        if (e->type == E820_ACPI || e->type == E820_RAM) {
+            u64 end = e->start + e->size;
+            if (end > 0x100000000ull) {
+                end -= 0x100000000ull;
+                if (end > maxram_over4G)
+                    maxram_over4G = end;
+            } else if (end > maxram)
+                maxram = end;
+        }
+        add_e820(e->start, e->size, e->type);
+    }
+
+    RamSize = maxram;
+    RamSizeOver4G = maxram_over4G;
+}
diff --git a/bios/seabios/src/xen.h b/bios/seabios/src/xen.h
new file mode 100644 (file)
index 0000000..0ed1e9f
--- /dev/null
@@ -0,0 +1,135 @@
+#ifndef __XEN_H
+#define __XEN_H
+
+#include "util.h"
+
+extern u32 xen_cpuid_base;
+
+void xen_probe(void);
+void xen_setup(void);
+void xen_init_hypercalls(void);
+void xen_copy_biostables(void);
+
+static inline int usingXen(void) {
+    if (!CONFIG_XEN)
+       return 0;
+    return (xen_cpuid_base != 0);
+}
+
+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/bios/seabios/tools/buildrom.py b/bios/seabios/tools/buildrom.py
new file mode 100755 (executable)
index 0000000..19b715a
--- /dev/null
@@ -0,0 +1,43 @@
+#!/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
+
+def alignpos(pos, alignbytes):
+    mask = alignbytes - 1
+    return (pos + mask) & ~mask
+
+def checksum(data):
+    ords = map(ord, data)
+    return sum(ords)
+
+def main():
+    inname = sys.argv[1]
+    outname = sys.argv[2]
+
+    # Read data in
+    f = open(inname, 'rb')
+    data = f.read()
+    count = len(data)
+
+    # Pad to a 512 byte boundary
+    data += "\0" * (alignpos(count, 512) - count)
+    count = len(data)
+
+    # Fill in size field; clear checksum field
+    data = data[:2] + chr(count/512) + data[3:6] + "\0" + data[7:]
+
+    # Checksum rom
+    newsum = (256 - checksum(data)) & 0xff
+    data = data[:6] + chr(newsum) + data[7:]
+
+    # Write new rom
+    f = open(outname, 'wb')
+    f.write(data)
+
+if __name__ == '__main__':
+    main()
diff --git a/bios/seabios/tools/checkrom.py b/bios/seabios/tools/checkrom.py
new file mode 100755 (executable)
index 0000000..69d65e8
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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
+import layoutrom
+
+def main():
+    # Get args
+    objinfo, rawfile, outfile = sys.argv[1:]
+
+    # Read in symbols
+    objinfofile = open(objinfo, 'rb')
+    symbols = layoutrom.parseObjDump(objinfofile, 'in')[1]
+
+    # Read in raw file
+    f = open(rawfile, 'rb')
+    rawdata = f.read()
+    f.close()
+    datasize = len(rawdata)
+    finalsize = 64*1024
+    if datasize > 64*1024:
+        finalsize = 128*1024
+        if datasize > 128*1024:
+            finalsize = 256*1024
+
+    # 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)
+
+    # Print statistics
+    runtimesize = datasize
+    if '_reloc_abs_start' in symbols:
+        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
+        , finalsize / 1024)
+
+    # Write final file
+    f = open(outfile, 'wb')
+    f.write(("\0" * (finalsize - datasize)) + rawdata)
+    f.close()
+
+if __name__ == '__main__':
+    main()
diff --git a/bios/seabios/tools/checkstack.py b/bios/seabios/tools/checkstack.py
new file mode 100755 (executable)
index 0000000..428c296
--- /dev/null
@@ -0,0 +1,225 @@
+#!/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 | tools/checkstack.py
+
+import sys
+import re
+
+# Functions that change stacks
+STACKHOP = ['__send_disk_op']
+# 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 insn == 'movl   %esp,%ebp':
+                    # 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)
+                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/bios/seabios/tools/checksum.py b/bios/seabios/tools/checksum.py
new file mode 100755 (executable)
index 0000000..8c7665d
--- /dev/null
@@ -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/bios/seabios/tools/encodeint.py b/bios/seabios/tools/encodeint.py
new file mode 100755 (executable)
index 0000000..12be5fe
--- /dev/null
@@ -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])
+
+    outval = struct.pack('<Q', value)
+    f = open(filename, 'wb')
+    f.write(outval)
+    f.close()
+
+if __name__ == '__main__':
+    main()
diff --git a/bios/seabios/tools/gen-offsets.sh b/bios/seabios/tools/gen-offsets.sh
new file mode 100755 (executable)
index 0000000..99fdc53
--- /dev/null
@@ -0,0 +1,17 @@
+:
+# 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/bios/seabios/tools/kconfig/.gitignore b/bios/seabios/tools/kconfig/.gitignore
new file mode 100644 (file)
index 0000000..624f650
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# Generated files
+#
+config*
+lex.*.c
+*.tab.c
+*.tab.h
+zconf.hash.c
+*.moc
+lkc_defs.h
+gconf.glade.h
+*.pot
+*.mo
+
+#
+# configuration programs
+#
+conf
+mconf
+nconf
+qconf
+gconf
+kxgettext
diff --git a/bios/seabios/tools/kconfig/Makefile b/bios/seabios/tools/kconfig/Makefile
new file mode 100644 (file)
index 0000000..890243b
--- /dev/null
@@ -0,0 +1,361 @@
+# ===========================================================================
+# 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
+
+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/generated
+       $(Q)$< --$@ $(Kconfig)
+
+# if no path is given, then use src directory to find file
+ifdef LSMOD
+LSMOD_F := $(LSMOD)
+ifeq ($(findstring /,$(LSMOD)),)
+  LSMOD_F := $(objtree)/$(LSMOD)
+endif
+endif
+
+localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
+       $(Q)mkdir -p include/generated
+       $(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .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
+
+localyesconfig: $(obj)/streamline_config.pl $(obj)/conf
+       $(Q)mkdir -p include/generated
+       $(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config
+       $(Q)sed -i s/=m/=y/ .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
+# The symlink is used to repair a deficiency in arch/um
+update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
+       $(Q)echo "  GEN config"
+       $(Q)xgettext --default-domain=linux              \
+           --add-comments --keyword=_ --keyword=N_      \
+           --from-code=UTF-8                            \
+           --files-from=tools/kconfig/POTFILES.in     \
+           --output $(obj)/config.pot
+       $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
+       $(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch
+       $(Q)(for i in `ls arch/*/Kconfig`;               \
+           do                                           \
+               echo "  GEN $$i";                        \
+               $(obj)/kxgettext $$i                     \
+                    >> $(obj)/config.pot;               \
+           done )
+       $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
+           --output $(obj)/linux.pot
+       $(Q)rm -f arch/um/Kconfig.arch
+       $(Q)rm -f $(obj)/config.pot
+
+PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig
+
+allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf
+       $< --$@ $(Kconfig)
+
+PHONY += listnewconfig oldnoconfig savedefconfig defconfig
+
+listnewconfig oldnoconfig: $(obj)/conf
+       $< --$@ $(Kconfig)
+
+savedefconfig: $(obj)/conf
+       $< --$@=defconfig $(Kconfig)
+
+defconfig: $(obj)/conf
+       @echo "  Build default config"
+       $(Q)$< --defconfig=/dev/null $(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  '  oldnoconfig     - Same as silentoldconfig but set new symbols to n (unset)'
+
+# 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
+
+hostprogs-y := conf qconf gconf kxgettext
+
+ifeq ($(MAKECMDGOALS),nconfig)
+       hostprogs-y += nconf
+endif
+
+ifeq ($(MAKECMDGOALS),menuconfig)
+       hostprogs-y += mconf
+endif
+
+ifeq ($(MAKECMDGOALS),xconfig)
+       qconf-target := 1
+endif
+ifeq ($(MAKECMDGOALS),gconfig)
+       gconf-target := 1
+endif
+
+
+ifeq ($(qconf-target),1)
+qconf-cxxobjs  := qconf.o
+qconf-objs     := kconfig_load.o zconf.tab.o
+endif
+
+ifeq ($(gconf-target),1)
+gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
+endif
+
+clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck \
+                  .tmp_gtkcheck zconf.tab.c lex.zconf.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_lex.zconf.o := -I$(src)
+HOSTCFLAGS_zconf.tab.o := -I$(src)
+
+HOSTLOADLIBES_qconf    = $(KC_QT_LIBS) -ldl
+HOSTCXXFLAGS_qconf.o   = $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK
+
+HOSTLOADLIBES_gconf    = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` -ldl
+HOSTCFLAGS_gconf.o     = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
+                          -D LKC_DIRECT_LINK
+
+HOSTLOADLIBES_mconf   = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
+
+HOSTLOADLIBES_nconf    = -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 "*"; \
+               echo "* Unable to find any QT installation. Please make sure that"; \
+               echo "* the QT4 or QT3 development package is correctly installed and"; \
+               echo "* either qmake can be found or install pkg-config or set"; \
+               echo "* the QTDIR environment variable to the correct location."; \
+               echo "*"; \
+               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)"; \
+         binpath="\$$(shell pkg-config QtCore --variable=prefix)"; \
+         moc="$$binpath/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 "*";                                                       \
+                       echo "* GTK+ is present but version >= 2.0.0 is required.";     \
+                       echo "*";                                                       \
+                       false;                                                          \
+               fi                                                                      \
+       else                                                                            \
+               echo "*";                                                               \
+               echo "* Unable to find the GTK+ installation. Please make sure that";   \
+               echo "* the GTK+ 2.0 development package is correctly installed...";    \
+               echo "* You need gtk+-2.0, glib-2.0 and libglade-2.0.";                 \
+               echo "*";                                                               \
+               false;                                                                  \
+       fi
+endif
+
+$(obj)/zconf.tab.o: $(obj)/lex.zconf.c $(obj)/zconf.hash.c
+
+$(obj)/kconfig_load.o: $(obj)/lkc_defs.h
+
+$(obj)/qconf.o: $(obj)/qconf.moc $(obj)/lkc_defs.h
+
+$(obj)/gconf.o: $(obj)/lkc_defs.h
+
+$(obj)/%.moc: $(src)/%.h
+       $(KC_QT_MOC) -i $< -o $@
+
+$(obj)/lkc_defs.h: $(src)/lkc_proto.h
+       sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+
+# Extract gconf menu items for I18N support
+$(obj)/gconf.glade.h: $(obj)/gconf.glade
+       intltool-extract --type=gettext/glade $(obj)/gconf.glade
+
+###
+# The following requires flex/bison/gperf
+# By default we use the _shipped versions, uncomment the following line if
+# you are modifying the flex/bison src.
+# LKC_GENPARSER := 1
+
+ifdef LKC_GENPARSER
+
+$(obj)/zconf.tab.c: $(src)/zconf.y
+$(obj)/lex.zconf.c: $(src)/zconf.l
+$(obj)/zconf.hash.c: $(src)/zconf.gperf
+
+%.tab.c: %.y
+       bison -l -b $* -p $(notdir $*) $<
+       cp $@ $@_shipped
+
+lex.%.c: %.l
+       flex -L -P$(notdir $*) -o$@ $<
+       cp $@ $@_shipped
+
+%.hash.c: %.gperf
+       gperf < $< > $@
+       cp $@ $@_shipped
+
+endif
+
+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/bios/seabios/tools/kconfig/POTFILES.in b/bios/seabios/tools/kconfig/POTFILES.in
new file mode 100644 (file)
index 0000000..f0baccd
--- /dev/null
@@ -0,0 +1,12 @@
+tools/kconfig/lxdialog/checklist.c
+tools/kconfig/lxdialog/inputbox.c
+tools/kconfig/lxdialog/menubox.c
+tools/kconfig/lxdialog/textbox.c
+tools/kconfig/lxdialog/util.c
+tools/kconfig/lxdialog/yesno.c
+tools/kconfig/mconf.c
+tools/kconfig/conf.c
+tools/kconfig/confdata.c
+tools/kconfig/gconf.c
+tools/kconfig/gconf.glade.h
+tools/kconfig/qconf.cc
diff --git a/bios/seabios/tools/kconfig/check.sh b/bios/seabios/tools/kconfig/check.sh
new file mode 100755 (executable)
index 0000000..fa59cbf
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Needed for systems without gettext
+$* -xc -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/bios/seabios/tools/kconfig/conf.c b/bios/seabios/tools/kconfig/conf.c
new file mode 100644 (file)
index 0000000..659326c
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * 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>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum input_mode {
+       oldaskconfig,
+       silentoldconfig,
+       oldconfig,
+       allnoconfig,
+       allyesconfig,
+       allmodconfig,
+       alldefconfig,
+       randconfig,
+       defconfig,
+       savedefconfig,
+       listnewconfig,
+       oldnoconfig,
+} input_mode = oldaskconfig;
+
+char *defconfig_file;
+
+static int indent = 1;
+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();
+       case oldaskconfig:
+               fflush(stdout);
+               xfgets(line, 128, stdin);
+               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;
+                       }
+               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();
+               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[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 == oldnoconfig) &&
+                           rootEntry != menu) {
+                               check_conf(menu);
+                               return;
+                       }
+               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 != oldnoconfig) {
+                               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},
+       {"oldnoconfig",     no_argument,       NULL, oldnoconfig},
+       {NULL, 0, NULL, 0}
+};
+
+int main(int ac, char **av)
+{
+       int opt;
+       const char *name;
+       struct stat tmpstat;
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       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;
+
+                       /*
+                        * 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));
+                       srand(seed);
+                       break;
+               }
+               case '?':
+                       fprintf(stderr, _("See README for usage info\n"));
+                       exit(1);
+                       break;
+               }
+       }
+       if (ac == optind) {
+               printf(_("%s: Kconfig file missing\n"), av[0]);
+               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 oldnoconfig:
+               conf_read(NULL);
+               break;
+       case allnoconfig:
+       case allyesconfig:
+       case allmodconfig:
+       case alldefconfig:
+       case randconfig:
+               name = getenv("KCONFIG_ALLCONFIG");
+               if (name && !stat(name, &tmpstat)) {
+                       conf_read_simple(name, S_DEF_USER);
+                       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 (!stat(name, &tmpstat))
+                       conf_read_simple(name, S_DEF_USER);
+               else if (!stat("all.config", &tmpstat))
+                       conf_read_simple("all.config", S_DEF_USER);
+               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 = isatty(0) && isatty(1) && isatty(2);
+       }
+
+       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:
+               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 oldnoconfig:
+       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 != oldnoconfig));
+               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(str, size, in)
+       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/bios/seabios/tools/kconfig/confdata.c b/bios/seabios/tools/kconfig/confdata.c
new file mode 100644 (file)
index 0000000..f110bf5
--- /dev/null
@@ -0,0 +1,1062 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#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;
+               }
+       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;
+               }
+               conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+               break;
+       case S_OTHER:
+               if (*p != '"') {
+                       for (p2 = p; *p2 && !isspace(*p2); p2++)
+                               ;
+                       sym->type = S_STRING;
+                       goto done;
+               }
+       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) {
+                       conf_warning("invalid string found");
+                       return 1;
+               }
+       case S_INT:
+       case S_HEX:
+       done:
+               if (sym_string_valid(sym, p)) {
+                       sym->def[def].val = strdup(p);
+                       sym->flags |= def_flags;
+               } else {
+                       conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+                       return 1;
+               }
+               break;
+       default:
+               ;
+       }
+       return 0;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+       FILE *in = NULL;
+       char line[1024];
+       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);
+               default:
+                       sym->def[def].val = NULL;
+                       sym->def[def].tri = no;
+               }
+       }
+
+       while (fgets(line, sizeof(line), in)) {
+               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);
+               }
+       }
+       fclose(in);
+
+       if (modules_sym)
+               sym_calc_value(modules_sym);
+       return 0;
+}
+
+int conf_read(const char *name)
+{
+       struct symbol *sym, *choice_sym;
+       struct property *prop;
+       struct expr *e;
+       int i, flags;
+
+       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))
+                       goto sym_ok;
+               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))
+                                       goto sym_ok;
+                       default:
+                               if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+                                       goto sym_ok;
+                               break;
+                       }
+               } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+                       /* no previous value and not saved */
+                       goto sym_ok;
+               conf_unsaved++;
+               /* maybe print value in verbose mode... */
+       sym_ok:
+               if (!sym_is_choice(sym))
+                       continue;
+               /* The choice symbol only has a set value (and thus is not new)
+                * if all its visible childs have values.
+                */
+               prop = sym_get_choice_prop(sym);
+               flags = sym->flags;
+               expr_list_for_each_sym(prop->expr, e, choice_sym)
+                       if (choice_sym->visible != no)
+                               flags &= choice_sym->flags;
+               sym->flags &= flags | ~SYMBOL_DEF_USER;
+       }
+
+       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;
+}
+
+/* Write a S_STRING */
+static void conf_write_string(bool headerfile, const char *name,
+                              const char *str, FILE *out)
+{
+       int l;
+       if (headerfile)
+               fprintf(out, "#define %s%s \"", CONFIG_, name);
+       else
+               fprintf(out, "%s%s=\"", CONFIG_, name);
+
+       while (1) {
+               l = strcspn(str, "\"\\");
+               if (l) {
+                       xfwrite(str, l, 1, out);
+                       str += l;
+               }
+               if (!*str)
+                       break;
+               fprintf(out, "\\%c", *str++);
+       }
+       fputs("\"\n", out);
+}
+
+static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no)
+{
+       const char *str;
+
+       switch (sym->type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               switch (sym_get_tristate_value(sym)) {
+               case no:
+                       if (write_no)
+                               fprintf(out, "# %s%s is not set\n",
+                                   CONFIG_, sym->name);
+                       break;
+               case mod:
+                       fprintf(out, "%s%s=m\n", CONFIG_, sym->name);
+                       break;
+               case yes:
+                       fprintf(out, "%s%s=y\n", CONFIG_, sym->name);
+                       break;
+               }
+               break;
+       case S_STRING:
+               conf_write_string(false, sym->name, sym_get_string_value(sym), out);
+               break;
+       case S_HEX:
+       case S_INT:
+               str = sym_get_string_value(sym);
+               fprintf(out, "%s%s=%s\n", CONFIG_, sym->name, str);
+               break;
+       case S_OTHER:
+       case S_UNKNOWN:
+               break;
+       }
+}
+
+/*
+ * 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(sym, out, true);
+               }
+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];
+       time_t now;
+       int use_timestamp = 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;
+
+       time(&now);
+       env = getenv("KCONFIG_NOTIMESTAMP");
+       if (env && *env)
+               use_timestamp = 0;
+
+       fprintf(out, _("#\n"
+                      "# Automatically generated make config: don't edit\n"
+                      "# %s\n"
+                      "%s%s"
+                      "#\n"),
+                    rootmenu.prompt->text,
+                    use_timestamp ? "# " : "",
+                    use_timestamp ? ctime(&now) : "");
+
+       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;
+                       /* Write config symbol to file */
+                       conf_write_symbol(sym, out, true);
+               }
+
+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 *str;
+       const char *name;
+       FILE *out, *tristate, *out_h;
+       time_t now;
+       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;
+       }
+
+       time(&now);
+       fprintf(out, "#\n"
+                    "# Automatically generated make config: don't edit\n"
+                    "# %s\n"
+                    "# %s"
+                    "#\n",
+                    rootmenu.prompt->text, ctime(&now));
+       fprintf(tristate, "#\n"
+                         "# Automatically generated - do not edit\n"
+                         "\n");
+       fprintf(out_h, "/*\n"
+                      " * Automatically generated C config: don't edit\n"
+                      " * %s\n"
+                      " * %s"
+                      " */\n",
+                      rootmenu.prompt->text, ctime(&now));
+
+       for_all_symbols(i, sym) {
+               sym_calc_value(sym);
+               if (!sym->name)
+                       continue;
+               if (!(sym->flags & SYMBOL_WRITE)) {
+                       if (sym->type == S_BOOLEAN || sym->type == S_HEX
+                           || sym->type == S_INT)
+                               fprintf(out_h, "#define %s%s 0\n",
+                                       CONFIG_, sym->name);
+                       continue;
+               }
+
+               /* write symbol to config file */
+               conf_write_symbol(sym, out, false);
+
+               /* update autoconf and tristate files */
+               switch (sym->type) {
+               case S_BOOLEAN:
+               case S_TRISTATE:
+                       switch (sym_get_tristate_value(sym)) {
+                       case no:
+                               fprintf(out_h, "#define %s%s 0\n",
+                                   CONFIG_, sym->name);
+                               break;
+                       case mod:
+                               fprintf(tristate, "%s%s=M\n",
+                                   CONFIG_, sym->name);
+                               fprintf(out_h, "#define %s%s_MODULE 1\n",
+                                   CONFIG_, sym->name);
+                               break;
+                       case yes:
+                               if (sym->type == S_TRISTATE)
+                                       fprintf(tristate,"%s%s=Y\n",
+                                           CONFIG_, sym->name);
+                               fprintf(out_h, "#define %s%s 1\n",
+                                   CONFIG_, sym->name);
+                               break;
+                       }
+                       break;
+               case S_STRING:
+                       conf_write_string(true, sym->name, sym_get_string_value(sym), out_h);
+                       break;
+               case S_HEX:
+                       str = sym_get_string_value(sym);
+                       if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
+                               fprintf(out_h, "#define %s%s 0x%s\n",
+                                   CONFIG_, sym->name, str);
+                               break;
+                       }
+               case S_INT:
+                       str = sym_get_string_value(sym);
+                       fprintf(out_h, "#define %s%s %s\n",
+                           CONFIG_, sym->name, str);
+                       break;
+               default:
+                       break;
+               }
+       }
+       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 void 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;
+
+       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;
+               }
+       }
+       csym->flags |= SYMBOL_DEF_USER;
+       /* clear VALID to get value calculated */
+       csym->flags &= ~(SYMBOL_VALID);
+}
+
+static 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);
+}
+
+void conf_set_all_new_symbols(enum conf_def_mode mode)
+{
+       struct symbol *sym, *csym;
+       int i, cnt;
+
+       for_all_symbols(i, sym) {
+               if (sym_has_value(sym))
+                       continue;
+               switch (sym_get_type(sym)) {
+               case S_BOOLEAN:
+               case S_TRISTATE:
+                       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:
+                               sym->def[S_DEF_USER].tri = no;
+                               break;
+                       case def_random:
+                               cnt = sym_get_type(sym) == S_TRISTATE ? 3 : 2;
+                               sym->def[S_DEF_USER].tri = (tristate)(rand() % cnt);
+                               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.
+        */
+       for_all_symbols(i, csym) {
+               if (sym_has_value(csym) || !sym_is_choice(csym))
+                       continue;
+
+               sym_calc_value(csym);
+               if (mode == def_random)
+                       randomize_choice_values(csym);
+               else
+                       set_all_choice_values(csym);
+       }
+}
diff --git a/bios/seabios/tools/kconfig/expr.c b/bios/seabios/tools/kconfig/expr.c
new file mode 100644 (file)
index 0000000..0010034
--- /dev/null
@@ -0,0 +1,1173 @@
+/*
+ * 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>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define DEBUG_EXPR     0
+
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+       struct expr *e = malloc(sizeof(*e));
+       memset(e, 0, 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 = malloc(sizeof(*e));
+       memset(e, 0, 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 = malloc(sizeof(*e));
+       memset(e, 0, 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 = malloc(sizeof(*e));
+       memset(e, 0, 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 = malloc(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/bios/seabios/tools/kconfig/expr.h b/bios/seabios/tools/kconfig/expr.h
new file mode 100644 (file)
index 0000000..3d238db
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * 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 <stdio.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+struct file {
+       struct file *next;
+       struct file *parent;
+       const char *name;
+       int lineno;
+       int flags;
+};
+
+#define FILE_BUSY              0x0001
+#define FILE_SCANNED           0x0002
+
+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  /* ? */
+#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 */
+
+#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
+
+#ifndef SWIG
+
+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);
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXPR_H */
diff --git a/bios/seabios/tools/kconfig/gconf.c b/bios/seabios/tools/kconfig/gconf.c
new file mode 100644 (file)
index 0000000..b7f31f2
--- /dev/null
@@ -0,0 +1,1577 @@
+/* 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 "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>
+#include <stdlib.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, FALSE);
+
+       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);
+static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
+                            gchar * arg1, 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, FALSE);
+
+       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);
+       /*g_signal_connect(G_OBJECT(renderer), "toggled",
+          G_CALLBACK(renderer_toggled), 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, 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, 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, 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_paned_set_position(GTK_PANED(hpaned), 0);
+       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_paned_set_position(GTK_PANED(hpaned), 0);
+       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 oldval, 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:
+               oldval = sym_get_tristate_value(sym);
+               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 void renderer_toggled(GtkCellRendererToggle * cell,
+                            gchar * path_string, gpointer user_data)
+{
+       GtkTreePath *path, *sel_path = NULL;
+       GtkTreeIter iter, sel_iter;
+       GtkTreeSelection *sel;
+       struct menu *menu;
+
+       path = gtk_tree_path_new_from_string(path_string);
+       if (!gtk_tree_model_get_iter(model2, &iter, path))
+               return;
+
+       sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
+       if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
+               sel_path = gtk_tree_model_get_path(model2, &sel_iter);
+       if (!sel_path)
+               goto out1;
+       if (gtk_tree_path_compare(path, sel_path))
+               goto out2;
+
+       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+       toggle_sym_value(menu);
+
+      out2:
+       gtk_tree_path_free(sel_path);
+      out1:
+       gtk_tree_path_free(path);
+}
+
+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;
+       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 property *prop;
+       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) {
+
+               prop = child1->prompt;
+               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))*/
+               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;
+
+#ifndef LKC_DIRECT_LINK
+       kconfig_load();
+#endif
+
+       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, "/tools/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/bios/seabios/tools/kconfig/gconf.glade b/bios/seabios/tools/kconfig/gconf.glade
new file mode 100644 (file)
index 0000000..aa483cb
--- /dev/null
@@ -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/bios/seabios/tools/kconfig/images.c b/bios/seabios/tools/kconfig/images.c
new file mode 100644 (file)
index 0000000..d4f84bd
--- /dev/null
@@ -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/bios/seabios/tools/kconfig/kconfig_load.c b/bios/seabios/tools/kconfig/kconfig_load.c
new file mode 100644 (file)
index 0000000..2d0cff8
--- /dev/null
@@ -0,0 +1,35 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lkc.h"
+
+#define P(name,type,arg)       type (*name ## _p) arg
+#include "lkc_proto.h"
+#undef P
+
+void kconfig_load(void)
+{
+       void *handle;
+       char *error;
+
+       handle = dlopen("./libkconfig.so", RTLD_LAZY);
+       if (!handle) {
+               handle = dlopen("./tools/kconfig/libkconfig.so", RTLD_LAZY);
+               if (!handle) {
+                       fprintf(stderr, "%s\n", dlerror());
+                       exit(1);
+               }
+       }
+
+#define P(name,type,arg)                       \
+{                                              \
+       name ## _p = dlsym(handle, #name);      \
+        if ((error = dlerror()))  {            \
+                fprintf(stderr, "%s\n", error);        \
+               exit(1);                        \
+       }                                       \
+}
+#include "lkc_proto.h"
+#undef P
+}
diff --git a/bios/seabios/tools/kconfig/kxgettext.c b/bios/seabios/tools/kconfig/kxgettext.c
new file mode 100644 (file)
index 0000000..e9d8e79
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * 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>
+
+#define LKC_DIRECT_LINK
+#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/bios/seabios/tools/kconfig/lex.zconf.c_shipped b/bios/seabios/tools/kconfig/lex.zconf.c_shipped
new file mode 100644 (file)
index 0000000..6eb0397
--- /dev/null
@@ -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/bios/seabios/tools/kconfig/lkc.h b/bios/seabios/tools/kconfig/lkc.h
new file mode 100644 (file)
index 0000000..febf0c9
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * 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
+
+#ifdef LKC_DIRECT_LINK
+#define P(name,type,arg)       extern type name arg
+#else
+#include "lkc_defs.h"
+#define P(name,type,arg)       extern type (*name ## _p) arg
+#endif
+#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
+
+#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
+
+struct kconf_id {
+       int name;
+       int token;
+       unsigned int flags;
+       enum symbol_type stype;
+};
+
+#ifdef YYDEBUG
+extern int zconfdebug;
+#endif
+
+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);
+
+/* conf.c */
+void xfgets(char *str, int size, FILE *in);
+
+/* 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);
+void conf_set_all_new_symbols(enum conf_def_mode mode);
+
+/* confdata.c and expr.c */
+static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
+{
+       if (fwrite(str, len, count, out) < count)
+               fprintf(stderr, "\nError in writing or end of file.\n");
+}
+
+/* kconfig_load.c */
+void kconfig_load(void);
+
+/* 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);
+
+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/bios/seabios/tools/kconfig/lkc_proto.h b/bios/seabios/tools/kconfig/lkc_proto.h
new file mode 100644 (file)
index 0000000..17342fe
--- /dev/null
@@ -0,0 +1,53 @@
+#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_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));
+P(get_relations_str, struct gstr, (struct symbol **sym_arr));
+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_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/bios/seabios/tools/kconfig/lxdialog/.gitignore b/bios/seabios/tools/kconfig/lxdialog/.gitignore
new file mode 100644 (file)
index 0000000..90b08ff
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Generated files
+#
+lxdialog
diff --git a/bios/seabios/tools/kconfig/lxdialog/BIG.FAT.WARNING b/bios/seabios/tools/kconfig/lxdialog/BIG.FAT.WARNING
new file mode 100644 (file)
index 0000000..a8999d8
--- /dev/null
@@ -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/bios/seabios/tools/kconfig/lxdialog/check-lxdialog.sh b/bios/seabios/tools/kconfig/lxdialog/check-lxdialog.sh
new file mode 100644 (file)
index 0000000..82cc3a8
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/sh
+# Check ncurses compatibility
+
+# What library to link
+ldflags()
+{
+       for ext in so 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/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="<ncurses/curses.h>"'
+       elif [ -f /usr/include/ncursesw/curses.h ]; then
+               echo '-I/usr/include/ncursesw -DCURSES_LOC="<ncursesw/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 -xc - -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/bios/seabios/tools/kconfig/lxdialog/checklist.c b/bios/seabios/tools/kconfig/lxdialog/checklist.c
new file mode 100644 (file)
index 0000000..a2eb80f
--- /dev/null
@@ -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 + 6))
+               return -ERRDISPLAYTOOSMALL;
+       if (getmaxx(stdscr) < (width + 6))
+               return -ERRDISPLAYTOOSMALL;
+
+       max_choice = MIN(list_height, item_count());
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - 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/bios/seabios/tools/kconfig/lxdialog/dialog.h b/bios/seabios/tools/kconfig/lxdialog/dialog.h
new file mode 100644 (file)
index 0000000..b5211fc
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *  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 dialog_info {
+       const char *backtitle;
+       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[];
+
+/*
+ * 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);
+
+int init_dialog(const char *backtitle);
+void set_dialog_backtitle(const char *backtitle);
+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);
+int dialog_textbox(const char *title, const char *file, int height, int width);
+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);
+extern char dialog_input_result[];
+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/bios/seabios/tools/kconfig/lxdialog/inputbox.c b/bios/seabios/tools/kconfig/lxdialog/inputbox.c
new file mode 100644 (file)
index 0000000..dd8e587
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ *  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, scroll = 0, key = 0, button = -1;
+       char *instr = dialog_input_result;
+       WINDOW *dialog;
+
+       if (!init)
+               instr[0] = '\0';
+       else
+               strcpy(instr, init);
+
+do_resize:
+       if (getmaxy(stdscr) <= (height - 2))
+               return -ERRDISPLAYTOOSMALL;
+       if (getmaxx(stdscr) <= (width - 2))
+               return -ERRDISPLAYTOOSMALL;
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - 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);
+
+       input_x = strlen(instr);
+
+       if (input_x >= box_width) {
+               scroll = input_x - box_width + 1;
+               input_x = box_width - 1;
+               for (i = 0; i < box_width - 1; i++)
+                       waddch(dialog, instr[scroll + i]);
+       } else {
+               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_LEFT:
+                               continue;
+                       case KEY_RIGHT:
+                               continue;
+                       case KEY_BACKSPACE:
+                       case 127:
+                               if (input_x || scroll) {
+                                       wattrset(dialog, dlg.inputbox.atr);
+                                       if (!input_x) {
+                                               scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
+                                               wmove(dialog, box_y, box_x);
+                                               for (i = 0; i < box_width; i++)
+                                                       waddch(dialog,
+                                                              instr[scroll + input_x + i] ?
+                                                              instr[scroll + input_x + i] : ' ');
+                                               input_x = strlen(instr) - scroll;
+                                       } else
+                                               input_x--;
+                                       instr[scroll + input_x] = '\0';
+                                       mvwaddch(dialog, box_y, input_x + box_x, ' ');
+                                       wmove(dialog, box_y, input_x + box_x);
+                                       wrefresh(dialog);
+                               }
+                               continue;
+                       default:
+                               if (key < 0x100 && isprint(key)) {
+                                       if (scroll + input_x < MAX_LEN) {
+                                               wattrset(dialog, dlg.inputbox.atr);
+                                               instr[scroll + input_x] = key;
+                                               instr[scroll + input_x + 1] = '\0';
+                                               if (input_x == box_width - 1) {
+                                                       scroll++;
+                                                       wmove(dialog, box_y, box_x);
+                                                       for (i = 0; i < box_width - 1; i++)
+                                                               waddch(dialog, instr [scroll + i]);
+                                               } else {
+                                                       wmove(dialog, box_y, input_x++ + box_x);
+                                                       waddch(dialog, key);
+                                               }
+                                               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/bios/seabios/tools/kconfig/lxdialog/menubox.c b/bios/seabios/tools/kconfig/lxdialog/menubox.c
new file mode 100644 (file)
index 0000000..1d60473
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ *  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 - 16;
+       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);
+
+       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 < 15 || width < 65)
+               return -ERRDISPLAYTOOSMALL;
+
+       height -= 4;
+       width  -= 5;
+       menu_height = height - 10;
+
+       max_choice = MIN(menu_height, item_count());
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - 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 (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)
+                           ? 2 : (button > 2 ? 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 3;
+                       case 'n':
+                               return 4;
+                       case 'm':
+                               return 5;
+                       case ' ':
+                               return 6;
+                       case '/':
+                               return 7;
+                       case 'z':
+                               return 8;
+                       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/bios/seabios/tools/kconfig/lxdialog/textbox.c b/bios/seabios/tools/kconfig/lxdialog/textbox.c
new file mode 100644 (file)
index 0000000..c704712
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ *  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);
+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 const char *buf;
+static const char *page;
+
+/*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+                                                         int cur_y, int cur_x)
+{
+       print_page(box, boxh, boxw);
+       print_position(dialog);
+       wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
+       wrefresh(dialog);
+}
+
+
+/*
+ * Display text from a file in a dialog box.
+ */
+int dialog_textbox(const char *title, const char *tbuf,
+                  int initial_height, int initial_width)
+{
+       int i, x, y, cur_x, cur_y, key = 0;
+       int height, width, boxh, boxw;
+       int passed_end;
+       WINDOW *dialog, *box;
+
+       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 */
+
+do_resize:
+       getmaxyx(stdscr, height, width);
+       if (height < 8 || width < 8)
+               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 = (COLS - width) / 2;
+       y = (LINES - 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);
+
+       while ((key != KEY_ESC) && (key != '\n')) {
+               key = wgetch(dialog);
+               switch (key) {
+               case 'E':       /* Exit */
+               case 'e':
+               case 'X':
+               case 'x':
+                       delwin(box);
+                       delwin(dialog);
+                       return 0;
+               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);
+                       }
+                       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);
+                       break;
+               case 'K':       /* Previous line */
+               case 'k':
+               case KEY_UP:
+                       if (!begin_reached) {
+                               back_lines(page_length + 1);
+
+                               /* We don't call print_page() here but use
+                                * scrolling to ensure faster screen update.
+                                * However, 'end_reached' and 'page_length'
+                                * should still be updated, and 'page' should
+                                * point to start of next page. This is done
+                                * by calling get_line() in the following
+                                * 'for' loop. */
+                               scrollok(box, TRUE);
+                               wscrl(box, -1); /* Scroll box region down one line */
+                               scrollok(box, FALSE);
+                               page_length = 0;
+                               passed_end = 0;
+                               for (i = 0; i < boxh; i++) {
+                                       if (!i) {
+                                               /* print first line of page */
+                                               print_line(box, 0, boxw);
+                                               wnoutrefresh(box);
+                                       } else
+                                               /* Called to update 'end_reached' and 'page' */
+                                               get_line();
+                                       if (!passed_end)
+                                               page_length++;
+                                       if (end_reached && !passed_end)
+                                               passed_end = 1;
+                               }
+
+                               print_position(dialog);
+                               wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
+                               wrefresh(dialog);
+                       }
+                       break;
+               case 'B':       /* Previous page */
+               case 'b':
+               case KEY_PPAGE:
+                       if (begin_reached)
+                               break;
+                       back_lines(page_length + boxh);
+                       refresh_text_box(dialog, box, boxh, boxw,
+                                        cur_y, cur_x);
+                       break;
+               case 'J':       /* Next line */
+               case 'j':
+               case KEY_DOWN:
+                       if (!end_reached) {
+                               begin_reached = 0;
+                               scrollok(box, TRUE);
+                               scroll(box);    /* Scroll box region up one line */
+                               scrollok(box, FALSE);
+                               print_line(box, boxh - 1, boxw);
+                               wnoutrefresh(box);
+                               print_position(dialog);
+                               wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
+                               wrefresh(dialog);
+                       }
+                       break;
+               case KEY_NPAGE: /* Next page */
+               case ' ':
+                       if (end_reached)
+                               break;
+
+                       begin_reached = 0;
+                       refresh_text_box(dialog, box, boxh, boxw,
+                                        cur_y, cur_x);
+                       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);
+                       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);
+                       break;
+               case KEY_ESC:
+                       key = on_key_esc(dialog);
+                       break;
+               case KEY_RESIZE:
+                       back_lines(height);
+                       delwin(box);
+                       delwin(dialog);
+                       on_key_resize();
+                       goto do_resize;
+               }
+       }
+       delwin(box);
+       delwin(dialog);
+       return key;             /* ESC pressed */
+}
+
+/*
+ * 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. Called by dialog_textbox().
+ */
+static void print_page(WINDOW * win, int height, int width)
+{
+       int i, passed_end = 0;
+
+       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. Called by dialog_textbox() and print_page().
+ */
+static void print_line(WINDOW * win, int row, int width)
+{
+       int y, x;
+       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));
+
+       getyx(win, y, x);
+       /* Clear 'residue' of previous line */
+#if OLD_NCURSES
+       {
+               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') {
+                       if (!end_reached) {
+                               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 pass '\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/bios/seabios/tools/kconfig/lxdialog/util.c b/bios/seabios/tools/kconfig/lxdialog/util.c
new file mode 100644 (file)
index 0000000..f2375ad
--- /dev/null
@@ -0,0 +1,657 @@
+/*
+ *  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"
+
+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)
+{
+       attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
+       /* Display background title if it exists ... - SLH */
+       if (dlg.backtitle != NULL) {
+               int i;
+
+               wattrset(stdscr, dlg.screen.atr);
+               mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
+               wmove(stdscr, 1, 1);
+               for (i = 1; i < COLS - 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 */
+       getmaxyx(stdscr, height, width);
+       if (height < 19 || width < 80) {
+               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;
+}
+
+/*
+ * 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 replaced by spaces.  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 i, prompt_len, room, wlen;
+       char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
+
+       strcpy(tempstr, prompt);
+
+       prompt_len = strlen(tempstr);
+
+       /*
+        * Remove newlines
+        */
+       for (i = 0; i < prompt_len; i++) {
+               if (tempstr[i] == '\n')
+                       tempstr[i] = ' ';
+       }
+
+       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 = strchr(word, ' ');
+                       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 = strchr(sp, ' '))
+                                || 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);
+                       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/bios/seabios/tools/kconfig/lxdialog/yesno.c b/bios/seabios/tools/kconfig/lxdialog/yesno.c
new file mode 100644 (file)
index 0000000..4e6e809
--- /dev/null
@@ -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 + 4))
+               return -ERRDISPLAYTOOSMALL;
+       if (getmaxx(stdscr) < (width + 4))
+               return -ERRDISPLAYTOOSMALL;
+
+       /* center dialog box on screen */
+       x = (COLS - width) / 2;
+       y = (LINES - 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/bios/seabios/tools/kconfig/mconf.c b/bios/seabios/tools/kconfig/mconf.c
new file mode 100644 (file)
index 0000000..d433c7a
--- /dev/null
@@ -0,0 +1,862 @@
+/*
+ * 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 <unistd.h>
+#include <locale.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+#include "lxdialog/dialog.h"
+
+static const char mconf_readme[] = N_(
+"Overview\n"
+"--------\n"
+"This interface let 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 removed it.  You may also press the <Space Bar> to cycle\n"
+"through the available options (ie. 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\n"
+"   you wish to change or submenu wish to select and press <Enter>.\n"
+"   Submenus are designated 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> and <Help>.\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 <SPACE BAR> and <B> for those\n"
+"   who are familiar with less and lynx.\n"
+"\n"
+"o  Press <E>, <X>, <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"
+"At the end of the main menu you will find two options.  One is\n"
+"for saving the current configuration to a file of your choosing.\n"
+"The other option is for loading a previously saved alternate\n"
+"configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you\n"
+"find during a Menuconfig session that you have completely messed\n"
+"up your settings, you may use the \"Load Alternate...\" option to\n"
+"restore your previously saved settings from \".config\" without\n"
+"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 a xterm definition which supports color.\n"
+"Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
+"display correctly in a 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, rather\n"
+"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  => a LCD friendly version of classic. (default)\n"
+"\n"),
+menu_instructions[] = N_(
+       "Arrow keys navigate the menu.  "
+       "<Enter> selects 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"
+       "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, MCA, 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 used in the menu structure for\n"
+       "  this symbol\n"
+       "o The 'Defined at' line tell at what file / line number the symbol\n"
+       "  is defined\n"
+       "o The 'Depends on:' line tell what symbols needs to be defined for\n"
+       "  this symbol to be visible in the menu (selectable)\n"
+       "o The 'Location:' lines tell where in the menu structure this symbol\n"
+       "  is located\n"
+       "    A location followed by a [=y] indicate that this is a selectable\n"
+       "    menu item - and current value is displayed inside brackets.\n"
+       "o The 'Selects:' line tell what symbol will be automatically\n"
+       "  selected if this symbol is selected (y or m)\n"
+       "o The 'Selected by' line tell 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 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_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';
+}
+
+
+static void search_conf(void)
+{
+       struct symbol **sym_arr;
+       struct gstr res;
+       char *dialog_input;
+       int dres;
+again:
+       dialog_clear();
+       dres = dialog_inputbox(_("Search Configuration Parameter"),
+                             _("Enter " CONFIG_ " (sub)string to search for "
+                               "(with or without \"" CONFIG_ "\")"),
+                             10, 75, "");
+       switch (dres) {
+       case 0:
+               break;
+       case 1:
+               show_helptext(_("Search Configuration"), search_help);
+               goto again;
+       default:
+               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);
+       free(sym_arr);
+       show_textbox(_("Search Results"), str_get(&res), 0, 0);
+       str_free(&res);
+}
+
+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  --->", indent + 1, ' ', prompt);
+
+                               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("  --->");
+                       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 *submenu;
+       const char *prompt = menu_get_prompt(menu);
+       struct symbol *sym;
+       struct menu *active_menu = NULL;
+       int res;
+       int s_scroll = 0;
+
+       while (1) {
+               item_reset();
+               current_menu = menu;
+               build_conf(menu);
+               if (!child_count)
+                       break;
+               if (menu == &rootmenu) {
+                       item_make("--- ");
+                       item_set_tag(':');
+                       item_make(_("    Load an Alternate Configuration File"));
+                       item_set_tag('L');
+                       item_make(_("    Save an Alternate Configuration File"));
+                       item_set_tag('S');
+               }
+               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_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);
+                               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);
+                               break;
+                       case 's':
+                               conf_string(submenu);
+                               break;
+                       case 'L':
+                               conf_load();
+                               break;
+                       case 'S':
+                               conf_save();
+                               break;
+                       }
+                       break;
+               case 2:
+                       if (sym)
+                               show_help(submenu);
+                       else
+                               show_helptext(_("README"), _(mconf_readme));
+                       break;
+               case 3:
+                       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 4:
+                       if (item_is_tag('t'))
+                               sym_set_tristate_value(sym, no);
+                       break;
+               case 5:
+                       if (item_is_tag('t'))
+                               sym_set_tristate_value(sym, mod);
+                       break;
+               case 6:
+                       if (item_is_tag('t'))
+                               sym_toggle_tristate_value(sym);
+                       else if (item_is_tag('m'))
+                               conf(submenu);
+                       break;
+               case 7:
+                       search_conf();
+                       break;
+               case 8:
+                       show_all_options = !show_all_options;
+                       break;
+               }
+       }
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+       dialog_clear();
+       dialog_textbox(title, text, r, c);
+}
+
+static void show_helptext(const char *title, const char *text)
+{
+       show_textbox(title, text, 0, 0);
+}
+
+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),
+                                        15, 70, 6);
+               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;
+               }
+       }
+}
+
+int main(int ac, char **av)
+{
+       int saved_x, saved_y;
+       char *mode;
+       int res;
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       conf_parse(av[1]);
+       conf_read(NULL);
+
+       mode = getenv("MENUCONFIG_MODE");
+       if (mode) {
+               if (!strcasecmp(mode, "single_menu"))
+                       single_menu_mode = 1;
+       }
+
+       initscr();
+
+       getyx(stdscr, saved_y, saved_x);
+       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());
+       do {
+               conf(&rootmenu);
+               dialog_clear();
+               if (conf_get_changed())
+                       res = dialog_yesno(NULL,
+                                          _("Do you wish to save your "
+                                            "new configuration?\n"
+                                            "<ESC><ESC> to continue."),
+                                          6, 60);
+               else
+                       res = -1;
+       } while (res == KEY_ESC);
+       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;
+               }
+       case -1:
+               printf(_("\n\n"
+                       "*** End of the configuration.\n"
+                       "*** Execute 'make' to start the build or try 'make help'."
+                       "\n\n"));
+               break;
+       default:
+               fprintf(stderr, _("\n\n"
+                       "Your configuration changes were NOT saved."
+                       "\n\n"));
+       }
+
+       return 0;
+}
+
diff --git a/bios/seabios/tools/kconfig/menu.c b/bios/seabios/tools/kconfig/menu.c
new file mode 100644 (file)
index 0000000..5fdf10d
--- /dev/null
@@ -0,0 +1,609 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static const char nohelp_text[] = N_(
+       "There is no help available for this option.\n");
+
+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 = malloc(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, "type of '%s' redefined 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) {
+                               if (!menu->visibility)
+                                       continue;
+                               prop->visible.expr
+                                       = expr_alloc_and(prop->visible.expr,
+                                                        menu->visibility);
+                       }
+               }
+
+               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)
+{
+       struct property *prop;
+
+       switch (token) {
+       case T_OPT_MODULES:
+               prop = prop_alloc(P_DEFAULT, modules_sym);
+               prop->expr = expr_alloc_symbol(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;
+       }
+}
+
+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 = 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;
+}
+
+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)
+{
+       int i, j;
+       struct menu *submenu[8], *menu;
+
+       str_printf(r, _("Prompt: %s\n"), _(prop->text));
+       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");
+       }
+       menu = prop->menu->parent;
+       for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
+               submenu[i++] = menu;
+       if (i > 0) {
+               str_printf(r, _("  Location:\n"));
+               for (j = 4; --i >= 0; j += 2) {
+                       menu = submenu[i];
+                       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");
+               }
+       }
+}
+
+void get_symbol_str(struct gstr *r, struct symbol *sym)
+{
+       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);
+       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 symbol *sym;
+       struct gstr res = str_new();
+       int i;
+
+       for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
+               get_symbol_str(&res, sym);
+       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;
+
+       if (menu_has_help(menu)) {
+               if (sym->name) {
+                       str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
+                       str_append(help, _(menu_get_help(menu)));
+                       str_append(help, "\n");
+               }
+       } else {
+               str_append(help, nohelp_text);
+       }
+       if (sym)
+               get_symbol_str(help, sym);
+}
diff --git a/bios/seabios/tools/kconfig/nconf.c b/bios/seabios/tools/kconfig/nconf.c
new file mode 100644 (file)
index 0000000..db56377
--- /dev/null
@@ -0,0 +1,1561 @@
+/*
+ * 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>
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+#include "nconf.h"
+#include <ctype.h>
+
+static const char nconf_readme[] = N_(
+"Overview\n"
+"--------\n"
+"This interface let 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"
+"  XXX cannot be selected. Use Symbol Info to find out why,\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 removed it.  You may also press the <Space Bar> to cycle\n"
+"through the available options (ie. 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\n"
+"   you wish to change use <Enter> or <Space>. Goto submenu by \n"
+"   pressing <Enter> of <right-arrow>. Use <Esc> or <left-arrow> to go back.\n"
+"   Submenus are designated by \"--->\".\n"
+"\n"
+"   Searching: pressing '/' triggers interactive search mode.\n"
+"              nconfig performs a case insensitive search for the string\n"
+"              in the menu prompts (no regex support).\n"
+"              Pressing the up/down keys highlights the previous/next\n"
+"              matching item. Backspace removes one character from the\n"
+"              match string. Pressing either '/' again or ESC exits\n"
+"              search mode. All other keys behave normally.\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 just press <ESC> <F5> <F8> or <left-arrow>.\n"
+"\n"
+"o  To get help with an item, press <F1>\n"
+"   Shortcut: Press <h> or <?>.\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, press <F1>\n"
+"   Shortcut: Press <H> or <?>.\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, press <F1>.\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 <SPACE BAR> for those\n"
+"   who are familiar with less and lynx.\n"
+"\n"
+"o  Press <Enter>, <F1>, <F5>, <F7> or <Esc> to exit.\n"
+"\n"
+"\n"
+"Alternate Configuration Files\n"
+"-----------------------------\n"
+"nconfig 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"
+"At the end of the main menu you will find two options.  One is\n"
+"for saving the current configuration to a file of your choosing.\n"
+"The other option is for loading a previously saved alternate\n"
+"configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you\n"
+"find during a nconfig session that you have completely messed\n"
+"up your settings, you may use the \"Load Alternate...\" option to\n"
+"restore your previously saved settings from \".config\" without\n"
+"restarting nconfig.\n"
+"\n"
+"Other information\n"
+"-----------------\n"
+"If you use nconfig in an XTERM window make sure you have your\n"
+"$TERM variable set to point to a xterm definition which supports color.\n"
+"Otherwise, nconfig will look rather bad.  nconfig will not\n"
+"display correctly in a RXVT window because rxvt displays only one\n"
+"intensity of color, bright.\n"
+"\n"
+"nconfig 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, rather\n"
+"than the default multimenu hierarchy, run the nconfig with NCONFIG_MODE\n"
+"environment variable set to single_menu. Example:\n"
+"\n"
+"make NCONFIG_MODE=single_menu nconfig\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"),
+menu_no_f_instructions[] = N_(
+" You do not have function keys support. Please follow the\n"
+" following instructions:\n"
+" Arrow keys navigate the menu.\n"
+" <Enter> or <right-arrow> selects submenus --->.\n"
+" Capital Letters are hotkeys.\n"
+" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
+" Pressing SpaceBar toggles between the above options.\n"
+" Press <Esc> or <left-arrow> to go back one menu,\n"
+" <?> or <h> for Help, </> for Search.\n"
+" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n"
+" Legend: [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
+" <Esc> always leaves the current window.\n"),
+menu_instructions[] = N_(
+" Arrow keys navigate the menu.\n"
+" <Enter> or <right-arrow> selects submenus --->.\n"
+" Capital Letters are hotkeys.\n"
+" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
+" Pressing SpaceBar toggles between the above options\n"
+" Press <Esc>, <F5> or <left-arrow> to go back one menu,\n"
+" <?>, <F1> or <h> for Help, </> for Search.\n"
+" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n"
+" Legend: [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
+" <Esc> always leaves the current window\n"),
+radiolist_instructions[] = N_(
+" Use the arrow keys to navigate this window or\n"
+" press the hotkey of the item you wish to select\n"
+" followed by the <SPACE BAR>.\n"
+" Press <?>, <F1> or <h> for additional information about this option.\n"),
+inputbox_instructions_int[] = N_(
+"Please enter a decimal value.\n"
+"Fractions will not be accepted.\n"
+"Press <RETURN> to accept, <ESC> to cancel."),
+inputbox_instructions_hex[] = N_(
+"Please enter a hexadecimal value.\n"
+"Press <RETURN> to accept, <ESC> to cancel."),
+inputbox_instructions_string[] = N_(
+"Please enter a string value.\n"
+"Press <RETURN> to accept, <ESC> to cancel."),
+setmod_text[] = N_(
+"This feature depends on another which\n"
+"has been configured as a module.\n"
+"As a result, this feature will be built as a module."),
+nohelp_text[] = N_(
+"There is no help available for this option.\n"),
+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\n"
+"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 therefor leave this blank to abort.\n"),
+save_config_text[] = N_(
+"Enter a filename to which this configuration should be saved\n"
+"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. Regular expressions\n"
+"are allowed.\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, MCA, 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 used in the menu structure for\n"
+"  this symbol\n"
+"o The 'Defined at' line tell at what file / line number the symbol\n"
+"  is defined\n"
+"o The 'Depends on:' line tell what symbols needs to be defined for\n"
+"  this symbol to be visible in the menu (selectable)\n"
+"o The 'Location:' lines tell where in the menu structure this symbol\n"
+"  is located\n"
+"    A location followed by a [ = y] indicate that this is a selectable\n"
+"    menu item - and current value is displayed inside brackets.\n"
+"o The 'Selects:' line tell what symbol will be automatically\n"
+"  selected if this symbol is selected (y or m)\n"
+"o The 'Selected by' line tell 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");
+
+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 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 = "Sym Info",
+               .key = F_SYMBOL,
+               .handler = handle_f2,
+       },
+       {
+               .key_str = "F3",
+               .func = "Insts",
+               .key = F_INSTS,
+               .handler = handle_f3,
+       },
+       {
+               .key_str = "F4",
+               .func = "Config",
+               .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 = "Sym Search",
+               .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;
+
+       for (i = 0; i < function_keys_num; i++) {
+               wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
+               mvwprintw(main_window, LINES-3, offset,
+                               "%s",
+                               function_keys[i].key_str);
+               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;
+       }
+       wattrset(main_window, attributes[NORMAL]);
+}
+
+/* help */
+static void handle_f1(int *key, struct menu *current_item)
+{
+       show_scroll_win(main_window,
+                       _("README"), _(nconf_readme));
+       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,
+                       _("Instructions"),
+                       _(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;
+       char dialog_input_result[100];
+       char *dialog_input;
+       int dres;
+again:
+       dres = dialog_inputbox(main_window,
+                       _("Search Configuration Parameter"),
+                       _("Enter " CONFIG_ " (sub)string to search for "
+                               "(with or without \"" CONFIG_ "\")"),
+                       "", dialog_input_result, 99);
+       switch (dres) {
+       case 0:
+               break;
+       case 1:
+               show_scroll_win(main_window,
+                               _("Search Configuration"), search_help);
+               goto again;
+       default:
+               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);
+       free(sym_arr);
+       show_scroll_win(main_window,
+                       _("Search Results"), str_get(&res));
+       str_free(&res);
+}
+
+
+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  --->",
+                                               indent + 1,
+                                               ' ', prompt);
+
+                               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("  --->");
+                       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();
+       wattrset(main_window, attributes[NORMAL]);
+       print_in_middle(stdscr, 1, 0, COLS,
+                       menu_backtitle,
+                       attributes[MAIN_HEADING]);
+
+       wattrset(main_window, attributes[MAIN_MENU_BOX]);
+       box(main_window, 0, 0);
+       wattrset(main_window, attributes[MAIN_MENU_HEADING]);
+       mvwprintw(main_window, 0, 3, " %s ", prompt);
+       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;
+       struct menu *active_menu = NULL;
+       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();
+               active_menu = (struct menu *)item_data();
+               if (!submenu || !menu_is_visible(submenu))
+                       continue;
+               if (submenu)
+                       sym = submenu->sym;
+               else
+                       sym = NULL;
+
+               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 = str_new();
+
+       if (menu && menu->sym && menu_has_help(menu)) {
+               if (menu->sym->name) {
+                       str_printf(&help, "%s%s:\n\n", CONFIG_, menu->sym->name);
+                       str_append(&help, _(menu_get_help(menu)));
+                       str_append(&help, "\n");
+                       get_symbol_str(&help, menu->sym);
+               } else {
+                       str_append(&help, _(menu_get_help(menu)));
+               }
+       } else {
+               str_append(&help, nohelp_text);
+       }
+       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);
+       char dialog_input_result[256];
+
+       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,
+                               sizeof(dialog_input_result));
+               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)
+{
+       char dialog_input_result[256];
+       while (1) {
+               int res;
+               res = dialog_inputbox(main_window,
+                               NULL, load_config_text,
+                               filename,
+                               dialog_input_result,
+                               sizeof(dialog_input_result));
+               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)
+{
+       char dialog_input_result[256];
+       while (1) {
+               int res;
+               res = dialog_inputbox(main_window,
+                               NULL, save_config_text,
+                               filename,
+                               dialog_input_result,
+                               sizeof(dialog_input_result));
+               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)
+{
+       if (main_window != NULL)
+               delwin(main_window);
+
+       /* set up the menu and menu window */
+       main_window = newwin(LINES-2, COLS-2, 2, 1);
+       keypad(main_window, TRUE);
+       mwin_max_lines = LINES-7;
+       mwin_max_cols = COLS-6;
+
+       /* panels order is from bottom to top */
+       new_panel(main_window);
+}
+
+int main(int ac, char **av)
+{
+       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);
+
+       if (COLS < 75 || LINES < 20) {
+               endwin();
+               printf("Your terminal should have at "
+                       "least 20 lines and 75 columns\n");
+               return 1;
+       }
+
+       notimeout(stdscr, FALSE);
+       ESCDELAY = 1;
+
+       /* 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/bios/seabios/tools/kconfig/nconf.gui.c b/bios/seabios/tools/kconfig/nconf.gui.c
new file mode 100644 (file)
index 0000000..f8137b3
--- /dev/null
@@ -0,0 +1,617 @@
+/*
+ * 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_BLUE, -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 = (LINES-(msg_lines+4))/2;
+       x = (COLS-(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 *result, 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);
+
+
+       /* 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 = (LINES-(prompt_lines+4))/2;
+       x = (COLS-(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, " ");
+       mvwprintw(form_win, 0, 0, "%s", result);
+
+       /* 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--;
+                       }
+                       break;
+               case KEY_DC:
+                       if (cursor_position >= 0 && cursor_position < len) {
+                               memmove(&result[cursor_position],
+                                               &result[cursor_position+1],
+                                               len-cursor_position+1);
+                       }
+                       break;
+               case KEY_UP:
+               case KEY_RIGHT:
+                       if (cursor_position < len &&
+                           cursor_position < min(result_len, prompt_width))
+                               cursor_position++;
+                       break;
+               case KEY_DOWN:
+               case KEY_LEFT:
+                       if (cursor_position > 0)
+                               cursor_position--;
+                       break;
+               default:
+                       if ((isgraph(res) || isspace(res)) &&
+                                       len-2 < result_len) {
+                               /* insert the char at the proper position */
+                               memmove(&result[cursor_position+1],
+                                               &result[cursor_position],
+                                               len+1);
+                               result[cursor_position] = res;
+                               cursor_position++;
+                       } else {
+                               mvprintw(0, 0, "unknow key: %d\n", res);
+                       }
+                       break;
+               }
+               wmove(form_win, 0, 0);
+               wclrtoeol(form_win);
+               mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
+               mvwprintw(form_win, 0, 0, "%s", result);
+               wmove(form_win, 0, cursor_position);
+               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;
+       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;
+
+       /* 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, COLS-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 = (COLS-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 ' ':
+                       start_y += text_lines-2;
+                       break;
+               case KEY_PPAGE:
+                       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_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/bios/seabios/tools/kconfig/nconf.h b/bios/seabios/tools/kconfig/nconf.h
new file mode 100644 (file)
index 0000000..58fbda8
--- /dev/null
@@ -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 *result, 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/bios/seabios/tools/kconfig/qconf.cc b/bios/seabios/tools/kconfig/qconf.cc
new file mode 100644 (file)
index 0000000..06dd2e3
--- /dev/null
@@ -0,0 +1,1787 @@
+/*
+ * 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 <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()));
+}
+
+/**
+ * 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();
+}
+
+void ConfigMainWindow::saveConfig(void)
+{
+       if (conf_write(NULL))
+               QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+}
+
+void ConfigMainWindow::saveConfigAs(void)
+{
+       QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this);
+       if (s.isNull())
+               return;
+       if (conf_write(QFile::encodeName(s)))
+               QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+}
+
+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:
+               conf_write(NULL);
+       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);
+
+#ifndef LKC_DIRECT_LINK
+       kconfig_load();
+#endif
+
+       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/bios/seabios/tools/kconfig/qconf.h b/bios/seabios/tools/kconfig/qconf.h
new file mode 100644 (file)
index 0000000..91677d9
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * 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:
+       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);
+       void 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/bios/seabios/tools/kconfig/symbol.c b/bios/seabios/tools/kconfig/symbol.c
new file mode 100644 (file)
index 0000000..a796c95
--- /dev/null
@@ -0,0 +1,1260 @@
+/*
+ * 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>
+
+#define LKC_DIRECT_LINK
+#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 int 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 strtol(sym->curr.val, NULL, base);
+}
+
+static void sym_validate_range(struct symbol *sym)
+{
+       struct property *prop;
+       int base, 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 = strtol(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, "%d", val2);
+       else
+               sprintf(str, "0x%x", 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;
+
+       /* first calculate all choice values' visibilities */
+       prop = sym_get_choice_prop(sym);
+       expr_list_for_each_sym(prop->expr, e, def_sym)
+               sym_calc_visibility(def_sym);
+
+       /* 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;
+       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;
+}
+
+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;
+       int 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 = strtol(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 = strtol(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 = malloc(size);
+               *val++ = '0';
+               *val++ = 'x';
+       } else if (!oldval || strcmp(oldval, newval))
+               sym->def[S_DEF_USER].val = val = malloc(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:
+                       return "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 = malloc(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 = malloc(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;
+}
+
+struct symbol **sym_re_search(const char *pattern)
+{
+       struct symbol *sym, **sym_arr = NULL;
+       int i, cnt, size;
+       regex_t re;
+
+       cnt = size = 0;
+       /* Skip if empty */
+       if (strlen(pattern) == 0)
+               return NULL;
+       if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
+               return NULL;
+
+       for_all_symbols(i, sym) {
+               if (sym->flags & SYMBOL_CONST || !sym->name)
+                       continue;
+               if (regexec(&re, sym->name, 0, NULL, 0))
+                       continue;
+               if (cnt + 1 >= size) {
+                       void *tmp = sym_arr;
+                       size += 16;
+                       sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
+                       if (!sym_arr) {
+                               free(tmp);
+                               return NULL;
+                       }
+               }
+               sym_calc_value(sym);
+               sym_arr[cnt++] = sym;
+       }
+       if (sym_arr)
+               sym_arr[cnt] = NULL;
+       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 inser() 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 = malloc(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/bios/seabios/tools/kconfig/util.c b/bios/seabios/tools/kconfig/util.c
new file mode 100644 (file)
index 0000000..6330cc8
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * 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 <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 = malloc(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 = malloc(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;
+}
+
diff --git a/bios/seabios/tools/kconfig/zconf.gperf b/bios/seabios/tools/kconfig/zconf.gperf
new file mode 100644 (file)
index 0000000..c9e690e
--- /dev/null
@@ -0,0 +1,47 @@
+%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 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
+%%
diff --git a/bios/seabios/tools/kconfig/zconf.hash.c_shipped b/bios/seabios/tools/kconfig/zconf.hash.c_shipped
new file mode 100644 (file)
index 0000000..4055d5d
--- /dev/null
@@ -0,0 +1,245 @@
+/* ANSI-C code produced by gperf version 3.0.3 */
+/* Command-line: gperf  */
+/* Computed positions: -k'1,3' */
+
+#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
+
+struct kconf_id;
+
+static struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
+/* maximum key range = 50, 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 unsigned char asso_values[] =
+    {
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 40,  5,
+       0,  0,  5, 52,  0, 20, 52, 52, 10, 20,
+       5,  0, 35, 52,  0, 30,  0, 15,  0, 52,
+      15, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52
+    };
+  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;
+}
+
+struct kconf_id_strings_t
+  {
+    char kconf_id_strings_str2[sizeof("on")];
+    char kconf_id_strings_str3[sizeof("env")];
+    char kconf_id_strings_str5[sizeof("endif")];
+    char kconf_id_strings_str6[sizeof("option")];
+    char kconf_id_strings_str7[sizeof("endmenu")];
+    char kconf_id_strings_str8[sizeof("optional")];
+    char kconf_id_strings_str9[sizeof("endchoice")];
+    char kconf_id_strings_str10[sizeof("range")];
+    char kconf_id_strings_str11[sizeof("choice")];
+    char kconf_id_strings_str12[sizeof("default")];
+    char kconf_id_strings_str13[sizeof("def_bool")];
+    char kconf_id_strings_str14[sizeof("help")];
+    char kconf_id_strings_str16[sizeof("config")];
+    char kconf_id_strings_str17[sizeof("def_tristate")];
+    char kconf_id_strings_str18[sizeof("hex")];
+    char kconf_id_strings_str19[sizeof("defconfig_list")];
+    char kconf_id_strings_str22[sizeof("if")];
+    char kconf_id_strings_str23[sizeof("int")];
+    char kconf_id_strings_str27[sizeof("modules")];
+    char kconf_id_strings_str28[sizeof("tristate")];
+    char kconf_id_strings_str29[sizeof("menu")];
+    char kconf_id_strings_str32[sizeof("comment")];
+    char kconf_id_strings_str35[sizeof("menuconfig")];
+    char kconf_id_strings_str36[sizeof("string")];
+    char kconf_id_strings_str37[sizeof("visible")];
+    char kconf_id_strings_str41[sizeof("prompt")];
+    char kconf_id_strings_str42[sizeof("depends")];
+    char kconf_id_strings_str44[sizeof("bool")];
+    char kconf_id_strings_str46[sizeof("select")];
+    char kconf_id_strings_str47[sizeof("boolean")];
+    char kconf_id_strings_str48[sizeof("mainmenu")];
+    char kconf_id_strings_str51[sizeof("source")];
+  };
+static struct kconf_id_strings_t kconf_id_strings_contents =
+  {
+    "on",
+    "env",
+    "endif",
+    "option",
+    "endmenu",
+    "optional",
+    "endchoice",
+    "range",
+    "choice",
+    "default",
+    "def_bool",
+    "help",
+    "config",
+    "def_tristate",
+    "hex",
+    "defconfig_list",
+    "if",
+    "int",
+    "modules",
+    "tristate",
+    "menu",
+    "comment",
+    "menuconfig",
+    "string",
+    "visible",
+    "prompt",
+    "depends",
+    "bool",
+    "select",
+    "boolean",
+    "mainmenu",
+    "source"
+  };
+#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
+#ifdef __GNUC__
+__inline
+#ifdef __GNUC_STDC_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+struct kconf_id *
+kconf_id_lookup (register const char *str, register unsigned int len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 32,
+      MIN_WORD_LENGTH = 2,
+      MAX_WORD_LENGTH = 14,
+      MIN_HASH_VALUE = 2,
+      MAX_HASH_VALUE = 51
+    };
+
+  static struct kconf_id wordlist[] =
+    {
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,            T_ON,           TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3,            T_OPT_ENV,      TF_OPTION},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,            T_ENDIF,        TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,            T_OPTION,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,    T_ENDMENU,      TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,    T_OPTIONAL,     TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,    T_ENDCHOICE,    TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10,           T_RANGE,        TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11,           T_CHOICE,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,   T_DEFAULT,      TF_COMMAND, S_UNKNOWN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,   T_DEFAULT,      TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,           T_HELP,         TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,           T_CONFIG,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,   T_DEFAULT,      TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,           T_TYPE,         TF_COMMAND, S_HEX},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19,   T_OPT_DEFCONFIG_LIST,TF_OPTION},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,           T_IF,           TF_COMMAND|TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,           T_TYPE,         TF_COMMAND, S_INT},
+      {-1}, {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,   T_OPT_MODULES,  TF_OPTION},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,   T_TYPE,         TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29,           T_MENU,         TF_COMMAND},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,   T_COMMENT,      TF_COMMAND},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35,   T_MENUCONFIG,   TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36,           T_TYPE,         TF_COMMAND, S_STRING},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,   T_VISIBLE,      TF_COMMAND},
+      {-1}, {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41,           T_PROMPT,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42,   T_DEPENDS,      TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str44,           T_TYPE,         TF_COMMAND, S_BOOLEAN},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46,           T_SELECT,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47,   T_TYPE,         TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48,   T_MAINMENU,     TF_COMMAND},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51,           T_SOURCE,       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;
+}
+
diff --git a/bios/seabios/tools/kconfig/zconf.l b/bios/seabios/tools/kconfig/zconf.l
new file mode 100644 (file)
index 0000000..3dbaec1
--- /dev/null
@@ -0,0 +1,360 @@
+%option backup nostdinit noyywrap never-interactive full ecs
+%option 8bit backup 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>
+
+#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;
+}
+%}
+
+ws     [ \n\t]
+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}+    {
+               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}|[-/.])+    {
+               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 = 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;
+       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;
+
+       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(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/bios/seabios/tools/kconfig/zconf.tab.c_shipped b/bios/seabios/tools/kconfig/zconf.tab.c_shipped
new file mode 100644 (file)
index 0000000..4c5495e
--- /dev/null
@@ -0,0 +1,2505 @@
+
+/* A Bison parser, made by GNU Bison 2.4.1.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   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.4.1"
+
+/* 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>
+
+#define LKC_DIRECT_LINK
+#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(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#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;
+       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 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 _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     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 _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+            && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (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 _STDLIB_H && (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)
+
+/* 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
+
+/* 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
+
+/* 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,   108,   108,   108,   110,   110,   112,   114,   115,   116,
+     117,   118,   119,   123,   127,   127,   127,   127,   127,   127,
+     127,   127,   131,   132,   133,   134,   135,   136,   140,   141,
+     147,   155,   161,   169,   179,   181,   182,   183,   184,   185,
+     186,   189,   197,   203,   213,   219,   225,   228,   230,   241,
+     242,   247,   256,   261,   269,   272,   274,   275,   276,   277,
+     278,   281,   287,   298,   304,   314,   316,   321,   329,   337,
+     340,   342,   343,   344,   349,   356,   363,   368,   376,   379,
+     381,   382,   383,   386,   394,   401,   408,   414,   421,   423,
+     424,   425,   428,   436,   438,   439,   442,   449,   451,   456,
+     457,   460,   461,   462,   466,   467,   470,   471,   474,   475,
+     476,   477,   478,   479,   480,   483,   484,   487,   488
+};
+#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 rule to reduce with in state
+   STATE-NUM 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 zero, do what YYDEFACT says.
+   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
+};
+
+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.  */
+
+#define YYFAIL         goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)                                 \
+do                                                             \
+  if (yychar == YYEMPTY && yylen == 1)                         \
+    {                                                          \
+      yychar = (Token);                                                \
+      yylval = (Value);                                                \
+      yytoken = YYTRANSLATE (yychar);                          \
+      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
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)                 \
+     fprintf (File, "%d.%d-%d.%d",                     \
+             (Loc).first_line, (Loc).first_column,     \
+             (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#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
+
+\f
+
+#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 YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+        constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+                   + sizeof yyexpecting - 1
+                   + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+                      * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+        YYCHECK.  */
+      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 yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+       if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+         {
+           if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+             {
+               yycount = 1;
+               yysize = yysize0;
+               yyformat[sizeof yyunexpected - 1] = '\0';
+               break;
+             }
+           yyarg[yycount++] = yytname[yyx];
+           yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+           yysize_overflow |= (yysize1 < yysize);
+           yysize = yysize1;
+           yyfmt = yystpcpy (yyfmt, yyprefix);
+           yyprefix = yyor;
+         }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+       return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+       {
+         /* 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 = yyresult;
+         int yyi = 0;
+         while ((*yyp = *yyf) != '\0')
+           {
+             if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+               {
+                 yyp += yytnamerr (yyp, yyarg[yyi++]);
+                 yyf += 2;
+               }
+             else
+               {
+                 yyp++;
+                 yyf++;
+               }
+           }
+       }
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+\f
+
+/*-----------------------------------------------.
+| 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 or yypush_parse.  |
+`-------------------------*/
+
+#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 (yyn == YYPACT_NINF)
+    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 (yyn == 0 || yyn == YYTABLE_NINF)
+       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:
+
+    {
+       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;
+    }
+  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:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (YY_("syntax error"));
+#else
+      {
+       YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+       if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+         {
+           YYSIZE_T yyalloc = 2 * yysize;
+           if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+             yyalloc = YYSTACK_ALLOC_MAXIMUM;
+           if (yymsg != yymsgbuf)
+             YYSTACK_FREE (yymsg);
+           yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+           if (yymsg)
+             yymsg_alloc = yyalloc;
+           else
+             {
+               yymsg = yymsgbuf;
+               yymsg_alloc = sizeof yymsgbuf;
+             }
+         }
+
+       if (0 < yysize && yysize <= yymsg_alloc)
+         {
+           (void) yysyntax_error (yymsg, yystate, yychar);
+           yyerror (yymsg);
+         }
+       else
+         {
+           yyerror (YY_("syntax error"));
+           if (yysize != 0)
+             goto yyexhaustedlab;
+         }
+      }
+#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 (yyn != YYPACT_NINF)
+       {
+         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)
+     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();
+       modules_sym = sym_lookup(NULL, 0);
+       modules_sym->type = S_BOOLEAN;
+       modules_sym->flags |= SYMBOL_AUTO;
+       rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
+
+#if YYDEBUG
+       if (getenv("ZCONF_DEBUG"))
+               zconfdebug = 1;
+#endif
+       zconfparse();
+       if (zconfnerrs)
+               exit(1);
+       if (!modules_sym->prop) {
+               struct property *prop;
+
+               prop = prop_alloc(P_DEFAULT, modules_sym);
+               prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+       }
+
+       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(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)
+{
+#if YYDEBUG
+       fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+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 "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
+
diff --git a/bios/seabios/tools/kconfig/zconf.y b/bios/seabios/tools/kconfig/zconf.y
new file mode 100644 (file)
index 0000000..49fb4ab
--- /dev/null
@@ -0,0 +1,749 @@
+%{
+/*
+ * 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>
+
+#define LKC_DIRECT_LINK
+#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(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+%}
+%expect 30
+
+%union
+{
+       char *string;
+       struct file *file;
+       struct symbol *symbol;
+       struct expr *expr;
+       struct menu *menu;
+       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
+{
+       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();
+       modules_sym = sym_lookup(NULL, 0);
+       modules_sym->type = S_BOOLEAN;
+       modules_sym->flags |= SYMBOL_AUTO;
+       rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
+
+#if YYDEBUG
+       if (getenv("ZCONF_DEBUG"))
+               zconfdebug = 1;
+#endif
+       zconfparse();
+       if (zconfnerrs)
+               exit(1);
+       if (!modules_sym->prop) {
+               struct property *prop;
+
+               prop = prop_alloc(P_DEFAULT, modules_sym);
+               prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+       }
+
+       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(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)
+{
+#if YYDEBUG
+       fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+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 "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
diff --git a/bios/seabios/tools/layoutrom.py b/bios/seabios/tools/layoutrom.py
new file mode 100755 (executable)
index 0000000..45738a3
--- /dev/null
@@ -0,0 +1,579 @@
+#!/usr/bin/env python
+# Script to analyze code and arrange ld sections.
+#
+# Copyright (C) 2008-2010  Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+
+# LD script headers/trailers
+COMMONHEADER = """
+/* DO NOT EDIT!  This is an autogenerated file.  See tools/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)
+                }
+}
+"""
+
+
+######################################################################
+# 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):
+    totspace = 0
+    for section in sections:
+        if section.align > minalign:
+            minalign = section.align
+        totspace = alignpos(totspace, section.align) + section.size
+    startaddr = (endaddr - totspace) / minalign * minalign
+    curaddr = startaddr
+    # out = [(addr, sectioninfo), ...]
+    out = []
+    for section in sections:
+        curaddr = alignpos(curaddr, section.align)
+        section.finalloc = curaddr
+        curaddr += section.size
+    return startaddr
+
+# The 16bit code can't exceed 64K of space.
+BUILD_BIOS_ADDR = 0xf0000
+BUILD_BIOS_SIZE = 0x10000
+
+# 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
+            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()
+    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()
+
+    # 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.finalloc + 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
+            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
+
+# Return the subset of sections with a given name prefix
+def getSectionsPrefix(sections, category, prefix):
+    return [section for section in sections
+            if section.category == category and section.name.startswith(prefix)]
+
+def doLayout(sections):
+    # Determine 16bit positions
+    textsections = getSectionsPrefix(sections, '16', '.text.')
+    rodatasections = (getSectionsPrefix(sections, '16', '.rodata.str1.1')
+                      + getSectionsPrefix(sections, '16', '.rodata.__func__.'))
+    datasections = getSectionsPrefix(sections, '16', '.data16.')
+    fixedsections = getSectionsPrefix(sections, '16', '.fixedaddr.')
+
+    firstfixed = fitSections(fixedsections, textsections)
+    remsections = [s for s in textsections+rodatasections+datasections
+                   if s.finalloc is None]
+    code16_start = setSectionsStart(remsections, firstfixed)
+
+    # Determine 32seg positions
+    textsections = getSectionsPrefix(sections, '32seg', '.text.')
+    rodatasections = (getSectionsPrefix(sections, '32seg', '.rodata.str1.1')
+                      +getSectionsPrefix(sections, '32seg', '.rodata.__func__.'))
+    datasections = getSectionsPrefix(sections, '32seg', '.data32seg.')
+
+    code32seg_start = setSectionsStart(
+        textsections + rodatasections + datasections, code16_start)
+
+    # Determine 32flat runtime positions
+    textsections = getSectionsPrefix(sections, '32flat', '.text.')
+    rodatasections = getSectionsPrefix(sections, '32flat', '.rodata')
+    datasections = getSectionsPrefix(sections, '32flat', '.data.')
+    bsssections = getSectionsPrefix(sections, '32flat', '.bss.')
+
+    code32flat_start = setSectionsStart(
+        textsections + rodatasections + datasections + bsssections
+        , code32seg_start + BUILD_BIOS_ADDR, 16)
+
+    # Determine 32flat init positions
+    textsections = getSectionsPrefix(sections, '32init', '.text.')
+    rodatasections = getSectionsPrefix(sections, '32init', '.rodata')
+    datasections = getSectionsPrefix(sections, '32init', '.data.')
+    bsssections = getSectionsPrefix(sections, '32init', '.bss.')
+
+    code32init_start = setSectionsStart(
+        textsections + rodatasections + datasections + bsssections
+        , code32flat_start, 16)
+
+    # Print statistics
+    size16 = BUILD_BIOS_SIZE - code16_start
+    size32seg = code16_start - code32seg_start
+    size32flat = code32seg_start + BUILD_BIOS_ADDR - code32flat_start
+    size32init = code32flat_start - code32init_start
+    print "16bit size:           %d" % size16
+    print "32bit segmented size: %d" % size32seg
+    print "32bit flat size:      %d" % size32flat
+    print "32bit flat init size: %d" % size32init
+
+
+######################################################################
+# Linker script output
+######################################################################
+
+# Write LD script includes for the given cross references
+def outXRefs(sections):
+    xrefs = {}
+    out = ""
+    for section in sections:
+        for reloc in section.relocs:
+            symbol = reloc.symbol
+            if (symbol.section is None
+                or (symbol.section.fileid == section.fileid
+                    and symbol.name == reloc.symbolname)
+                or reloc.symbolname in xrefs):
+                continue
+            xrefs[reloc.symbolname] = 1
+            addr = symbol.section.finalloc + symbol.offset
+            if (section.fileid == '32flat'
+                and symbol.section.fileid in ('16', '32seg')):
+                addr += BUILD_BIOS_ADDR
+            out += "%s = 0x%x ;\n" % (reloc.symbolname, addr)
+    return out
+
+# Write LD script includes for the given sections using relative offsets
+def outRelSections(sections, startsym):
+    out = ""
+    for section in sections:
+        out += ". = ( 0x%x - %s ) ;\n" % (section.finalloc, startsym)
+        if section.name == '.rodata.str1.1':
+            out += "_rodata = . ;\n"
+        out += "*(%s)\n" % (section.name,)
+    return out
+
+def getSectionsFile(sections, fileid, defaddr=0):
+    sections = [(section.finalloc, section)
+                for section in sections if section.fileid == fileid]
+    sections.sort()
+    sections = [section for addr, section in sections]
+    pos = defaddr
+    if sections:
+        pos = sections[0].finalloc
+    return sections, pos
+
+# Layout the 32bit segmented code.  This places the code as high as possible.
+def writeLinkerScripts(sections, entrysym, genreloc, out16, out32seg, out32flat):
+    # Write 16bit linker script
+    sections16, code16_start = getSectionsFile(sections, '16')
+    output = open(out16, 'wb')
+    output.write(COMMONHEADER + outXRefs(sections16) + """
+    code16_start = 0x%x ;
+    .text16 code16_start : {
+""" % (code16_start)
+                 + outRelSections(sections16, 'code16_start')
+                 + """
+    }
+"""
+                 + COMMONTRAILER)
+    output.close()
+
+    # Write 32seg linker script
+    sections32seg, code32seg_start = getSectionsFile(
+        sections, '32seg', code16_start)
+    output = open(out32seg, 'wb')
+    output.write(COMMONHEADER + outXRefs(sections32seg) + """
+    code32seg_start = 0x%x ;
+    .text32seg code32seg_start : {
+""" % (code32seg_start)
+                 + outRelSections(sections32seg, 'code32seg_start')
+                 + """
+    }
+"""
+                 + COMMONTRAILER)
+    output.close()
+
+    # Write 32flat linker script
+    sections32flat, code32flat_start = getSectionsFile(
+        sections, '32flat', code32seg_start)
+    relocstr = ""
+    relocminalign = 0
+    if genreloc:
+        # Generate relocations
+        relocstr, size, relocminalign = genRelocs(sections)
+        code32flat_start -= size
+    output = open(out32flat, 'wb')
+    output.write(COMMONHEADER
+                 + outXRefs(sections32flat) + """
+    %s = 0x%x ;
+    _reloc_min_align = 0x%x ;
+    code32flat_start = 0x%x ;
+    .text code32flat_start : {
+""" % (entrysym.name,
+       entrysym.section.finalloc + entrysym.offset + BUILD_BIOS_ADDR,
+       relocminalign, code32flat_start)
+                 + relocstr
+                 + """
+        code32init_start = ABSOLUTE(.) ;
+"""
+                 + outRelSections(getSectionsPrefix(sections32flat, '32init', '')
+                                  , 'code32flat_start')
+                 + """
+        code32init_end = ABSOLUTE(.) ;
+"""
+                 + outRelSections(getSectionsPrefix(sections32flat, '32flat', '')
+                                  , 'code32flat_start')
+                 + """
+        . = ( 0x%x - code32flat_start ) ;
+        *(.text32seg)
+        . = ( 0x%x - code32flat_start ) ;
+        *(.text16)
+        code32flat_end = ABSOLUTE(.) ;
+    } :text
+""" % (code32seg_start + BUILD_BIOS_ADDR, code16_start + BUILD_BIOS_ADDR)
+                 + COMMONTRAILER
+                 + """
+ENTRY(%s)
+PHDRS
+{
+        text PT_LOAD AT ( code32flat_start ) ;
+}
+""" % (entrysym.name,))
+    output.close()
+
+
+######################################################################
+# Detection of init code
+######################################################################
+
+# Determine init section relocations
+def genRelocs(sections):
+    absrelocs = []
+    relrelocs = []
+    initrelocs = []
+    minalign = 16
+    for section in sections:
+        if section.category == '32init' and section.align > minalign:
+            minalign = section.align
+        for reloc in section.relocs:
+            symbol = reloc.symbol
+            if symbol.section is None:
+                continue
+            relocpos = section.finalloc + reloc.offset
+            if (reloc.type == 'R_386_32' and section.category == '32init'
+                and symbol.section.category == '32init'):
+                # Absolute relocation
+                absrelocs.append(relocpos)
+            elif (reloc.type == 'R_386_PC32' and section.category == '32init'
+                  and symbol.section.category != '32init'):
+                # Relative relocation
+                relrelocs.append(relocpos)
+            elif (section.category != '32init'
+                  and symbol.section.category == '32init'):
+                # Relocation to the init section
+                if section.fileid in ('16', '32seg'):
+                    relocpos += BUILD_BIOS_ADDR
+                initrelocs.append(relocpos)
+    absrelocs.sort()
+    relrelocs.sort()
+    initrelocs.sort()
+    out = ("        _reloc_abs_start = ABSOLUTE(.) ;\n"
+           + "".join(["LONG(0x%x - code32init_start)\n" % (pos,)
+                      for pos in absrelocs])
+           + "        _reloc_abs_end = ABSOLUTE(.) ;\n"
+           + "        _reloc_rel_start = ABSOLUTE(.) ;\n"
+           + "".join(["LONG(0x%x - code32init_start)\n" % (pos,)
+                      for pos in relrelocs])
+           + "        _reloc_rel_end = ABSOLUTE(.) ;\n"
+           + "        _reloc_init_start = ABSOLUTE(.) ;\n"
+           + "".join(["LONG(0x%x - code32flat_start)\n" % (pos,)
+                      for pos in initrelocs])
+           + "        _reloc_init_end = ABSOLUTE(.) ;\n")
+    return out, len(absrelocs + relrelocs + initrelocs) * 4, minalign
+
+def markRuntime(section, sections):
+    if (section is None or not section.keep or section.category is not None
+        or '.init.' in section.name or section.fileid != '32flat'):
+        return
+    section.category = '32flat'
+    # Recursively mark all sections this section points to
+    for reloc in section.relocs:
+        markRuntime(reloc.symbol.section, sections)
+
+def findInit(sections):
+    # Recursively find and mark all "runtime" sections.
+    for section in sections:
+        if '.runtime.' in section.name or '.export.' in section.name:
+            markRuntime(section, sections)
+    for section in sections:
+        if section.category is not None:
+            continue
+        if section.fileid == '32flat':
+            section.category = '32init'
+        else:
+            section.category = section.fileid
+
+
+######################################################################
+# Section garbage collection
+######################################################################
+
+CFUNCPREFIX = [('_cfunc16_', 0), ('_cfunc32seg_', 1), ('_cfunc32flat_', 2)]
+
+# Find and keep the section associated with a symbol (if available).
+def keepsymbol(reloc, infos, pos, isxref):
+    symbolname = reloc.symbolname
+    mustbecfunc = 0
+    for symprefix, needpos in CFUNCPREFIX:
+        if symbolname.startswith(symprefix):
+            if needpos != pos:
+                return -1
+            symbolname = symbolname[len(symprefix):]
+            mustbecfunc = 1
+            break
+    symbol = infos[pos][1].get(symbolname)
+    if (symbol is None or symbol.section is None
+        or symbol.section.name.startswith('.discard.')):
+        return -1
+    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 -1
+
+    reloc.symbol = symbol
+    keepsection(symbol.section, infos, pos)
+    return 0
+
+# Note required section, and recursively set all referenced sections
+# as required.
+def keepsection(section, infos, pos=0):
+    if section.keep:
+        # Already kept - nothing to do.
+        return
+    section.keep = 1
+    # Keep all sections that this section points to
+    for reloc in section.relocs:
+        ret = keepsymbol(reloc, infos, pos, 0)
+        if not ret:
+            continue
+        # Not in primary sections - it may be a cross 16/32 reference
+        ret = keepsymbol(reloc, infos, (pos+1)%3, 1)
+        if not ret:
+            continue
+        ret = keepsymbol(reloc, infos, (pos+2)%3, 1)
+        if not ret:
+            continue
+
+# Determine which sections are actually referenced and need to be
+# placed into the output file.
+def gc(info16, info32seg, info32flat):
+    # infos = ((sections16, symbols16), (sect32seg, sym32seg)
+    #          , (sect32flat, sym32flat))
+    infos = (info16, info32seg, info32flat)
+    # Start by keeping sections that are globally visible.
+    for section in info16[0]:
+        if section.name.startswith('.fixedaddr.') or '.export.' in section.name:
+            keepsection(section, infos)
+    return [section for section in info16[0]+info32seg[0]+info32flat[0]
+            if section.keep]
+
+
+######################################################################
+# Startup and input parsing
+######################################################################
+
+class Section:
+    name = size = alignment = fileid = relocs = None
+    finalloc = category = keep = 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:
+                sectionname, size, name = line[17:].split()
+                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
+
+def main():
+    # Get output name
+    in16, in32seg, in32flat, out16, out32seg, out32flat = sys.argv[1:]
+
+    # Read in the objdump information
+    infile16 = open(in16, 'rb')
+    infile32seg = open(in32seg, 'rb')
+    infile32flat = open(in32flat, 'rb')
+
+    # infoX = (sections, symbols)
+    info16 = parseObjDump(infile16, '16')
+    info32seg = parseObjDump(infile32seg, '32seg')
+    info32flat = parseObjDump(infile32flat, '32flat')
+
+    # Figure out which sections to keep.
+    sections = gc(info16, info32seg, info32flat)
+
+    # Separate 32bit flat into runtime and init parts
+    findInit(sections)
+
+    # Determine the final memory locations of each kept section.
+    doLayout(sections)
+
+    # Write out linker script files.
+    entrysym = info16[1]['entry_elf']
+    genreloc = '_reloc_abs_start' in info32flat[1]
+    writeLinkerScripts(sections, entrysym, genreloc, out16, out32seg, out32flat)
+
+if __name__ == '__main__':
+    main()
diff --git a/bios/seabios/tools/layoutrom.pyc b/bios/seabios/tools/layoutrom.pyc
new file mode 100644 (file)
index 0000000..f0425ce
Binary files /dev/null and b/bios/seabios/tools/layoutrom.pyc differ
diff --git a/bios/seabios/tools/readserial.py b/bios/seabios/tools/readserial.py
new file mode 100755 (executable)
index 0000000..d85392e
--- /dev/null
@@ -0,0 +1,186 @@
+#!/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:
+#   tools/readserial.py /dev/ttyUSB0 115200
+
+import sys
+import time
+import select
+import optparse
+
+# 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(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")
+            break
+        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:
+            break
+        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(msg)
+        lasttime = datatime
+
+        # Translate unprintable chars; add timestamps
+        out = ""
+        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
+
+        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 file 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)
+    else:
+        # Read from a file
+        ser = open(serialport, 'rb')
+        import fcntl
+        import os
+        fcntl.fcntl(ser, fcntl.F_SETFL
+                    , fcntl.fcntl(ser, fcntl.F_GETFL) | os.O_NONBLOCK)
+
+    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')
+    readserial(ser, f, byteadjust)
+
+if __name__ == '__main__':
+    main()
diff --git a/bios/seabios/tools/test-gcc.sh b/bios/seabios/tools/test-gcc.sh
new file mode 100755 (executable)
index 0000000..935f211
--- /dev/null
@@ -0,0 +1,121 @@
+#!/bin/sh
+# Script to test if gcc "-fwhole-program" works properly.
+
+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
+$LD -T $TMPFILE1_ld $TMPFILE1o -o $TMPFILE2o > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+    echo "The version of LD on this system does not properly handle" > /dev/fd/2
+    echo "alignments.  As a result, this project can not be built." > /dev/fd/2
+    echo "" > /dev/fd/2
+    echo "The problem may be the result of this LD bug report:" > /dev/fd/2
+    echo " http://sourceware.org/bugzilla/show_bug.cgi?id=12726" > /dev/fd/2
+    echo "" > /dev/fd/2
+    echo "Please update to a working version of binutils and retry." > /dev/fd/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" > /dev/fd/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" > /dev/fd/2
+    echo 2
+    exit 0
+fi
+
+# Test if "-combine" works.  On Ubuntu 8.04 the compiler doesn't work
+# correctly with combine and the "struct bregs" register due to the
+# anonymous unions and structs.  On Fedora Core 12 the compiler throws
+# an internal compiler error when multiple files access global
+# variables with debugging enabled.
+cat - > $TMPFILE1 <<EOF
+// Look for anonymous union/struct failure
+struct ts { union { int u1; struct { int u2; }; }; };
+void func1(struct ts *r);
+
+// Look for global variable failure.
+struct s1_s { int v; } g1;
+void __attribute__((externally_visible)) func2() {
+    struct s1_s *l1 = &g1;
+    l1->v=0;
+}
+EOF
+cat - > $TMPFILE2 <<EOF
+struct ts { union { int u1; struct { int u2; }; }; };
+void func1(struct ts *r);
+
+extern struct s1_s g1;
+void func3() {
+    &g1;
+}
+EOF
+$CC -O -g -fwhole-program -combine -c $TMPFILE1 $TMPFILE2 -o $TMPFILE1o > /dev/null 2>&1
+if [ $? -eq 0 ]; then
+    echo 0
+else
+    echo "  Working around non-functional -combine" > /dev/fd/2
+    echo 1
+fi
+
+# Also, on several compilers, -combine fails if code is emitted with a
+# reference to an extern variable that is later found to be externally
+# visible - the compiler does not mark those variables as global.
+# This is being worked around by ordering the compile objects to avoid
+# this case.
+
+# 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/bios/seabios/tools/transdump.py b/bios/seabios/tools/transdump.py
new file mode 100755 (executable)
index 0000000..4caaeb7
--- /dev/null
@@ -0,0 +1,50 @@
+#!/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:
+        sys.stdout.write(struct.pack("<I", i))
+
+if __name__ == '__main__':
+    main()
diff --git a/bios/seabios/vgasrc/clext.c b/bios/seabios/vgasrc/clext.c
new file mode 100644 (file)
index 0000000..36ccad3
--- /dev/null
@@ -0,0 +1,390 @@
+//  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 "vgatables.h" // cirrus_init
+#include "biosvar.h" // GET_GLOBAL
+#include "util.h" // dprintf
+
+struct cirrus_mode_s {
+    /* + 0 */
+    u16 mode;
+    u16 width;
+    u16 height;
+    u16 depth;
+    /* + 8 */
+    u16 hidden_dac; /* 0x3c6 */
+    u16 *seq; /* 0x3c4 */
+    u16 *graph; /* 0x3ce */
+    u16 *crtc; /* 0x3d4 */
+    /* +16 */
+    u8 bitsperpixel;
+    u8 vesacolortype;
+    u8 vesaredmask;
+    u8 vesaredpos;
+    u8 vesagreenmask;
+    u8 vesagreenpos;
+    u8 vesabluemask;
+    u8 vesabluepos;
+    /* +24 */
+    u8 vesareservedmask;
+    u8 vesareservedpos;
+};
+
+/* 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,0x0013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+    0x001a,0x321b,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,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18,
+    0x001a,0x221b,0x001d,
+    0xffff
+};
+
+static struct cirrus_mode_s cirrus_modes[] VAR16 = {
+    {0x5f,640,480,8,0x00,
+     cseq_640x480x8,cgraph_svgacolor,ccrtc_640x480x8,8,
+     4,0,0,0,0,0,0,0,0},
+    {0x64,640,480,16,0xe1,
+     cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16,
+     6,5,11,6,5,5,0,0,0},
+    {0x66,640,480,15,0xf0,
+     cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16,
+     6,5,10,5,5,5,0,1,15},
+    {0x71,640,480,24,0xe5,
+     cseq_640x480x24,cgraph_svgacolor,ccrtc_640x480x24,24,
+     6,8,16,8,8,8,0,0,0},
+
+    {0x5c,800,600,8,0x00,
+     cseq_800x600x8,cgraph_svgacolor,ccrtc_800x600x8,8,
+     4,0,0,0,0,0,0,0,0},
+    {0x65,800,600,16,0xe1,
+     cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16,
+     6,5,11,6,5,5,0,0,0},
+    {0x67,800,600,15,0xf0,
+     cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16,
+     6,5,10,5,5,5,0,1,15},
+
+    {0x60,1024,768,8,0x00,
+     cseq_1024x768x8,cgraph_svgacolor,ccrtc_1024x768x8,8,
+     4,0,0,0,0,0,0,0,0},
+    {0x74,1024,768,16,0xe1,
+     cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16,
+     6,5,11,6,5,5,0,0,0},
+    {0x68,1024,768,15,0xf0,
+     cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16,
+     6,5,10,5,5,5,0,1,15},
+
+    {0x78,800,600,24,0xe5,
+     cseq_800x600x24,cgraph_svgacolor,ccrtc_800x600x24,24,
+     6,8,16,8,8,8,0,0,0},
+    {0x79,1024,768,24,0xe5,
+     cseq_1024x768x24,cgraph_svgacolor,ccrtc_1024x768x24,24,
+     6,8,16,8,8,8,0,0,0},
+
+    {0x6d,1280,1024,8,0x00,
+     cseq_1280x1024x8,cgraph_svgacolor,ccrtc_1280x1024x8,8,
+     4,0,0,0,0,0,0,0,0},
+    {0x69,1280,1024,15,0xf0,
+     cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16,
+     6,5,10,5,5,5,0,1,15},
+    {0x75,1280,1024,16,0xe1,
+     cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16,
+     6,5,11,6,5,5,0,0,0},
+
+    {0x7b,1600,1200,8,0x00,
+     cseq_1600x1200x8,cgraph_svgacolor,ccrtc_1600x1200x8,8,
+     4,0,0,0,0,0,0,0,0},
+
+    {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0,
+     0xff,0,0,0,0,0,0,0,0},
+};
+
+static struct cirrus_mode_s *
+cirrus_get_modeentry(u8 mode)
+{
+    struct cirrus_mode_s *table_g = cirrus_modes;
+    while (table_g < &cirrus_modes[ARRAY_SIZE(cirrus_modes)]) {
+        u16 tmode = GET_GLOBAL(table_g->mode);
+        if (tmode == mode)
+            return table_g;
+        table_g++;
+    }
+    return NULL;
+}
+
+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 u16
+cirrus_get_crtc(void)
+{
+    if (inb(VGAREG_READ_MISC_OUTPUT) & 1)
+        return VGAREG_VGA_CRTC_ADDRESS;
+    return VGAREG_MDA_CRTC_ADDRESS;
+}
+
+static void
+cirrus_switch_mode(struct cirrus_mode_s *table)
+{
+    // Unlock cirrus special
+    outw(0x1206, VGAREG_SEQU_ADDRESS);
+    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), cirrus_get_crtc());
+
+    outb(0x00, VGAREG_PEL_MASK);
+    inb(VGAREG_PEL_MASK);
+    inb(VGAREG_PEL_MASK);
+    inb(VGAREG_PEL_MASK);
+    inb(VGAREG_PEL_MASK);
+    outb(GET_GLOBAL(table->hidden_dac), VGAREG_PEL_MASK);
+    outb(0xff, VGAREG_PEL_MASK);
+
+    u8 vesacolortype = GET_GLOBAL(table->vesacolortype);
+    u8 v = vgahw_get_single_palette_reg(0x10) & 0xfe;
+    if (vesacolortype == 3)
+        v |= 0x41;
+    else if (vesacolortype)
+        v |= 0x01;
+    vgahw_set_single_palette_reg(0x10, v);
+}
+
+void
+cirrus_set_video_mode(u8 mode)
+{
+    dprintf(1, "cirrus mode %d\n", mode);
+    SET_BDA(vbe_mode, 0);
+    struct cirrus_mode_s *table_g = cirrus_get_modeentry(mode & 0x7f);
+    if (table_g) {
+        //XXX - cirrus_set_video_mode_extended(table);
+        return;
+    }
+    table_g = cirrus_get_modeentry(0xfe);
+    cirrus_switch_mode(table_g);
+    dprintf(1, "cirrus mode switch regular\n");
+}
+
+static int
+cirrus_check(void)
+{
+    outw(0x9206, VGAREG_SEQU_ADDRESS);
+    return inb(VGAREG_SEQU_DATA) == 0x12;
+}
+
+void
+cirrus_init(void)
+{
+    dprintf(1, "cirrus init\n");
+    if (! cirrus_check())
+        return;
+    dprintf(1, "cirrus init 2\n");
+
+    // memory setup
+    outb(0x0f, VGAREG_SEQU_ADDRESS);
+    u8 v = inb(VGAREG_SEQU_DATA);
+    outb(((v & 0x18) << 8) | 0x0a, VGAREG_SEQU_ADDRESS);
+    // set vga mode
+    outw(0x0007, VGAREG_SEQU_ADDRESS);
+    // reset bitblt
+    outw(0x0431, VGAREG_GRDC_ADDRESS);
+    outw(0x0031, VGAREG_GRDC_ADDRESS);
+}
diff --git a/bios/seabios/vgasrc/vga.c b/bios/seabios/vgasrc/vga.c
new file mode 100644 (file)
index 0000000..d734e23
--- /dev/null
@@ -0,0 +1,1387 @@
+// VGA bios implementation
+//
+// 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.
+
+
+// TODO:
+//  * review correctness of converted asm by comparing with RBIL
+//
+//  * convert vbe/clext code
+
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_BDA
+#include "util.h" // memset
+#include "vgatables.h" // find_vga_entry
+
+// XXX
+#define CONFIG_VBE 0
+#define CONFIG_CIRRUS 0
+
+// XXX
+#define DEBUG_VGA_POST 1
+#define DEBUG_VGA_10 3
+
+#define SET_VGA(var, val) SET_FARVAR(get_global_seg(), (var), (val))
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+static inline void
+call16_vgaint(u32 eax, u32 ebx)
+{
+    asm volatile(
+        "int $0x10\n"
+        "cli\n"
+        "cld"
+        :
+        : "a"(eax), "b"(ebx)
+        : "cc", "memory");
+}
+
+static void
+perform_gray_scale_summing(u16 start, u16 count)
+{
+    vgahw_screen_disable();
+    int i;
+    for (i = start; i < start+count; i++) {
+        u8 rgb[3];
+        vgahw_get_dac_regs(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;
+
+        vgahw_set_dac_regs(GET_SEG(SS), rgb, i, 1);
+    }
+    vgahw_screen_enable();
+}
+
+static void
+set_cursor_shape(u8 start, u8 end)
+{
+    start &= 0x3f;
+    end &= 0x1f;
+
+    u16 curs = (start << 8) + end;
+    SET_BDA(cursor_type, curs);
+
+    u8 modeset_ctl = GET_BDA(modeset_ctl);
+    u16 cheight = GET_BDA(char_height);
+    if ((modeset_ctl & 0x01) && (cheight > 8) && (end < 8) && (start < 0x20)) {
+        if (end != (start + 1))
+            start = ((start + 1) * cheight / 8) - 1;
+        else
+            start = ((end + 1) * cheight / 8) - 2;
+        end = ((end + 1) * cheight / 8) - 1;
+    }
+    vgahw_set_cursor_shape(start, end);
+}
+
+static u16
+get_cursor_shape(u8 page)
+{
+    if (page > 7)
+        return 0;
+    // FIXME should handle VGA 14/16 lines
+    return GET_BDA(cursor_type);
+}
+
+static void
+set_cursor_pos(struct cursorpos cp)
+{
+    // Should not happen...
+    if (cp.page > 7)
+        return;
+
+    // Bios cursor pos
+    SET_BDA(cursor_pos[cp.page], (cp.y << 8) | cp.x);
+
+    // Set the hardware cursor
+    u8 current = GET_BDA(video_page);
+    if (cp.page != current)
+        return;
+
+    // Get the dimensions
+    u16 nbcols = GET_BDA(video_cols);
+    u16 nbrows = GET_BDA(video_rows) + 1;
+
+    // Calculate the address knowing nbcols nbrows and page num
+    u16 address = (SCREEN_IO_START(nbcols, nbrows, cp.page)
+                   + cp.x + cp.y * nbcols);
+
+    vgahw_set_cursor_pos(address);
+}
+
+static 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;
+    }
+    // FIXME should handle VGA 14/16 lines
+    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 = find_vga_entry(GET_BDA(video_mode));
+    if (!vmode_g)
+        return;
+
+    // Get pos curs pos for the right page
+    struct cursorpos cp = get_cursor_pos(page);
+
+    u16 address;
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
+        // Get the dimensions
+        u16 nbcols = GET_BDA(video_cols);
+        u16 nbrows = GET_BDA(video_rows) + 1;
+
+        // Calculate the address knowing nbcols nbrows and page num
+        address = SCREEN_MEM_START(nbcols, nbrows, page);
+        SET_BDA(video_pagestart, address);
+
+        // Start address
+        address = SCREEN_IO_START(nbcols, nbrows, page);
+    } else {
+        struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+        address = page * GET_GLOBAL(vparam_g->slength);
+    }
+
+    vgahw_set_active_page(address);
+
+    // And change the BIOS page
+    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(cp);
+}
+
+static void
+set_scan_lines(u8 lines)
+{
+    vgahw_set_scan_lines(lines);
+    if (lines == 8)
+        set_cursor_shape(0x06, 0x07);
+    else
+        set_cursor_shape(lines - 4, lines - 3);
+    SET_BDA(char_height, lines);
+    u16 vde = vgahw_get_vde();
+    u8 rows = vde / lines;
+    SET_BDA(video_rows, rows - 1);
+    u16 cols = GET_BDA(video_cols);
+    SET_BDA(video_pagesize, rows * cols * 2);
+}
+
+
+/****************************************************************
+ * Character writing
+ ****************************************************************/
+
+// Scroll the screen one line.  This function is designed to be called
+// tail-recursive to reduce stack usage.
+static void noinline
+scroll_one(u16 nbrows, u16 nbcols, u8 page)
+{
+    struct cursorpos ul = {0, 0, page};
+    struct cursorpos lr = {nbcols-1, nbrows-1, page};
+    vgafb_scroll(1, -1, ul, lr);
+}
+
+// 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)
+{
+    struct cursorpos cp = *pcp;
+
+    // Get the dimensions
+    u16 nbrows = GET_BDA(video_rows) + 1;
+    u16 nbcols = GET_BDA(video_cols);
+
+    switch (ca.car) {
+    case 7:
+        //FIXME should beep
+        break;
+    case 8:
+        if (cp.x > 0)
+            cp.x--;
+        break;
+    case '\r':
+        cp.x = 0;
+        break;
+    case '\n':
+        cp.y++;
+        break;
+    case '\t':
+        do {
+            struct carattr dummyca = {' ', ca.attr, ca.use_attr};
+            vgafb_write_char(cp, dummyca);
+            cp.x++;
+        } while (cp.x < nbcols && cp.x % 8);
+        break;
+    default:
+        vgafb_write_char(cp, ca);
+        cp.x++;
+    }
+
+    // Do we need to wrap ?
+    if (cp.x == nbcols) {
+        cp.x = 0;
+        cp.y++;
+    }
+    // Do we need to scroll ?
+    if (cp.y < nbrows) {
+        *pcp = cp;
+        return;
+    }
+    // Scroll screen
+    cp.y--;
+    *pcp = cp;
+    scroll_one(nbrows, nbcols, cp.page);
+}
+
+// Write out a buffer of alternating characters and attributes.
+static void
+write_attr_string(struct cursorpos *pcp, u16 count, u16 seg, u8 *offset_far)
+{
+    while (count--) {
+        u8 car = GET_FARVAR(seg, *offset_far);
+        offset_far++;
+        u8 attr = GET_FARVAR(seg, *offset_far);
+        offset_far++;
+
+        struct carattr ca = {car, attr, 1};
+        write_teletype(pcp, ca);
+    }
+}
+
+// Write out a buffer of characters.
+static void
+write_string(struct cursorpos *pcp, u8 attr, u16 count, u16 seg, u8 *offset_far)
+{
+    while (count--) {
+        u8 car = GET_FARVAR(seg, *offset_far);
+        offset_far++;
+
+        struct carattr ca = {car, attr, 1};
+        write_teletype(pcp, ca);
+    }
+}
+
+
+/****************************************************************
+ * Save and restore bda state
+ ****************************************************************/
+
+static void
+save_bda_state(u16 seg, struct saveBDAstate *info)
+{
+    SET_FARVAR(seg, info->video_mode, GET_BDA(video_mode));
+    SET_FARVAR(seg, info->video_cols, GET_BDA(video_cols));
+    SET_FARVAR(seg, info->video_pagesize, GET_BDA(video_pagesize));
+    SET_FARVAR(seg, info->crtc_address, GET_BDA(crtc_address));
+    SET_FARVAR(seg, info->video_rows, GET_BDA(video_rows));
+    SET_FARVAR(seg, info->char_height, GET_BDA(char_height));
+    SET_FARVAR(seg, info->video_ctl, GET_BDA(video_ctl));
+    SET_FARVAR(seg, info->video_switches, GET_BDA(video_switches));
+    SET_FARVAR(seg, info->modeset_ctl, GET_BDA(modeset_ctl));
+    SET_FARVAR(seg, info->cursor_type, GET_BDA(cursor_type));
+    u16 i;
+    for (i=0; i<8; i++)
+        SET_FARVAR(seg, info->cursor_pos[i], GET_BDA(cursor_pos[i]));
+    SET_FARVAR(seg, info->video_pagestart, GET_BDA(video_pagestart));
+    SET_FARVAR(seg, info->video_page, GET_BDA(video_page));
+    /* current font */
+    SET_FARVAR(seg, info->font0, GET_IVT(0x1f));
+    SET_FARVAR(seg, info->font1, GET_IVT(0x43));
+}
+
+static void
+restore_bda_state(u16 seg, struct saveBDAstate *info)
+{
+    SET_BDA(video_mode, GET_FARVAR(seg, info->video_mode));
+    SET_BDA(video_cols, GET_FARVAR(seg, info->video_cols));
+    SET_BDA(video_pagesize, GET_FARVAR(seg, info->video_pagesize));
+    SET_BDA(crtc_address, GET_FARVAR(seg, info->crtc_address));
+    SET_BDA(video_rows, GET_FARVAR(seg, info->video_rows));
+    SET_BDA(char_height, GET_FARVAR(seg, info->char_height));
+    SET_BDA(video_ctl, GET_FARVAR(seg, info->video_ctl));
+    SET_BDA(video_switches, GET_FARVAR(seg, info->video_switches));
+    SET_BDA(modeset_ctl, GET_FARVAR(seg, info->modeset_ctl));
+    SET_BDA(cursor_type, GET_FARVAR(seg, info->cursor_type));
+    u16 i;
+    for (i = 0; i < 8; i++)
+        SET_BDA(cursor_pos[i], GET_FARVAR(seg, info->cursor_pos[i]));
+    SET_BDA(video_pagestart, GET_FARVAR(seg, info->video_pagestart));
+    SET_BDA(video_page, GET_FARVAR(seg, info->video_page));
+    /* current font */
+    SET_IVT(0x1f, GET_FARVAR(seg, info->font0));
+    SET_IVT(0x43, GET_FARVAR(seg, info->font1));
+}
+
+
+/****************************************************************
+ * VGA int 10 handler
+ ****************************************************************/
+
+// set video mode
+static void
+handle_1000(struct bregs *regs)
+{
+    u8 noclearmem = regs->al & 0x80;
+    u8 mode = regs->al & 0x7f;
+
+    // Set regs->al
+    if (mode > 7)
+        regs->al = 0x20;
+    else if (mode == 6)
+        regs->al = 0x3f;
+    else
+        regs->al = 0x30;
+
+    if (CONFIG_CIRRUS)
+        cirrus_set_video_mode(mode);
+
+    if (CONFIG_VBE)
+        if (vbe_has_vbe_display())
+            dispi_set_enable(VBE_DISPI_DISABLED);
+
+    // find the entry in the video modes
+    struct vgamode_s *vmode_g = find_vga_entry(mode);
+    dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
+    if (!vmode_g)
+        return;
+
+    // Read the bios mode set control
+    u8 modeset_ctl = GET_BDA(modeset_ctl);
+
+    // Then we know the number of lines
+// FIXME
+
+    // if palette loading (bit 3 of modeset ctl = 0)
+    if ((modeset_ctl & 0x08) == 0) {    // Set the PEL mask
+        vgahw_set_pel_mask(GET_GLOBAL(vmode_g->pelmask));
+
+        // From which palette
+        u8 *palette_g = GET_GLOBAL(vmode_g->dac);
+        u16 palsize = GET_GLOBAL(vmode_g->dacsize) / 3;
+
+        // Always 256*3 values
+        vgahw_set_dac_regs(get_global_seg(), palette_g, 0, palsize);
+        u16 i;
+        for (i = palsize; i < 0x0100; i++) {
+            static u8 rgb[3] VAR16;
+            vgahw_set_dac_regs(get_global_seg(), rgb, i, 1);
+        }
+
+        if ((modeset_ctl & 0x02) == 0x02)
+            perform_gray_scale_summing(0x00, 0x100);
+    }
+
+    struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+    vgahw_set_mode(vparam_g);
+
+    if (noclearmem == 0x00)
+        clear_screen(vmode_g);
+
+    // Set CRTC address VGA or MDA
+    u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
+    if (GET_GLOBAL(vmode_g->memmodel) == MTEXT)
+        crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
+
+    // Set the BIOS mem
+    u16 cheight = GET_GLOBAL(vparam_g->cheight);
+    SET_BDA(video_mode, mode);
+    SET_BDA(video_cols, GET_GLOBAL(vparam_g->twidth));
+    SET_BDA(video_pagesize, GET_GLOBAL(vparam_g->slength));
+    SET_BDA(crtc_address, crtc_addr);
+    SET_BDA(video_rows, GET_GLOBAL(vparam_g->theightm1));
+    SET_BDA(char_height, cheight);
+    SET_BDA(video_ctl, (0x60 | noclearmem));
+    SET_BDA(video_switches, 0xF9);
+    SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
+
+    // FIXME We nearly have the good tables. to be reworked
+    SET_BDA(dcc_index, 0x08);   // 8 is VGA should be ok for now
+    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...
+
+    // Set cursor shape
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
+        set_cursor_shape(0x06, 0x07);
+    // Set cursor pos for page 0..7
+    int i;
+    for (i = 0; i < 8; i++) {
+        struct cursorpos cp = {0, 0, i};
+        set_cursor_pos(cp);
+    }
+
+    // Set active page 0
+    set_active_page(0x00);
+
+    // Write the fonts in memory
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
+        call16_vgaint(0x1104, 0);
+        call16_vgaint(0x1103, 0);
+    }
+    // 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;
+    }
+}
+
+static void
+handle_1001(struct bregs *regs)
+{
+    set_cursor_shape(regs->ch, regs->cl);
+}
+
+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_cursor_shape(regs->bh);
+    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 page = GET_BDA(video_page);
+    struct cursorpos ul = {regs->cl, regs->ch, page};
+    struct cursorpos lr = {regs->dl, regs->dh, page};
+
+    u16 nbrows = GET_BDA(video_rows) + 1;
+    if (lr.y >= nbrows)
+        lr.y = nbrows - 1;
+    u16 nbcols = GET_BDA(video_cols);
+    if (lr.x >= nbcols)
+        lr.x = nbcols - 1;
+
+    if (ul.x > lr.x || ul.y > lr.y)
+        return;
+
+    u16 nblines = regs->al;
+    if (!nblines || nblines > lr.y - ul.y + 1)
+        nblines = lr.y - ul.y + 1;
+
+    vgafb_scroll(dir * nblines, regs->bh, ul, lr);
+}
+
+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
+write_chars(u8 page, struct carattr ca, u16 count)
+{
+    struct cursorpos cp = get_cursor_pos(page);
+    while (count--) {
+        vgafb_write_char(cp, ca);
+        cp.x++;
+    }
+}
+
+static void
+handle_1009(struct bregs *regs)
+{
+    struct carattr ca = {regs->al, regs->bl, 1};
+    write_chars(regs->bh, ca, regs->cx);
+}
+
+static void
+handle_100a(struct bregs *regs)
+{
+    struct carattr ca = {regs->al, regs->bl, 0};
+    write_chars(regs->bh, ca, regs->cx);
+}
+
+
+static void
+handle_100b00(struct bregs *regs)
+{
+    vgahw_set_border_color(regs->bl);
+}
+
+static void
+handle_100b01(struct bregs *regs)
+{
+    vgahw_set_palette(regs->bl);
+}
+
+static void
+handle_100bXX(struct bregs *regs)
+{
+    debug_stub(regs);
+}
+
+static void
+handle_100b(struct bregs *regs)
+{
+    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;
+    vgahw_set_single_palette_reg(regs->bl, regs->bh);
+}
+
+static void
+handle_101001(struct bregs *regs)
+{
+    vgahw_set_overscan_border_color(regs->bh);
+}
+
+static void
+handle_101002(struct bregs *regs)
+{
+    vgahw_set_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
+}
+
+static void
+handle_101003(struct bregs *regs)
+{
+    vgahw_toggle_intensity(regs->bl);
+}
+
+static void
+handle_101007(struct bregs *regs)
+{
+    if (regs->bl > 0x14)
+        return;
+    regs->bh = vgahw_get_single_palette_reg(regs->bl);
+}
+
+static void
+handle_101008(struct bregs *regs)
+{
+    regs->bh = vgahw_get_overscan_border_color();
+}
+
+static void
+handle_101009(struct bregs *regs)
+{
+    vgahw_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};
+    vgahw_set_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
+}
+
+static void
+handle_101012(struct bregs *regs)
+{
+    vgahw_set_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
+}
+
+static void
+handle_101013(struct bregs *regs)
+{
+    vgahw_select_video_dac_color_page(regs->bl, regs->bh);
+}
+
+static void noinline
+handle_101015(struct bregs *regs)
+{
+    u8 rgb[3];
+    vgahw_get_dac_regs(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)
+{
+    vgahw_get_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
+}
+
+static void
+handle_101018(struct bregs *regs)
+{
+    vgahw_set_pel_mask(regs->bl);
+}
+
+static void
+handle_101019(struct bregs *regs)
+{
+    regs->bl = vgahw_get_pel_mask();
+}
+
+static void
+handle_10101a(struct bregs *regs)
+{
+    vgahw_read_video_dac_state(&regs->bl, &regs->bh);
+}
+
+static void
+handle_10101b(struct bregs *regs)
+{
+    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)
+{
+    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)
+{
+    vgafb_load_font(regs->es, (void*)(regs->bp+0), regs->cx
+                    , regs->dx, regs->bl, regs->bh);
+}
+
+static void
+handle_101101(struct bregs *regs)
+{
+    vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
+}
+
+static void
+handle_101102(struct bregs *regs)
+{
+    vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
+}
+
+static void
+handle_101103(struct bregs *regs)
+{
+    vgahw_set_text_block_specifier(regs->bl);
+}
+
+static void
+handle_101104(struct bregs *regs)
+{
+    vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
+}
+
+static void
+handle_101110(struct bregs *regs)
+{
+    vgafb_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)
+{
+    vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
+    set_scan_lines(14);
+}
+
+static void
+handle_101112(struct bregs *regs)
+{
+    vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
+    set_scan_lines(8);
+}
+
+static void
+handle_101114(struct bregs *regs)
+{
+    vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
+    set_scan_lines(16);
+}
+
+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->dx = GET_BDA(video_rows);
+}
+
+static void
+handle_1011XX(struct bregs *regs)
+{
+    debug_stub(regs);
+}
+
+static void
+handle_1011(struct bregs *regs)
+{
+    switch (regs->al) {
+    case 0x00: handle_101100(regs); break;
+    case 0x01: handle_101101(regs); break;
+    case 0x02: handle_101102(regs); break;
+    case 0x03: handle_101103(regs); break;
+    case 0x04: handle_101104(regs); break;
+    case 0x10: handle_101110(regs); break;
+    case 0x11: handle_101111(regs); break;
+    case 0x12: handle_101112(regs); break;
+    case 0x14: handle_101114(regs); break;
+    case 0x30: handle_101130(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)
+{
+    vgahw_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)
+{
+    u8 v = (regs->al & 0x01) ^ 0x01;
+    u8 v2 = GET_BDA(modeset_ctl) & ~0x01;
+    SET_BDA(modeset_ctl, v | v2);
+    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)
+{
+    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;
+    }
+
+    // XXX - cirrus has 1280, 1281, 1282, 1285, 129a, 12a0, 12a1, 12a2, 12ae
+}
+
+
+// Write string
+static void noinline
+handle_1013(struct bregs *regs)
+{
+    struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
+    // if row=0xff special case : use current cursor position
+    if (cp.y == 0xff)
+        cp = get_cursor_pos(cp.page);
+    u8 flag = regs->al;
+    if (flag & 2)
+        write_attr_string(&cp, regs->cx, regs->es, (void*)(regs->bp + 0));
+    else
+        write_string(&cp, regs->bl, regs->cx, regs->es, (void*)(regs->bp + 0));
+
+    if (flag & 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 funcInfo {
+    u16 static_functionality_off;
+    u16 static_functionality_seg;
+    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];
+};
+
+static void
+handle_101b(struct bregs *regs)
+{
+    u16 seg = regs->es;
+    struct funcInfo *info = (void*)(regs->di+0);
+    memset_far(seg, info, 0, sizeof(*info));
+    // Address of static functionality table
+    SET_FARVAR(seg, info->static_functionality_off, (u32)static_functionality);
+    SET_FARVAR(seg, info->static_functionality_seg, get_global_seg());
+
+    // 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_101c00(struct bregs *regs)
+{
+    u16 flags = regs->cx;
+    u16 size = 0;
+    if (flags & 1)
+        size += sizeof(struct saveVideoHardware);
+    if (flags & 2)
+        size += sizeof(struct saveBDAstate);
+    if (flags & 4)
+        size += sizeof(struct saveDACcolors);
+    regs->bx = size;
+    regs->al = 0x1c;
+}
+
+static void
+handle_101c01(struct bregs *regs)
+{
+    u16 flags = regs->cx;
+    u16 seg = regs->es;
+    void *data = (void*)(regs->bx+0);
+    if (flags & 1) {
+        vgahw_save_state(seg, data);
+        data += sizeof(struct saveVideoHardware);
+    }
+    if (flags & 2) {
+        save_bda_state(seg, data);
+        data += sizeof(struct saveBDAstate);
+    }
+    if (flags & 4)
+        vgahw_save_dac_state(seg, data);
+    regs->al = 0x1c;
+}
+
+static void
+handle_101c02(struct bregs *regs)
+{
+    u16 flags = regs->cx;
+    u16 seg = regs->es;
+    void *data = (void*)(regs->bx+0);
+    if (flags & 1) {
+        vgahw_restore_state(seg, data);
+        data += sizeof(struct saveVideoHardware);
+    }
+    if (flags & 2) {
+        restore_bda_state(seg, data);
+        data += sizeof(struct saveBDAstate);
+    }
+    if (flags & 4)
+        vgahw_restore_dac_state(seg, data);
+    regs->al = 0x1c;
+}
+
+static void
+handle_101cXX(struct bregs *regs)
+{
+    debug_stub(regs);
+}
+
+static void
+handle_101c(struct bregs *regs)
+{
+    switch (regs->al) {
+    case 0x00: handle_101c00(regs); break;
+    case 0x01: handle_101c01(regs); break;
+    case 0x02: handle_101c02(regs); break;
+    default:   handle_101cXX(regs); break;
+    }
+}
+
+
+static void
+handle_104f00(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_return_controller_information(&AX,ES,DI);
+    // XXX - OR cirrus_vesa_00h
+}
+
+static void
+handle_104f01(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
+    // XXX - OR cirrus_vesa_01h
+}
+
+static void
+handle_104f02(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_set_mode(&AX,BX,ES,DI);
+    // XXX - OR cirrus_vesa_02h
+}
+
+static void
+handle_104f03(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_return_current_mode
+    // XXX - OR cirrus_vesa_03h
+}
+
+static void
+handle_104f04(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
+}
+
+static void
+handle_104f05(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_display_window_control
+    // XXX - OR cirrus_vesa_05h
+}
+
+static void
+handle_104f06(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_set_get_logical_scan_line_length
+    // XXX - OR cirrus_vesa_06h
+}
+
+static void
+handle_104f07(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_set_get_display_start
+    // XXX - OR cirrus_vesa_07h
+}
+
+static void
+handle_104f08(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_set_get_dac_palette_format
+}
+
+static void
+handle_104f0a(struct bregs *regs)
+{
+    // XXX - vbe_biosfn_return_protected_mode_interface
+}
+
+static void
+handle_104fXX(struct bregs *regs)
+{
+    debug_stub(regs);
+    regs->ax = 0x0100;
+}
+
+static void
+handle_104f(struct bregs *regs)
+{
+    if (! CONFIG_VBE || !vbe_has_vbe_display()) {
+        handle_104fXX(regs);
+        return;
+    }
+
+    switch (regs->al) {
+    case 0x00: handle_104f00(regs); break;
+    case 0x01: handle_104f01(regs); break;
+    case 0x02: handle_104f02(regs); break;
+    case 0x03: handle_104f03(regs); break;
+    case 0x04: handle_104f04(regs); break;
+    case 0x05: handle_104f05(regs); break;
+    case 0x06: handle_104f06(regs); break;
+    case 0x07: handle_104f07(regs); break;
+    case 0x08: handle_104f08(regs); break;
+    case 0x0a: handle_104f0a(regs); break;
+    default:   handle_104fXX(regs); break;
+    }
+}
+
+
+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;
+    }
+}
+
+
+/****************************************************************
+ * VGA post
+ ****************************************************************/
+
+static void
+init_bios_area(void)
+{
+    // init detected hardware BIOS Area
+    // set 80x25 color (not clear from RBIL but usual)
+    u16 eqf = GET_BDA(equipment_list_flags);
+    SET_BDA(equipment_list_flags, (eqf & 0xffcf) | 0x20);
+
+    // Just for the first int10 find its children
+
+    // the default char height
+    SET_BDA(char_height, 0x10);
+
+    // Clear the screen
+    SET_BDA(video_ctl, 0x60);
+
+    // Set the basic screen we have
+    SET_BDA(video_switches, 0xf9);
+
+    // Set the basic modeset options
+    SET_BDA(modeset_ctl, 0x51);
+
+    // Set the  default MSR
+    SET_BDA(video_msr, 0x09);
+}
+
+void VISIBLE16
+vga_post(struct bregs *regs)
+{
+    debug_enter(regs, DEBUG_VGA_POST);
+
+    vgahw_init();
+
+    init_bios_area();
+
+    if (CONFIG_VBE)
+        vbe_init();
+
+    extern void entry_10(void);
+    SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10));
+
+    if (CONFIG_CIRRUS)
+        cirrus_init();
+
+    // XXX - clear screen and display info
+
+    // XXX: fill it
+    SET_VGA(video_save_pointer_table[0], (u32)video_param_table);
+    SET_VGA(video_save_pointer_table[1], get_global_seg());
+
+    // Fixup checksum
+    extern u8 _rom_header_size, _rom_header_checksum;
+    SET_VGA(_rom_header_checksum, 0);
+    u8 sum = -checksum_far(get_global_seg(), 0, _rom_header_size * 512);
+    SET_VGA(_rom_header_checksum, sum);
+}
diff --git a/bios/seabios/vgasrc/vgaentry.S b/bios/seabios/vgasrc/vgaentry.S
new file mode 100644 (file)
index 0000000..fbfa9f7
--- /dev/null
@@ -0,0 +1,48 @@
+// Rom layout and bios assembler to C interface.
+//
+// Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+/****************************************************************
+ * Include of 16bit C code
+ ****************************************************************/
+
+        .code16gcc
+#include "vgaccode.16.s"
+
+#include "entryfuncs.S" // ENTRY_*
+
+
+/****************************************************************
+ * Rom Header
+ ****************************************************************/
+
+        .section .rom.header
+        .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 21
+
+
+/****************************************************************
+ * Entry points
+ ****************************************************************/
+
+        DECLFUNC _optionrom_entry
+_optionrom_entry:
+        ENTRY_ARG vga_post
+        lretw
+
+        DECLFUNC entry_10
+entry_10:
+        ENTRY_ARG handle_10
+        iretw
diff --git a/bios/seabios/vgasrc/vgafb.c b/bios/seabios/vgasrc/vgafb.c
new file mode 100644 (file)
index 0000000..866f7f8
--- /dev/null
@@ -0,0 +1,512 @@
+// Code for manipulating VGA framebuffers.
+//
+// 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_BDA
+#include "util.h" // memset_far
+#include "vgatables.h" // find_vga_entry
+
+
+/****************************************************************
+ * Screen scrolling
+ ****************************************************************/
+
+static inline void *
+memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
+{
+    for (; lines; lines--, dst+=stride, src+=stride)
+        memcpy_far(seg, dst, seg, src, copylen);
+    return dst;
+}
+
+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);
+}
+
+static void
+scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
+           , struct cursorpos ul, struct cursorpos lr)
+{
+    struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+    u8 cheight = GET_GLOBAL(vparam_g->cheight);
+    int stride = GET_BDA(video_cols);
+    void *src_far, *dest_far;
+    if (nblines >= 0) {
+        dest_far = (void*)(ul.y * cheight * stride + ul.x);
+        src_far = dest_far + nblines * cheight * stride;
+    } else {
+        // Scroll down
+        nblines = -nblines;
+        dest_far = (void*)(lr.y * cheight * stride + ul.x);
+        src_far = dest_far - nblines * cheight * stride;
+        stride = -stride;
+    }
+    int cols = lr.x - ul.x + 1;
+    int rows = lr.y - ul.y + 1;
+    if (nblines < rows) {
+        vgahw_grdc_write(0x05, 0x01);
+        dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols, stride
+                                 , (rows - nblines) * cheight);
+    }
+    if (attr < 0)
+        attr = 0;
+    vgahw_grdc_write(0x05, 0x02);
+    memset_stride(SEG_GRAPH, dest_far, attr, cols, stride, nblines * cheight);
+    vgahw_grdc_write(0x05, 0x00);
+}
+
+static void
+scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
+            , struct cursorpos ul, struct cursorpos lr)
+{
+    struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+    u8 cheight = GET_GLOBAL(vparam_g->cheight);
+    u8 bpp = GET_GLOBAL(vmode_g->pixbits);
+    int stride = GET_BDA(video_cols) * bpp;
+    void *src_far, *dest_far;
+    if (nblines >= 0) {
+        dest_far = (void*)(ul.y * cheight * stride + ul.x * bpp);
+        src_far = dest_far + nblines * cheight * stride;
+    } else {
+        // Scroll down
+        nblines = -nblines;
+        dest_far = (void*)(lr.y * cheight * stride + ul.x * bpp);
+        src_far = dest_far - nblines * cheight * stride;
+        stride = -stride;
+    }
+    int cols = (lr.x - ul.x + 1) * bpp;
+    int rows = lr.y - ul.y + 1;
+    if (nblines < rows) {
+        memcpy_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000, cols
+                      , stride, (rows - nblines) * cheight / 2);
+        dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols
+                                 , stride, (rows - nblines) * cheight / 2);
+    }
+    if (attr < 0)
+        attr = 0;
+    memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols
+                  , stride, nblines * cheight / 2);
+    memset_stride(SEG_CTEXT, dest_far, attr, cols
+                  , stride, nblines * cheight / 2);
+}
+
+static void
+scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
+            , struct cursorpos ul, struct cursorpos lr)
+{
+    u16 nbrows = GET_BDA(video_rows) + 1;
+    u16 nbcols = GET_BDA(video_cols);
+    void *src_far, *dest_far = (void*)SCREEN_MEM_START(nbcols, nbrows, ul.page);
+    int stride = nbcols * 2;
+    if (nblines >= 0) {
+        dest_far += ul.y * stride + ul.x * 2;
+        src_far = dest_far + nblines * stride;
+    } else {
+        // Scroll down
+        nblines = -nblines;
+        dest_far += lr.y * stride + ul.x * 2;
+        src_far = dest_far - nblines * stride;
+        stride = -stride;
+    }
+    int cols = (lr.x - ul.x + 1) * 2;
+    int rows = lr.y - ul.y + 1;
+    u16 seg = GET_GLOBAL(vmode_g->sstart);
+    if (nblines < rows)
+        dest_far = memcpy_stride(seg, dest_far, src_far, cols, stride
+                                 , (rows - nblines));
+    if (attr < 0)
+        attr = 0x07;
+    attr = (attr << 8) | ' ';
+    memset16_stride(seg, dest_far, attr, cols, stride, nblines);
+}
+
+void
+vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
+{
+    // Get the mode
+    struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+    if (!vmode_g)
+        return;
+
+    // FIXME gfx mode not complete
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case CTEXT:
+    case MTEXT:
+        scroll_text(vmode_g, nblines, attr, ul, lr);
+        break;
+    case PLANAR4:
+    case PLANAR1:
+        scroll_pl4(vmode_g, nblines, attr, ul, lr);
+        break;
+    case CGA:
+        scroll_cga(vmode_g, nblines, attr, ul, lr);
+        break;
+    default:
+        dprintf(1, "Scroll in graphics mode\n");
+    }
+}
+
+void
+clear_screen(struct vgamode_s *vmode_g)
+{
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case CTEXT:
+    case MTEXT:
+        memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
+        break;
+    case 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);
+    }
+}
+
+
+/****************************************************************
+ * Read/write characters to screen
+ ****************************************************************/
+
+static void
+write_gfx_char_pl4(struct vgamode_s *vmode_g
+                   , struct cursorpos cp, struct carattr ca)
+{
+    u16 nbcols = GET_BDA(video_cols);
+    if (cp.x >= nbcols)
+        return;
+
+    struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+    u8 cheight = GET_GLOBAL(vparam_g->cheight);
+    u8 *fdata_g;
+    switch (cheight) {
+    case 14:
+        fdata_g = vgafont14;
+        break;
+    case 16:
+        fdata_g = vgafont16;
+        break;
+    default:
+        fdata_g = vgafont8;
+    }
+    u16 addr = cp.x + cp.y * cheight * nbcols;
+    u16 src = ca.car * cheight;
+    vgahw_sequ_write(0x02, 0x0f);
+    vgahw_grdc_write(0x05, 0x02);
+    if (ca.attr & 0x80)
+        vgahw_grdc_write(0x03, 0x18);
+    else
+        vgahw_grdc_write(0x03, 0x00);
+    u8 i;
+    for (i = 0; i < cheight; i++) {
+        u8 *dest_far = (void*)(addr + i * nbcols);
+        u8 j;
+        for (j = 0; j < 8; j++) {
+            u8 mask = 0x80 >> j;
+            vgahw_grdc_write(0x08, mask);
+            GET_FARVAR(SEG_GRAPH, *dest_far);
+            if (GET_GLOBAL(fdata_g[src + i]) & mask)
+                SET_FARVAR(SEG_GRAPH, *dest_far, ca.attr & 0x0f);
+            else
+                SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
+        }
+    }
+    vgahw_grdc_write(0x08, 0xff);
+    vgahw_grdc_write(0x05, 0x00);
+    vgahw_grdc_write(0x03, 0x00);
+}
+
+static void
+write_gfx_char_cga(struct vgamode_s *vmode_g
+                   , struct cursorpos cp, struct carattr ca)
+{
+    u16 nbcols = GET_BDA(video_cols);
+    if (cp.x >= nbcols)
+        return;
+
+    u8 *fdata_g = vgafont8;
+    u8 bpp = GET_GLOBAL(vmode_g->pixbits);
+    u16 addr = (cp.x * bpp) + cp.y * 320;
+    u16 src = ca.car * 8;
+    u8 i;
+    for (i = 0; i < 8; i++) {
+        u8 *dest_far = (void*)(addr + (i >> 1) * 80);
+        if (i & 1)
+            dest_far += 0x2000;
+        u8 mask = 0x80;
+        if (bpp == 1) {
+            u8 data = 0;
+            if (ca.attr & 0x80)
+                data = GET_FARVAR(SEG_CTEXT, *dest_far);
+            u8 j;
+            for (j = 0; j < 8; j++) {
+                if (GET_GLOBAL(fdata_g[src + i]) & mask) {
+                    if (ca.attr & 0x80)
+                        data ^= (ca.attr & 0x01) << (7 - j);
+                    else
+                        data |= (ca.attr & 0x01) << (7 - j);
+                }
+                mask >>= 1;
+            }
+            SET_FARVAR(SEG_CTEXT, *dest_far, data);
+        } else {
+            while (mask > 0) {
+                u8 data = 0;
+                if (ca.attr & 0x80)
+                    data = GET_FARVAR(SEG_CTEXT, *dest_far);
+                u8 j;
+                for (j = 0; j < 4; j++) {
+                    if (GET_GLOBAL(fdata_g[src + i]) & mask) {
+                        if (ca.attr & 0x80)
+                            data ^= (ca.attr & 0x03) << ((3 - j) * 2);
+                        else
+                            data |= (ca.attr & 0x03) << ((3 - j) * 2);
+                    }
+                    mask >>= 1;
+                }
+                SET_FARVAR(SEG_CTEXT, *dest_far, data);
+                dest_far += 1;
+            }
+        }
+    }
+}
+
+static void
+write_gfx_char_lin(struct vgamode_s *vmode_g
+                   , struct cursorpos cp, struct carattr ca)
+{
+    // Get the dimensions
+    u16 nbcols = GET_BDA(video_cols);
+    if (cp.x >= nbcols)
+        return;
+
+    u8 *fdata_g = vgafont8;
+    u16 addr = cp.x * 8 + cp.y * nbcols * 64;
+    u16 src = ca.car * 8;
+    u8 i;
+    for (i = 0; i < 8; i++) {
+        u8 *dest_far = (void*)(addr + i * nbcols * 8);
+        u8 mask = 0x80;
+        u8 j;
+        for (j = 0; j < 8; j++) {
+            u8 data = 0x00;
+            if (GET_GLOBAL(fdata_g[src + i]) & mask)
+                data = ca.attr;
+            SET_FARVAR(SEG_GRAPH, dest_far[j], data);
+            mask >>= 1;
+        }
+    }
+}
+
+static void
+write_text_char(struct vgamode_s *vmode_g
+                , struct cursorpos cp, struct carattr ca)
+{
+    // Get the dimensions
+    u16 nbrows = GET_BDA(video_rows) + 1;
+    u16 nbcols = GET_BDA(video_cols);
+
+    // Compute the address
+    void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
+                                + (cp.x + cp.y * nbcols) * 2);
+
+    if (ca.use_attr) {
+        u16 dummy = (ca.attr << 8) | ca.car;
+        SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
+    } else {
+        SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
+    }
+}
+
+void
+vgafb_write_char(struct cursorpos cp, struct carattr ca)
+{
+    // Get the mode
+    struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+    if (!vmode_g)
+        return;
+
+    // FIXME gfx mode not complete
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case CTEXT:
+    case MTEXT:
+        write_text_char(vmode_g, cp, ca);
+        break;
+    case PLANAR4:
+    case PLANAR1:
+        write_gfx_char_pl4(vmode_g, cp, ca);
+        break;
+    case CGA:
+        write_gfx_char_cga(vmode_g, cp, ca);
+        break;
+    case LINEAR8:
+        write_gfx_char_lin(vmode_g, cp, ca);
+        break;
+    }
+}
+
+struct carattr
+vgafb_read_char(struct cursorpos cp)
+{
+    // Get the mode
+    struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+    if (!vmode_g)
+        goto fail;
+
+    if (!(GET_GLOBAL(vmode_g->memmodel) & TEXT)) {
+        // FIXME gfx mode
+        dprintf(1, "Read char in graphics mode\n");
+        goto fail;
+    }
+
+    // Get the dimensions
+    u16 nbrows = GET_BDA(video_rows) + 1;
+    u16 nbcols = GET_BDA(video_cols);
+
+    // Compute the address
+    u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
+                               + (cp.x + cp.y * nbcols) * 2);
+    u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
+    struct carattr ca = {v, v>>8, 0};
+    return ca;
+
+fail: ;
+    struct carattr ca2 = {0, 0, 0};
+    return ca2;
+}
+
+
+/****************************************************************
+ * Read/write pixels
+ ****************************************************************/
+
+void
+vgafb_write_pixel(u8 color, u16 x, u16 y)
+{
+    // Get the mode
+    struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+    if (!vmode_g)
+        return;
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
+        return;
+
+    u8 *addr_far, mask, attr, data;
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case PLANAR4:
+    case PLANAR1:
+        addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
+        mask = 0x80 >> (x & 0x07);
+        vgahw_grdc_write(0x08, mask);
+        vgahw_grdc_write(0x05, 0x02);
+        data = GET_FARVAR(SEG_GRAPH, *addr_far);
+        if (color & 0x80)
+            vgahw_grdc_write(0x03, 0x18);
+        SET_FARVAR(SEG_GRAPH, *addr_far, color);
+        vgahw_grdc_write(0x08, 0xff);
+        vgahw_grdc_write(0x05, 0x00);
+        vgahw_grdc_write(0x03, 0x00);
+        break;
+    case CGA:
+        if (GET_GLOBAL(vmode_g->pixbits) == 2)
+            addr_far = (void*)((x >> 2) + (y >> 1) * 80);
+        else
+            addr_far = (void*)((x >> 3) + (y >> 1) * 80);
+        if (y & 1)
+            addr_far += 0x2000;
+        data = GET_FARVAR(SEG_CTEXT, *addr_far);
+        if (GET_GLOBAL(vmode_g->pixbits) == 2) {
+            attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
+            mask = 0x03 << ((3 - (x & 0x03)) * 2);
+        } else {
+            attr = (color & 0x01) << (7 - (x & 0x07));
+            mask = 0x01 << (7 - (x & 0x07));
+        }
+        if (color & 0x80) {
+            data ^= attr;
+        } else {
+            data &= ~mask;
+            data |= attr;
+        }
+        SET_FARVAR(SEG_CTEXT, *addr_far, data);
+        break;
+    case LINEAR8:
+        addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
+        SET_FARVAR(SEG_GRAPH, *addr_far, color);
+        break;
+    }
+}
+
+u8
+vgafb_read_pixel(u16 x, u16 y)
+{
+    // Get the mode
+    struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+    if (!vmode_g)
+        return 0;
+    if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
+        return 0;
+
+    u8 *addr_far, mask, attr=0, data, i;
+    switch (GET_GLOBAL(vmode_g->memmodel)) {
+    case PLANAR4:
+    case PLANAR1:
+        addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
+        mask = 0x80 >> (x & 0x07);
+        attr = 0x00;
+        for (i = 0; i < 4; i++) {
+            vgahw_grdc_write(0x04, i);
+            data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
+            if (data > 0)
+                attr |= (0x01 << i);
+        }
+        break;
+    case CGA:
+        addr_far = (void*)((x >> 2) + (y >> 1) * 80);
+        if (y & 1)
+            addr_far += 0x2000;
+        data = GET_FARVAR(SEG_CTEXT, *addr_far);
+        if (GET_GLOBAL(vmode_g->pixbits) == 2)
+            attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
+        else
+            attr = (data >> (7 - (x & 0x07))) & 0x01;
+        break;
+    case LINEAR8:
+        addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
+        attr = GET_FARVAR(SEG_GRAPH, *addr_far);
+        break;
+    }
+    return attr;
+}
+
+
+/****************************************************************
+ * Font loading
+ ****************************************************************/
+
+void
+vgafb_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();
+}
diff --git a/bios/seabios/vgasrc/vgafonts.c b/bios/seabios/vgasrc/vgafonts.c
new file mode 100644 (file)
index 0000000..8c1752c
--- /dev/null
@@ -0,0 +1,785 @@
+#include "vgatables.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/bios/seabios/vgasrc/vgaio.c b/bios/seabios/vgasrc/vgaio.c
new file mode 100644 (file)
index 0000000..ffded34
--- /dev/null
@@ -0,0 +1,555 @@
+// VGA io port access
+//
+// 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 "ioport.h" // outb
+#include "farptr.h" // SET_FARVAR
+#include "biosvar.h" // GET_BDA
+#include "vgatables.h" // VGAREG_*
+
+// TODO
+//  * replace direct in/out calls with wrapper functions
+
+
+/****************************************************************
+ * Attribute control
+ ****************************************************************/
+
+void
+vgahw_screen_disable(void)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x00, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_screen_enable(void)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_set_border_color(u8 color)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x00, VGAREG_ACTL_ADDRESS);
+    u8 v1 = color & 0x0f;
+    if (v1 & 0x08)
+        v1 += 0x08;
+    outb(v1, VGAREG_ACTL_WRITE_DATA);
+
+    u8 v2 = color & 0x10;
+    int i;
+    for (i = 1; i < 4; i++) {
+        outb(i, VGAREG_ACTL_ADDRESS);
+
+        u8 cur = inb(VGAREG_ACTL_READ_DATA);
+        cur &= 0xef;
+        cur |= v2;
+        outb(cur, VGAREG_ACTL_WRITE_DATA);
+    }
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_set_overscan_border_color(u8 color)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x11, VGAREG_ACTL_ADDRESS);
+    outb(color, VGAREG_ACTL_WRITE_DATA);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+u8
+vgahw_get_overscan_border_color(void)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x11, VGAREG_ACTL_ADDRESS);
+    u8 v = inb(VGAREG_ACTL_READ_DATA);
+    inb(VGAREG_ACTL_RESET);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+    return v;
+}
+
+void
+vgahw_set_palette(u8 palid)
+{
+    inb(VGAREG_ACTL_RESET);
+    palid &= 0x01;
+    int i;
+    for (i = 1; i < 4; i++) {
+        outb(i, VGAREG_ACTL_ADDRESS);
+
+        u8 v = inb(VGAREG_ACTL_READ_DATA);
+        v &= 0xfe;
+        v |= palid;
+        outb(v, VGAREG_ACTL_WRITE_DATA);
+    }
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_set_single_palette_reg(u8 reg, u8 val)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(reg, VGAREG_ACTL_ADDRESS);
+    outb(val, VGAREG_ACTL_WRITE_DATA);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+u8
+vgahw_get_single_palette_reg(u8 reg)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(reg, VGAREG_ACTL_ADDRESS);
+    u8 v = inb(VGAREG_ACTL_READ_DATA);
+    inb(VGAREG_ACTL_RESET);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+    return v;
+}
+
+void
+vgahw_set_all_palette_reg(u16 seg, u8 *data_far)
+{
+    inb(VGAREG_ACTL_RESET);
+    int i;
+    for (i = 0; i < 0x10; i++) {
+        outb(i, VGAREG_ACTL_ADDRESS);
+        u8 val = GET_FARVAR(seg, *data_far);
+        outb(val, VGAREG_ACTL_WRITE_DATA);
+        data_far++;
+    }
+    outb(0x11, VGAREG_ACTL_ADDRESS);
+    outb(GET_FARVAR(seg, *data_far), VGAREG_ACTL_WRITE_DATA);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_get_all_palette_reg(u16 seg, u8 *data_far)
+{
+    int i;
+    for (i = 0; i < 0x10; i++) {
+        inb(VGAREG_ACTL_RESET);
+        outb(i, VGAREG_ACTL_ADDRESS);
+        SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
+        data_far++;
+    }
+    inb(VGAREG_ACTL_RESET);
+    outb(0x11, VGAREG_ACTL_ADDRESS);
+    SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
+    inb(VGAREG_ACTL_RESET);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_toggle_intensity(u8 flag)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x10, VGAREG_ACTL_ADDRESS);
+    u8 val = (inb(VGAREG_ACTL_READ_DATA) & 0xf7) | ((flag & 0x01) << 3);
+    outb(val, VGAREG_ACTL_WRITE_DATA);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_select_video_dac_color_page(u8 flag, u8 data)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x10, VGAREG_ACTL_ADDRESS);
+    u8 val = inb(VGAREG_ACTL_READ_DATA);
+    if (!(flag & 0x01)) {
+        // select paging mode
+        val = (val & 0x7f) | (data << 7);
+        outb(val, VGAREG_ACTL_WRITE_DATA);
+        outb(0x20, VGAREG_ACTL_ADDRESS);
+        return;
+    }
+    // select page
+    inb(VGAREG_ACTL_RESET);
+    outb(0x14, VGAREG_ACTL_ADDRESS);
+    if (!(val & 0x80))
+        data <<= 2;
+    data &= 0x0f;
+    outb(data, VGAREG_ACTL_WRITE_DATA);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_read_video_dac_state(u8 *pmode, u8 *curpage)
+{
+    inb(VGAREG_ACTL_RESET);
+    outb(0x10, VGAREG_ACTL_ADDRESS);
+    u8 val1 = inb(VGAREG_ACTL_READ_DATA) >> 7;
+
+    inb(VGAREG_ACTL_RESET);
+    outb(0x14, VGAREG_ACTL_ADDRESS);
+    u8 val2 = inb(VGAREG_ACTL_READ_DATA) & 0x0f;
+    if (!(val1 & 0x01))
+        val2 >>= 2;
+
+    inb(VGAREG_ACTL_RESET);
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+
+    *pmode = val1;
+    *curpage = val2;
+}
+
+
+/****************************************************************
+ * DAC control
+ ****************************************************************/
+
+void
+vgahw_set_dac_regs(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--;
+    }
+}
+
+void
+vgahw_get_dac_regs(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
+vgahw_set_pel_mask(u8 val)
+{
+    outb(val, VGAREG_PEL_MASK);
+}
+
+u8
+vgahw_get_pel_mask(void)
+{
+    return inb(VGAREG_PEL_MASK);
+}
+
+void
+vgahw_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, inb(VGAREG_PEL_MASK));
+    vgahw_get_dac_regs(seg, info->dac, 0, 256);
+    SET_FARVAR(seg, info->color_select, 0);
+}
+
+void
+vgahw_restore_dac_state(u16 seg, struct saveDACcolors *info)
+{
+    outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK);
+    vgahw_set_dac_regs(seg, info->dac, 0, 256);
+    outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
+}
+
+
+/****************************************************************
+ * Memory control
+ ****************************************************************/
+
+void
+vgahw_sequ_write(u8 index, u8 value)
+{
+    outw((value<<8) | index, VGAREG_SEQU_ADDRESS);
+}
+
+void
+vgahw_grdc_write(u8 index, u8 value)
+{
+    outw((value<<8) | index, VGAREG_GRDC_ADDRESS);
+}
+
+void
+vgahw_set_text_block_specifier(u8 spec)
+{
+    outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS);
+}
+
+void
+get_font_access(void)
+{
+    outw(0x0100, VGAREG_SEQU_ADDRESS);
+    outw(0x0402, VGAREG_SEQU_ADDRESS);
+    outw(0x0704, VGAREG_SEQU_ADDRESS);
+    outw(0x0300, VGAREG_SEQU_ADDRESS);
+    outw(0x0204, VGAREG_GRDC_ADDRESS);
+    outw(0x0005, VGAREG_GRDC_ADDRESS);
+    outw(0x0406, VGAREG_GRDC_ADDRESS);
+}
+
+void
+release_font_access(void)
+{
+    outw(0x0100, VGAREG_SEQU_ADDRESS);
+    outw(0x0302, VGAREG_SEQU_ADDRESS);
+    outw(0x0304, VGAREG_SEQU_ADDRESS);
+    outw(0x0300, VGAREG_SEQU_ADDRESS);
+    u16 v = (inw(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a;
+    outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS);
+    outw(0x0004, VGAREG_GRDC_ADDRESS);
+    outw(0x1005, VGAREG_GRDC_ADDRESS);
+}
+
+
+/****************************************************************
+ * CRTC registers
+ ****************************************************************/
+
+static u16
+get_crtc(void)
+{
+    return GET_BDA(crtc_address);
+}
+
+void
+vgahw_set_cursor_shape(u8 start, u8 end)
+{
+    u16 crtc_addr = get_crtc();
+    outb(0x0a, crtc_addr);
+    outb(start, crtc_addr + 1);
+    outb(0x0b, crtc_addr);
+    outb(end, crtc_addr + 1);
+}
+
+void
+vgahw_set_active_page(u16 address)
+{
+    u16 crtc_addr = get_crtc();
+    outb(0x0c, crtc_addr);
+    outb((address & 0xff00) >> 8, crtc_addr + 1);
+    outb(0x0d, crtc_addr);
+    outb(address & 0x00ff, crtc_addr + 1);
+}
+
+void
+vgahw_set_cursor_pos(u16 address)
+{
+    u16 crtc_addr = get_crtc();
+    outb(0x0e, crtc_addr);
+    outb((address & 0xff00) >> 8, crtc_addr + 1);
+    outb(0x0f, crtc_addr);
+    outb(address & 0x00ff, crtc_addr + 1);
+}
+
+void
+vgahw_set_scan_lines(u8 lines)
+{
+    u16 crtc_addr = get_crtc();
+    outb(0x09, crtc_addr);
+    u8 crtc_r9 = inb(crtc_addr + 1);
+    crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
+    outb(crtc_r9, crtc_addr + 1);
+}
+
+// Get vertical display end
+u16
+vgahw_get_vde(void)
+{
+    u16 crtc_addr = get_crtc();
+    outb(0x12, crtc_addr);
+    u16 vde = inb(crtc_addr + 1);
+    outb(0x07, crtc_addr);
+    u8 ovl = inb(crtc_addr + 1);
+    vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
+    return vde;
+}
+
+
+/****************************************************************
+ * Save/Restore/Set state
+ ****************************************************************/
+
+void
+vgahw_save_state(u16 seg, struct saveVideoHardware *info)
+{
+    u16 crtc_addr = 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));
+    inb(VGAREG_ACTL_RESET);
+    u16 ar_index = inb(VGAREG_ACTL_ADDRESS);
+    SET_FARVAR(seg, info->actl_index, ar_index);
+    SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
+
+    u16 i;
+    for (i=0; i<4; i++) {
+        outb(i+1, VGAREG_SEQU_ADDRESS);
+        SET_FARVAR(seg, info->sequ_regs[i], inb(VGAREG_SEQU_DATA));
+    }
+    outb(0, VGAREG_SEQU_ADDRESS);
+    SET_FARVAR(seg, info->sequ0, inb(VGAREG_SEQU_DATA));
+
+    for (i=0; i<25; i++) {
+        outb(i, crtc_addr);
+        SET_FARVAR(seg, info->crtc_regs[i], inb(crtc_addr + 1));
+    }
+
+    for (i=0; i<20; i++) {
+        inb(VGAREG_ACTL_RESET);
+        outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
+        SET_FARVAR(seg, info->actl_regs[i], inb(VGAREG_ACTL_READ_DATA));
+    }
+    inb(VGAREG_ACTL_RESET);
+
+    for (i=0; i<9; i++) {
+        outb(i, VGAREG_GRDC_ADDRESS);
+        SET_FARVAR(seg, info->grdc_regs[i], inb(VGAREG_GRDC_DATA));
+    }
+
+    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);
+}
+
+void
+vgahw_restore_state(u16 seg, struct saveVideoHardware *info)
+{
+    // Reset Attribute Ctl flip-flop
+    inb(VGAREG_ACTL_RESET);
+
+    u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
+
+    u16 i;
+    for (i=0; i<4; i++) {
+        outb(i+1, VGAREG_SEQU_ADDRESS);
+        outb(GET_FARVAR(seg, info->sequ_regs[i]), VGAREG_SEQU_DATA);
+    }
+    outb(0, VGAREG_SEQU_ADDRESS);
+    outb(GET_FARVAR(seg, info->sequ0), VGAREG_SEQU_DATA);
+
+    // Disable CRTC write protection
+    outw(0x0011, crtc_addr);
+    // Set CRTC regs
+    for (i=0; i<25; i++)
+        if (i != 0x11) {
+            outb(i, crtc_addr);
+            outb(GET_FARVAR(seg, info->crtc_regs[i]), crtc_addr + 1);
+        }
+    // select crtc base address
+    u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
+    if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS)
+        v |= 0x01;
+    outb(v, VGAREG_WRITE_MISC_OUTPUT);
+
+    // enable write protection if needed
+    outb(0x11, crtc_addr);
+    outb(GET_FARVAR(seg, info->crtc_regs[0x11]), crtc_addr + 1);
+
+    // Set Attribute Ctl
+    u16 ar_index = GET_FARVAR(seg, info->actl_index);
+    inb(VGAREG_ACTL_RESET);
+    for (i=0; i<20; i++) {
+        outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
+        outb(GET_FARVAR(seg, info->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
+    }
+    outb(ar_index, VGAREG_ACTL_ADDRESS);
+    inb(VGAREG_ACTL_RESET);
+
+    for (i=0; i<9; i++) {
+        outb(i, VGAREG_GRDC_ADDRESS);
+        outb(GET_FARVAR(seg, info->grdc_regs[i]), VGAREG_GRDC_DATA);
+    }
+
+    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);
+}
+
+void
+vgahw_set_mode(struct VideoParam_s *vparam_g)
+{
+    // Reset Attribute Ctl flip-flop
+    inb(VGAREG_ACTL_RESET);
+
+    // Set Attribute Ctl
+    u16 i;
+    for (i = 0; i <= 0x13; i++) {
+        outb(i, VGAREG_ACTL_ADDRESS);
+        outb(GET_GLOBAL(vparam_g->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
+    }
+    outb(0x14, VGAREG_ACTL_ADDRESS);
+    outb(0x00, VGAREG_ACTL_WRITE_DATA);
+
+    // Set Sequencer Ctl
+    outb(0, VGAREG_SEQU_ADDRESS);
+    outb(0x03, VGAREG_SEQU_DATA);
+    for (i = 1; i <= 4; i++) {
+        outb(i, VGAREG_SEQU_ADDRESS);
+        outb(GET_GLOBAL(vparam_g->sequ_regs[i - 1]), VGAREG_SEQU_DATA);
+    }
+
+    // Set Grafx Ctl
+    for (i = 0; i <= 8; i++) {
+        outb(i, VGAREG_GRDC_ADDRESS);
+        outb(GET_GLOBAL(vparam_g->grdc_regs[i]), VGAREG_GRDC_DATA);
+    }
+
+    // Set CRTC address VGA or MDA
+    u8 miscreg = GET_GLOBAL(vparam_g->miscreg);
+    u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
+    if (!(miscreg & 1))
+        crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
+
+    // Disable CRTC write protection
+    outw(0x0011, crtc_addr);
+    // Set CRTC regs
+    for (i = 0; i <= 0x18; i++) {
+        outb(i, crtc_addr);
+        outb(GET_GLOBAL(vparam_g->crtc_regs[i]), crtc_addr + 1);
+    }
+
+    // Set the misc register
+    outb(miscreg, VGAREG_WRITE_MISC_OUTPUT);
+
+    // Enable video
+    outb(0x20, VGAREG_ACTL_ADDRESS);
+    inb(VGAREG_ACTL_RESET);
+}
+
+
+/****************************************************************
+ * Misc
+ ****************************************************************/
+
+void
+vgahw_enable_video_addressing(u8 disable)
+{
+    u8 v = (disable & 1) ? 0x00 : 0x02;
+    u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02;
+    outb(v | v2, VGAREG_WRITE_MISC_OUTPUT);
+}
+
+void
+vgahw_init(void)
+{
+    // switch to color mode and enable CPU access 480 lines
+    outb(0xc3, VGAREG_WRITE_MISC_OUTPUT);
+    // more than 64k 3C4/04
+    outb(0x04, VGAREG_SEQU_ADDRESS);
+    outb(0x02, VGAREG_SEQU_DATA);
+}
diff --git a/bios/seabios/vgasrc/vgalayout.lds.S b/bios/seabios/vgasrc/vgalayout.lds.S
new file mode 100644 (file)
index 0000000..08a5f32
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.__func__.*)
+                *(.rodata.str1.1)
+                *(.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) }
+}
diff --git a/bios/seabios/vgasrc/vgatables.c b/bios/seabios/vgasrc/vgatables.c
new file mode 100644 (file)
index 0000000..0587e65
--- /dev/null
@@ -0,0 +1,438 @@
+// Tables used by VGA bios
+//
+// 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 "vgatables.h" // struct VideoParamTableEntry_s
+#include "biosvar.h" // GET_GLOBAL
+
+
+/****************************************************************
+ * Video parameter table
+ ****************************************************************/
+
+struct VideoParam_s video_param_table[] VAR16 = {
+    // index=0x00 no mode defined
+    {},
+    // index=0x01 no mode defined
+    {},
+    // index=0x02 no mode defined
+    {},
+    // index=0x03 no mode defined
+    {},
+    // index=0x04 vga mode 0x04
+    { 40, 24, 8, 0x0800,      /* tw, th-1, ch, slength */
+      { 0x09, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x01, 0x00, 0x03, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x05 vga mode 0x05 */
+    { 40, 24, 8, 0x0800,     /* tw, th-1, ch, slength */
+      { 0x09, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x01, 0x00, 0x03, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x06 vga mode 0x06 */
+    { 80, 24, 8, 0x1000,     /* tw, th-1, ch, slength */
+      { 0x01, 0x01, 0x00, 0x06 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+        0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+        0x01, 0x00, 0x01, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x07 vga mode 0x07 */
+    { 80, 24, 16, 0x1000,    /* tw, th-1, ch, slength */
+      { 0x00, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x66,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+        0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x0e, 0x00, 0x0f, 0x08 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x08 no mode defined */
+    {},
+    /* index=0x09 no mode defined */
+    {},
+    /* index=0x0a no mode defined */
+    {},
+    /* index=0x0b no mode defined */
+    {},
+    /* index=0x0c no mode defined */
+    {},
+    /* index=0x0d vga mode 0x0d */
+    { 40, 24, 8, 0x2000,     /* tw, th-1, ch, slength */
+      { 0x09, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x0e vga mode 0x0e */
+    { 80, 24, 8, 0x4000,     /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x0f no mode defined */
+    {},
+    /* index=0x10 no mode defined */
+    {},
+    /* index=0x11 vga mode 0x0f */
+    { 80, 24, 14, 0x8000,    /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xa3,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+        0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+        0x01, 0x00, 0x01, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x12 vga mode 0x10 */
+    { 80, 24, 14, 0x8000,    /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xa3,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x13 no mode defined */
+    {},
+    /* index=0x14 no mode defined */
+    {},
+    /* index=0x15 no mode defined */
+    {},
+    /* index=0x16 no mode defined */
+    {},
+    /* index=0x17 vga mode 0x01 */
+    { 40, 24, 16, 0x0800,    /* tw, th-1, ch, slength */
+      { 0x08, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x67,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x0c, 0x00, 0x0f, 0x08 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x18 vga mode 0x03 */
+    { 80, 24, 16, 0x1000,    /* tw, th-1, ch, slength */
+      { 0x00, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x67,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x0c, 0x00, 0x0f, 0x08 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x19 vga mode 0x07 */
+    { 80, 24, 16, 0x1000,    /* tw, th-1, ch, slength */
+      { 0x00, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x66,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+        0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x0e, 0x00, 0x0f, 0x08 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x1a vga mode 0x11 */
+    { 80, 29, 16, 0x0000,    /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xe3,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+        0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x1b vga mode 0x12 */
+    { 80, 29, 16, 0x0000,    /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xe3,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x1c vga mode 0x13 */
+    { 40, 24, 8, 0x0000,     /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x0e },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+        0x41, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+    /* index=0x1d vga mode 0x6a */
+    { 100, 36, 16, 0x0000,   /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xe3,                      /* miscreg */
+      { 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 },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+     },
+};
+
+
+/****************************************************************
+ * Palette 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
+};
+
+
+/****************************************************************
+ * Video mode list
+ ****************************************************************/
+
+#define PAL(x) x, sizeof(x)
+#define VPARAM(x) &video_param_table[x]
+
+static struct vgamode_s vga_modes[] VAR16 = {
+    //mode vparam        model bits  sstart     pelm  dac
+    {0x00, VPARAM(0x17), CTEXT,   4, SEG_CTEXT, 0xFF, PAL(palette2)},
+    {0x01, VPARAM(0x17), CTEXT,   4, SEG_CTEXT, 0xFF, PAL(palette2)},
+    {0x02, VPARAM(0x18), CTEXT,   4, SEG_CTEXT, 0xFF, PAL(palette2)},
+    {0x03, VPARAM(0x18), CTEXT,   4, SEG_CTEXT, 0xFF, PAL(palette2)},
+    {0x04, VPARAM(0x04), CGA,     2, SEG_CTEXT, 0xFF, PAL(palette1)},
+    {0x05, VPARAM(0x05), CGA,     2, SEG_CTEXT, 0xFF, PAL(palette1)},
+    {0x06, VPARAM(0x06), CGA,     1, SEG_CTEXT, 0xFF, PAL(palette1)},
+    {0x07, VPARAM(0x07), MTEXT,   4, SEG_MTEXT, 0xFF, PAL(palette0)},
+    {0x0D, VPARAM(0x0d), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette1)},
+    {0x0E, VPARAM(0x0e), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette1)},
+    {0x0F, VPARAM(0x11), PLANAR1, 1, SEG_GRAPH, 0xFF, PAL(palette0)},
+    {0x10, VPARAM(0x12), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette2)},
+    {0x11, VPARAM(0x1a), PLANAR1, 1, SEG_GRAPH, 0xFF, PAL(palette2)},
+    {0x12, VPARAM(0x1b), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette2)},
+    {0x13, VPARAM(0x1c), LINEAR8, 8, SEG_GRAPH, 0xFF, PAL(palette3)},
+    {0x6A, VPARAM(0x1d), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette2)},
+};
+
+struct vgamode_s *
+find_vga_entry(u8 mode)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(vga_modes); i++) {
+        struct vgamode_s *vmode_g = &vga_modes[i];
+        if (GET_GLOBAL(vmode_g->svgamode) == mode)
+            return vmode_g;
+    }
+    return NULL;
+}
+
+u16 video_save_pointer_table[14] VAR16;
+
+
+/****************************************************************
+ * Static functionality table
+ ****************************************************************/
+
+u8 static_functionality[0x10] VAR16 = {
+ /* 0 */ 0xff,  // All modes supported #1
+ /* 1 */ 0xe0,  // All modes supported #2
+ /* 2 */ 0x0f,  // All modes supported #3
+ /* 3 */ 0x00, 0x00, 0x00, 0x00,  // reserved
+ /* 7 */ 0x07,  // 200, 350, 400 scan lines
+ /* 8 */ 0x02,  // mamimum number of visible charsets in text mode
+ /* 9 */ 0x08,  // total number of charset blocks in text mode
+ /* a */ 0xe7,  // Change to add new functions
+ /* b */ 0x0c,  // Change to add new functions
+ /* c */ 0x00,  // reserved
+ /* d */ 0x00,  // reserved
+ /* e */ 0x00,  // Change to add new functions
+ /* f */ 0x00   // reserved
+};
diff --git a/bios/seabios/vgasrc/vgatables.h b/bios/seabios/vgasrc/vgatables.h
new file mode 100644 (file)
index 0000000..1e76b3a
--- /dev/null
@@ -0,0 +1,217 @@
+#ifndef __VGATABLES_H
+#define __VGATABLES_H
+
+#include "types.h" // u8
+#include "farptr.h" // struct segoff_s
+
+/*
+ *
+ * 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
+
+/*
+ * Tables of default values for each mode
+ */
+#define TEXT       0x80
+
+#define CTEXT      (0x00 | TEXT)
+#define MTEXT      (0x01 | TEXT)
+#define CGA        0x02
+#define PLANAR1    0x03
+#define PLANAR4    0x04
+#define LINEAR8    0x05
+
+// for SVGA
+#define LINEAR15   0x10
+#define LINEAR16   0x11
+#define LINEAR24   0x12
+#define LINEAR32   0x13
+
+#define SCREEN_IO_START(x,y,p) (((((x)*(y)) | 0x00ff) + 1) * (p))
+#define SCREEN_MEM_START(x,y,p) SCREEN_IO_START(((x)*2),(y),(p))
+
+/* standard BIOS Video Parameter Table */
+struct VideoParam_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;
+
+struct vgamode_s {
+    u8 svgamode;
+    struct VideoParam_s *vparam;
+    u8 memmodel;    /* CTEXT,MTEXT,CGA,PL1,PL2,PL4,P8,P15,P16,P24,P32 */
+    u8 pixbits;
+    u16 sstart;
+    u8 pelmask;
+    u8 *dac;
+    u16 dacsize;
+};
+
+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];
+};
+
+struct saveBDAstate {
+    u8 video_mode;
+    u16 video_cols;
+    u16 video_pagesize;
+    u16 crtc_address;
+    u8 video_rows;
+    u16 char_height;
+    u8 video_ctl;
+    u8 video_switches;
+    u8 modeset_ctl;
+    u16 cursor_type;
+    u16 cursor_pos[8];
+    u16 video_pagestart;
+    u8 video_page;
+    /* current font */
+    struct segoff_s font0;
+    struct segoff_s font1;
+};
+
+struct saveDACcolors {
+    u8 rwmode;
+    u8 peladdr;
+    u8 pelmask;
+    u8 dac[768];
+    u8 color_select;
+};
+
+// vgatables.c
+struct vgamode_s *find_vga_entry(u8 mode);
+extern u16 video_save_pointer_table[];
+extern struct VideoParam_s video_param_table[];
+extern u8 static_functionality[];
+
+// vgafonts.c
+extern u8 vgafont8[];
+extern u8 vgafont14[];
+extern u8 vgafont16[];
+extern u8 vgafont14alt[];
+extern u8 vgafont16alt[];
+
+// vga.c
+struct carattr {
+    u8 car, attr, use_attr;
+};
+struct cursorpos {
+    u8 x, y, page;
+};
+
+// vgafb.c
+void clear_screen(struct vgamode_s *vmode_g);
+void vgafb_scroll(int nblines, int attr
+                  , struct cursorpos ul, struct cursorpos lr);
+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_load_font(u16 seg, void *src_far, u16 count
+                     , u16 start, u8 destflags, u8 fontsize);
+
+// vgaio.c
+void vgahw_screen_disable(void);
+void vgahw_screen_enable(void);
+void vgahw_set_border_color(u8 color);
+void vgahw_set_overscan_border_color(u8 color);
+u8 vgahw_get_overscan_border_color(void);
+void vgahw_set_palette(u8 palid);
+void vgahw_set_single_palette_reg(u8 reg, u8 val);
+u8 vgahw_get_single_palette_reg(u8 reg);
+void vgahw_set_all_palette_reg(u16 seg, u8 *data_far);
+void vgahw_get_all_palette_reg(u16 seg, u8 *data_far);
+void vgahw_toggle_intensity(u8 flag);
+void vgahw_select_video_dac_color_page(u8 flag, u8 data);
+void vgahw_read_video_dac_state(u8 *pmode, u8 *curpage);
+void vgahw_set_dac_regs(u16 seg, u8 *data_far, u8 start, int count);
+void vgahw_get_dac_regs(u16 seg, u8 *data_far, u8 start, int count);
+void vgahw_set_pel_mask(u8 val);
+u8 vgahw_get_pel_mask(void);
+void vgahw_save_dac_state(u16 seg, struct saveDACcolors *info);
+void vgahw_restore_dac_state(u16 seg, struct saveDACcolors *info);
+void vgahw_sequ_write(u8 index, u8 value);
+void vgahw_grdc_write(u8 index, u8 value);
+void vgahw_set_text_block_specifier(u8 spec);
+void get_font_access(void);
+void release_font_access(void);
+void vgahw_set_cursor_shape(u8 start, u8 end);
+void vgahw_set_active_page(u16 address);
+void vgahw_set_cursor_pos(u16 address);
+void vgahw_set_scan_lines(u8 lines);
+u16 vgahw_get_vde(void);
+void vgahw_save_state(u16 seg, struct saveVideoHardware *info);
+void vgahw_restore_state(u16 seg, struct saveVideoHardware *info);
+void vgahw_set_mode(struct VideoParam_s *vparam_g);
+void vgahw_enable_video_addressing(u8 disable);
+void vgahw_init(void);
+
+// clext.c
+void cirrus_set_video_mode(u8 mode);
+void cirrus_init(void);
+
+// vbe.c -- not implemented yet.
+#define VBE_DISPI_DISABLED              0x00
+void dispi_set_enable(int enable);
+void vbe_init(void);
+int vbe_has_vbe_display(void);
+
+#endif // vgatables.h