summaryrefslogtreecommitdiffstats
path: root/qemu/roms/seabios/src/fw
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2015-08-28 09:58:54 +0800
committerYang Zhang <yang.z.zhang@intel.com>2015-09-01 12:44:00 +0800
commite44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch)
tree66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/seabios/src/fw
parent9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff)
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/seabios/src/fw')
-rw-r--r--qemu/roms/seabios/src/fw/acpi-dsdt-cpu-hotplug.dsl78
-rw-r--r--qemu/roms/seabios/src/fw/acpi-dsdt-dbug.dsl26
-rw-r--r--qemu/roms/seabios/src/fw/acpi-dsdt-hpet.dsl36
-rw-r--r--qemu/roms/seabios/src/fw/acpi-dsdt-isa.dsl102
-rw-r--r--qemu/roms/seabios/src/fw/acpi-dsdt-pci-crs.dsl90
-rw-r--r--qemu/roms/seabios/src/fw/acpi-dsdt.dsl342
-rw-r--r--qemu/roms/seabios/src/fw/acpi.c685
-rw-r--r--qemu/roms/seabios/src/fw/biostables.c461
-rw-r--r--qemu/roms/seabios/src/fw/coreboot.c553
-rw-r--r--qemu/roms/seabios/src/fw/csm.c344
-rw-r--r--qemu/roms/seabios/src/fw/dev-piix.h29
-rw-r--r--qemu/roms/seabios/src/fw/dev-q35.h49
-rw-r--r--qemu/roms/seabios/src/fw/lzmadecode.c398
-rw-r--r--qemu/roms/seabios/src/fw/lzmadecode.h67
-rw-r--r--qemu/roms/seabios/src/fw/mptable.c196
-rw-r--r--qemu/roms/seabios/src/fw/mtrr.c106
-rw-r--r--qemu/roms/seabios/src/fw/paravirt.c448
-rw-r--r--qemu/roms/seabios/src/fw/paravirt.h37
-rw-r--r--qemu/roms/seabios/src/fw/pciinit.c954
-rw-r--r--qemu/roms/seabios/src/fw/pirtable.c103
-rw-r--r--qemu/roms/seabios/src/fw/q35-acpi-dsdt.dsl450
-rw-r--r--qemu/roms/seabios/src/fw/romfile_loader.c177
-rw-r--r--qemu/roms/seabios/src/fw/romfile_loader.h72
-rw-r--r--qemu/roms/seabios/src/fw/shadow.c171
-rw-r--r--qemu/roms/seabios/src/fw/smbios.c585
-rw-r--r--qemu/roms/seabios/src/fw/smm.c259
-rw-r--r--qemu/roms/seabios/src/fw/smp.c153
-rw-r--r--qemu/roms/seabios/src/fw/ssdt-misc.dsl104
-rw-r--r--qemu/roms/seabios/src/fw/ssdt-pcihp.dsl36
-rw-r--r--qemu/roms/seabios/src/fw/ssdt-proc.dsl48
-rw-r--r--qemu/roms/seabios/src/fw/xen.c147
-rw-r--r--qemu/roms/seabios/src/fw/xen.h125
32 files changed, 7431 insertions, 0 deletions
diff --git a/qemu/roms/seabios/src/fw/acpi-dsdt-cpu-hotplug.dsl b/qemu/roms/seabios/src/fw/acpi-dsdt-cpu-hotplug.dsl
new file mode 100644
index 000000000..0f3e83b14
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/acpi-dsdt-cpu-hotplug.dsl
@@ -0,0 +1,78 @@
+/****************************************************************
+ * CPU hotplug
+ ****************************************************************/
+
+Scope(\_SB) {
+ /* Objects filled in by run-time generated SSDT */
+ External(NTFY, MethodObj)
+ External(CPON, PkgObj)
+
+ /* Methods called by run-time generated SSDT Processor objects */
+ Method(CPMA, 1, NotSerialized) {
+ // _MAT method - create an madt apic buffer
+ // Arg0 = Processor ID = Local APIC ID
+ // Local0 = CPON flag for this cpu
+ Store(DerefOf(Index(CPON, Arg0)), Local0)
+ // Local1 = Buffer (in madt apic form) to return
+ Store(Buffer(8) {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}, Local1)
+ // Update the processor id, lapic id, and enable/disable status
+ Store(Arg0, Index(Local1, 2))
+ Store(Arg0, Index(Local1, 3))
+ Store(Local0, Index(Local1, 4))
+ Return (Local1)
+ }
+ Method(CPST, 1, NotSerialized) {
+ // _STA method - return ON status of cpu
+ // Arg0 = Processor ID = Local APIC ID
+ // Local0 = CPON flag for this cpu
+ Store(DerefOf(Index(CPON, Arg0)), Local0)
+ If (Local0) {
+ Return (0xF)
+ } Else {
+ Return (0x0)
+ }
+ }
+ Method(CPEJ, 2, NotSerialized) {
+ // _EJ0 method - eject callback
+ Sleep(200)
+ }
+
+ /* CPU hotplug notify method */
+ OperationRegion(PRST, SystemIO, 0xaf00, 32)
+ Field(PRST, ByteAcc, NoLock, Preserve) {
+ PRS, 256
+ }
+ Method(PRSC, 0) {
+ // Local5 = active cpu bitmap
+ Store(PRS, Local5)
+ // Local2 = last read byte from bitmap
+ Store(Zero, Local2)
+ // Local0 = Processor ID / APIC ID iterator
+ Store(Zero, Local0)
+ While (LLess(Local0, SizeOf(CPON))) {
+ // Local1 = CPON flag for this cpu
+ Store(DerefOf(Index(CPON, Local0)), Local1)
+ If (And(Local0, 0x07)) {
+ // Shift down previously read bitmap byte
+ ShiftRight(Local2, 1, Local2)
+ } Else {
+ // Read next byte from cpu bitmap
+ Store(DerefOf(Index(Local5, ShiftRight(Local0, 3))), Local2)
+ }
+ // Local3 = active state for this cpu
+ Store(And(Local2, 1), Local3)
+
+ If (LNotEqual(Local1, Local3)) {
+ // State change - update CPON with new state
+ Store(Local3, Index(CPON, Local0))
+ // Do CPU notify
+ If (LEqual(Local3, 1)) {
+ NTFY(Local0, 1)
+ } Else {
+ NTFY(Local0, 3)
+ }
+ }
+ Increment(Local0)
+ }
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/acpi-dsdt-dbug.dsl b/qemu/roms/seabios/src/fw/acpi-dsdt-dbug.dsl
new file mode 100644
index 000000000..276321f61
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/acpi-dsdt-dbug.dsl
@@ -0,0 +1,26 @@
+/****************************************************************
+ * Debugging
+ ****************************************************************/
+
+Scope(\) {
+ /* Debug Output */
+ OperationRegion(DBG, SystemIO, 0x0402, 0x01)
+ Field(DBG, ByteAcc, NoLock, Preserve) {
+ DBGB, 8,
+ }
+
+ /* Debug method - use this method to send output to the QEMU
+ * BIOS debug port. This method handles strings, integers,
+ * and buffers. For example: DBUG("abc") DBUG(0x123) */
+ Method(DBUG, 1) {
+ ToHexString(Arg0, Local0)
+ ToBuffer(Local0, Local0)
+ Subtract(SizeOf(Local0), 1, Local1)
+ Store(Zero, Local2)
+ While (LLess(Local2, Local1)) {
+ Store(DerefOf(Index(Local0, Local2)), DBGB)
+ Increment(Local2)
+ }
+ Store(0x0A, DBGB)
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/acpi-dsdt-hpet.dsl b/qemu/roms/seabios/src/fw/acpi-dsdt-hpet.dsl
new file mode 100644
index 000000000..f33e52795
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/acpi-dsdt-hpet.dsl
@@ -0,0 +1,36 @@
+/****************************************************************
+ * HPET
+ ****************************************************************/
+
+Scope(\_SB) {
+ Device(HPET) {
+ Name(_HID, EISAID("PNP0103"))
+ Name(_UID, 0)
+ OperationRegion(HPTM, SystemMemory, 0xFED00000, 0x400)
+ Field(HPTM, DWordAcc, Lock, Preserve) {
+ VEND, 32,
+ PRD, 32,
+ }
+ Method(_STA, 0, NotSerialized) {
+ Store(VEND, Local0)
+ Store(PRD, Local1)
+ ShiftRight(Local0, 16, Local0)
+ If (LOr(LEqual(Local0, 0), LEqual(Local0, 0xffff))) {
+ Return (0x0)
+ }
+ If (LOr(LEqual(Local1, 0), LGreater(Local1, 100000000))) {
+ Return (0x0)
+ }
+ Return (0x0F)
+ }
+ Name(_CRS, ResourceTemplate() {
+#if 0 /* This makes WinXP BSOD for not yet figured reasons. */
+ IRQNoFlags() {2, 8}
+#endif
+ Memory32Fixed(ReadOnly,
+ 0xFED00000, // Address Base
+ 0x00000400, // Address Length
+ )
+ })
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/acpi-dsdt-isa.dsl b/qemu/roms/seabios/src/fw/acpi-dsdt-isa.dsl
new file mode 100644
index 000000000..23761dbba
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/acpi-dsdt-isa.dsl
@@ -0,0 +1,102 @@
+/* Common legacy ISA style devices. */
+Scope(\_SB.PCI0.ISA) {
+
+ Device(RTC) {
+ Name(_HID, EisaId("PNP0B00"))
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x0070, 0x0070, 0x10, 0x02)
+ IRQNoFlags() { 8 }
+ IO(Decode16, 0x0072, 0x0072, 0x02, 0x06)
+ })
+ }
+
+ Device(KBD) {
+ Name(_HID, EisaId("PNP0303"))
+ Method(_STA, 0, NotSerialized) {
+ Return (0x0f)
+ }
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x0060, 0x0060, 0x01, 0x01)
+ IO(Decode16, 0x0064, 0x0064, 0x01, 0x01)
+ IRQNoFlags() { 1 }
+ })
+ }
+
+ Device(MOU) {
+ Name(_HID, EisaId("PNP0F13"))
+ Method(_STA, 0, NotSerialized) {
+ Return (0x0f)
+ }
+ Name(_CRS, ResourceTemplate() {
+ IRQNoFlags() { 12 }
+ })
+ }
+
+ Device(FDC0) {
+ Name(_HID, EisaId("PNP0700"))
+ Method(_STA, 0, NotSerialized) {
+ Store(FDEN, Local0)
+ If (LEqual(Local0, 0)) {
+ Return (0x00)
+ } Else {
+ Return (0x0F)
+ }
+ }
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x03F2, 0x03F2, 0x00, 0x04)
+ IO(Decode16, 0x03F7, 0x03F7, 0x00, 0x01)
+ IRQNoFlags() { 6 }
+ DMA(Compatibility, NotBusMaster, Transfer8) { 2 }
+ })
+ }
+
+ Device(LPT) {
+ Name(_HID, EisaId("PNP0400"))
+ Method(_STA, 0, NotSerialized) {
+ Store(LPEN, Local0)
+ If (LEqual(Local0, 0)) {
+ Return (0x00)
+ } Else {
+ Return (0x0F)
+ }
+ }
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x0378, 0x0378, 0x08, 0x08)
+ IRQNoFlags() { 7 }
+ })
+ }
+
+ Device(COM1) {
+ Name(_HID, EisaId("PNP0501"))
+ Name(_UID, 0x01)
+ Method(_STA, 0, NotSerialized) {
+ Store(CAEN, Local0)
+ If (LEqual(Local0, 0)) {
+ Return (0x00)
+ } Else {
+ Return (0x0F)
+ }
+ }
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x03F8, 0x03F8, 0x00, 0x08)
+ IRQNoFlags() { 4 }
+ })
+ }
+
+ Device(COM2) {
+ Name(_HID, EisaId("PNP0501"))
+ Name(_UID, 0x02)
+ Method(_STA, 0, NotSerialized) {
+ Store(CBEN, Local0)
+ If (LEqual(Local0, 0)) {
+ Return (0x00)
+ } Else {
+ Return (0x0F)
+ }
+ }
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x02F8, 0x02F8, 0x00, 0x08)
+ IRQNoFlags() { 3 }
+ })
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/acpi-dsdt-pci-crs.dsl b/qemu/roms/seabios/src/fw/acpi-dsdt-pci-crs.dsl
new file mode 100644
index 000000000..d4218914f
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/acpi-dsdt-pci-crs.dsl
@@ -0,0 +1,90 @@
+/* PCI CRS (current resources) definition. */
+Scope(\_SB.PCI0) {
+
+ Name(CRES, ResourceTemplate() {
+ WordBusNumber(ResourceProducer, MinFixed, MaxFixed, PosDecode,
+ 0x0000, // Address Space Granularity
+ 0x0000, // Address Range Minimum
+ 0x00FF, // Address Range Maximum
+ 0x0000, // Address Translation Offset
+ 0x0100, // Address Length
+ ,, )
+ IO(Decode16,
+ 0x0CF8, // Address Range Minimum
+ 0x0CF8, // Address Range Maximum
+ 0x01, // Address Alignment
+ 0x08, // Address Length
+ )
+ WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+ 0x0000, // Address Space Granularity
+ 0x0000, // Address Range Minimum
+ 0x0CF7, // Address Range Maximum
+ 0x0000, // Address Translation Offset
+ 0x0CF8, // Address Length
+ ,, , TypeStatic)
+ WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+ 0x0000, // Address Space Granularity
+ 0x0D00, // Address Range Minimum
+ 0xFFFF, // Address Range Maximum
+ 0x0000, // Address Translation Offset
+ 0xF300, // Address Length
+ ,, , TypeStatic)
+ DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
+ 0x00000000, // Address Space Granularity
+ 0x000A0000, // Address Range Minimum
+ 0x000BFFFF, // Address Range Maximum
+ 0x00000000, // Address Translation Offset
+ 0x00020000, // Address Length
+ ,, , AddressRangeMemory, TypeStatic)
+ DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
+ 0x00000000, // Address Space Granularity
+ 0xE0000000, // Address Range Minimum
+ 0xFEBFFFFF, // Address Range Maximum
+ 0x00000000, // Address Translation Offset
+ 0x1EC00000, // Address Length
+ ,, PW32, AddressRangeMemory, TypeStatic)
+ })
+
+ Name(CR64, ResourceTemplate() {
+ QWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
+ 0x00000000, // Address Space Granularity
+ 0x8000000000, // Address Range Minimum
+ 0xFFFFFFFFFF, // Address Range Maximum
+ 0x00000000, // Address Translation Offset
+ 0x8000000000, // Address Length
+ ,, PW64, AddressRangeMemory, TypeStatic)
+ })
+
+ Method(_CRS, 0) {
+ /* Fields provided by dynamically created ssdt */
+ External(P0S, IntObj)
+ External(P0E, IntObj)
+ External(P1V, IntObj)
+ External(P1S, BuffObj)
+ External(P1E, BuffObj)
+ External(P1L, BuffObj)
+
+ /* fixup 32bit pci io window */
+ CreateDWordField(CRES, \_SB.PCI0.PW32._MIN, PS32)
+ CreateDWordField(CRES, \_SB.PCI0.PW32._MAX, PE32)
+ CreateDWordField(CRES, \_SB.PCI0.PW32._LEN, PL32)
+ Store(P0S, PS32)
+ Store(P0E, PE32)
+ Store(Add(Subtract(P0E, P0S), 1), PL32)
+
+ If (LEqual(P1V, Zero)) {
+ Return (CRES)
+ }
+
+ /* fixup 64bit pci io window */
+ CreateQWordField(CR64, \_SB.PCI0.PW64._MIN, PS64)
+ CreateQWordField(CR64, \_SB.PCI0.PW64._MAX, PE64)
+ CreateQWordField(CR64, \_SB.PCI0.PW64._LEN, PL64)
+ Store(P1S, PS64)
+ Store(P1E, PE64)
+ Store(P1L, PL64)
+ /* add window and return result */
+ ConcatenateResTemplate(CRES, CR64, Local0)
+ Return (Local0)
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/acpi-dsdt.dsl b/qemu/roms/seabios/src/fw/acpi-dsdt.dsl
new file mode 100644
index 000000000..3556dcaf1
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/acpi-dsdt.dsl
@@ -0,0 +1,342 @@
+/*
+ * Bochs/QEMU ACPI DSDT ASL definition
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ACPI_EXTRACT_ALL_CODE AmlCode
+
+DefinitionBlock (
+ "acpi-dsdt.aml", // Output Filename
+ "DSDT", // Signature
+ 0x01, // DSDT Compliance Revision
+ "BXPC", // OEMID
+ "BXDSDT", // TABLE ID
+ 0x1 // OEM Revision
+ )
+{
+
+#include "acpi-dsdt-dbug.dsl"
+
+
+/****************************************************************
+ * PCI Bus definition
+ ****************************************************************/
+
+ Scope(\_SB) {
+ Device(PCI0) {
+ Name(_HID, EisaId("PNP0A03"))
+ Name(_ADR, 0x00)
+ Name(_UID, 1)
+ }
+ }
+
+#include "acpi-dsdt-pci-crs.dsl"
+#include "acpi-dsdt-hpet.dsl"
+
+
+/****************************************************************
+ * VGA
+ ****************************************************************/
+
+ Scope(\_SB.PCI0) {
+ Device(VGA) {
+ Name(_ADR, 0x00020000)
+ OperationRegion(PCIC, PCI_Config, Zero, 0x4)
+ Field(PCIC, DWordAcc, NoLock, Preserve) {
+ VEND, 32
+ }
+ Method(_S1D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S2D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S3D, 0, NotSerialized) {
+ If (LEqual(VEND, 0x1001b36)) {
+ Return (0x03) // QXL
+ } Else {
+ Return (0x00)
+ }
+ }
+ }
+ }
+
+
+/****************************************************************
+ * PIIX4 PM
+ ****************************************************************/
+
+ Scope(\_SB.PCI0) {
+ Device(PX13) {
+ Name(_ADR, 0x00010003)
+ OperationRegion(P13C, PCI_Config, 0x00, 0xff)
+ }
+ }
+
+
+/****************************************************************
+ * PIIX3 ISA bridge
+ ****************************************************************/
+
+ Scope(\_SB.PCI0) {
+ Device(ISA) {
+ Name(_ADR, 0x00010000)
+
+ /* PIIX PCI to ISA irq remapping */
+ OperationRegion(P40C, PCI_Config, 0x60, 0x04)
+
+ /* enable bits */
+ Field(\_SB.PCI0.PX13.P13C, AnyAcc, NoLock, Preserve) {
+ Offset(0x5f),
+ , 7,
+ LPEN, 1, // LPT
+ Offset(0x67),
+ , 3,
+ CAEN, 1, // COM1
+ , 3,
+ CBEN, 1, // COM2
+ }
+ Name(FDEN, 1)
+ }
+ }
+
+#include "acpi-dsdt-isa.dsl"
+
+
+/****************************************************************
+ * PCI hotplug
+ ****************************************************************/
+
+ Scope(\_SB.PCI0) {
+ OperationRegion(PCST, SystemIO, 0xae00, 0x08)
+ Field(PCST, DWordAcc, NoLock, WriteAsZeros) {
+ PCIU, 32,
+ PCID, 32,
+ }
+
+ OperationRegion(SEJ, SystemIO, 0xae08, 0x04)
+ Field(SEJ, DWordAcc, NoLock, WriteAsZeros) {
+ B0EJ, 32,
+ }
+
+ /* Methods called by bulk generated PCI devices below */
+
+ /* Methods called by hotplug devices */
+ Method(PCEJ, 1, NotSerialized) {
+ // _EJ0 method - eject callback
+ Store(ShiftLeft(1, Arg0), B0EJ)
+ }
+
+ /* Hotplug notification method supplied by SSDT */
+ External(\_SB.PCI0.PCNT, MethodObj)
+
+ /* PCI hotplug notify method */
+ Method(PCNF, 0) {
+ // Local0 = iterator
+ Store(Zero, Local0)
+ While (LLess(Local0, 31)) {
+ Increment(Local0)
+ If (And(PCIU, ShiftLeft(1, Local0))) {
+ PCNT(Local0, 1)
+ }
+ If (And(PCID, ShiftLeft(1, Local0))) {
+ PCNT(Local0, 3)
+ }
+ }
+ }
+ }
+
+
+/****************************************************************
+ * PCI IRQs
+ ****************************************************************/
+
+ Scope(\_SB) {
+ Scope(PCI0) {
+ Name(_PRT, Package() {
+ /* PCI IRQ routing table, example from ACPI 2.0a specification,
+ section 6.2.8.1 */
+ /* Note: we provide the same info as the PCI routing
+ table of the Bochs BIOS */
+
+#define prt_slot(nr, lnk0, lnk1, lnk2, lnk3) \
+ Package() { nr##ffff, 0, lnk0, 0 }, \
+ Package() { nr##ffff, 1, lnk1, 0 }, \
+ Package() { nr##ffff, 2, lnk2, 0 }, \
+ Package() { nr##ffff, 3, lnk3, 0 }
+
+#define prt_slot0(nr) prt_slot(nr, LNKD, LNKA, LNKB, LNKC)
+#define prt_slot1(nr) prt_slot(nr, LNKA, LNKB, LNKC, LNKD)
+#define prt_slot2(nr) prt_slot(nr, LNKB, LNKC, LNKD, LNKA)
+#define prt_slot3(nr) prt_slot(nr, LNKC, LNKD, LNKA, LNKB)
+
+ prt_slot0(0x0000),
+ /* Device 1 is power mgmt device, and can only use irq 9 */
+ prt_slot(0x0001, LNKS, LNKB, LNKC, LNKD),
+ prt_slot2(0x0002),
+ prt_slot3(0x0003),
+ prt_slot0(0x0004),
+ prt_slot1(0x0005),
+ prt_slot2(0x0006),
+ prt_slot3(0x0007),
+ prt_slot0(0x0008),
+ prt_slot1(0x0009),
+ prt_slot2(0x000a),
+ prt_slot3(0x000b),
+ prt_slot0(0x000c),
+ prt_slot1(0x000d),
+ prt_slot2(0x000e),
+ prt_slot3(0x000f),
+ prt_slot0(0x0010),
+ prt_slot1(0x0011),
+ prt_slot2(0x0012),
+ prt_slot3(0x0013),
+ prt_slot0(0x0014),
+ prt_slot1(0x0015),
+ prt_slot2(0x0016),
+ prt_slot3(0x0017),
+ prt_slot0(0x0018),
+ prt_slot1(0x0019),
+ prt_slot2(0x001a),
+ prt_slot3(0x001b),
+ prt_slot0(0x001c),
+ prt_slot1(0x001d),
+ prt_slot2(0x001e),
+ prt_slot3(0x001f),
+ })
+ }
+
+ Field(PCI0.ISA.P40C, ByteAcc, NoLock, Preserve) {
+ PRQ0, 8,
+ PRQ1, 8,
+ PRQ2, 8,
+ PRQ3, 8
+ }
+
+ Method(IQST, 1, NotSerialized) {
+ // _STA method - get status
+ If (And(0x80, Arg0)) {
+ Return (0x09)
+ }
+ Return (0x0B)
+ }
+ Method(IQCR, 1, Serialized) {
+ // _CRS method - get current settings
+ Name(PRR0, ResourceTemplate() {
+ Interrupt(, Level, ActiveHigh, Shared) { 0 }
+ })
+ CreateDWordField(PRR0, 0x05, PRRI)
+ If (LLess(Arg0, 0x80)) {
+ Store(Arg0, PRRI)
+ }
+ Return (PRR0)
+ }
+
+#define define_link(link, uid, reg) \
+ Device(link) { \
+ Name(_HID, EISAID("PNP0C0F")) \
+ Name(_UID, uid) \
+ Name(_PRS, ResourceTemplate() { \
+ Interrupt(, Level, ActiveHigh, Shared) { \
+ 5, 10, 11 \
+ } \
+ }) \
+ Method(_STA, 0, NotSerialized) { \
+ Return (IQST(reg)) \
+ } \
+ Method(_DIS, 0, NotSerialized) { \
+ Or(reg, 0x80, reg) \
+ } \
+ Method(_CRS, 0, NotSerialized) { \
+ Return (IQCR(reg)) \
+ } \
+ Method(_SRS, 1, NotSerialized) { \
+ CreateDWordField(Arg0, 0x05, PRRI) \
+ Store(PRRI, reg) \
+ } \
+ }
+
+ define_link(LNKA, 0, PRQ0)
+ define_link(LNKB, 1, PRQ1)
+ define_link(LNKC, 2, PRQ2)
+ define_link(LNKD, 3, PRQ3)
+
+ Device(LNKS) {
+ Name(_HID, EISAID("PNP0C0F"))
+ Name(_UID, 4)
+ Name(_PRS, ResourceTemplate() {
+ Interrupt(, Level, ActiveHigh, Shared) { 9 }
+ })
+
+ // The SCI cannot be disabled and is always attached to GSI 9,
+ // so these are no-ops. We only need this link to override the
+ // polarity to active high and match the content of the MADT.
+ Method(_STA, 0, NotSerialized) { Return (0x0b) }
+ Method(_DIS, 0, NotSerialized) { }
+ Method(_CRS, 0, NotSerialized) { Return (_PRS) }
+ Method(_SRS, 1, NotSerialized) { }
+ }
+ }
+
+#include "acpi-dsdt-cpu-hotplug.dsl"
+
+
+/****************************************************************
+ * General purpose events
+ ****************************************************************/
+
+ Scope(\_GPE) {
+ Name(_HID, "ACPI0006")
+
+ Method(_L00) {
+ }
+ Method(_E01) {
+ // PCI hotplug event
+ \_SB.PCI0.PCNF()
+ }
+ Method(_E02) {
+ // CPU hotplug event
+ \_SB.PRSC()
+ }
+ Method(_L03) {
+ }
+ Method(_L04) {
+ }
+ Method(_L05) {
+ }
+ Method(_L06) {
+ }
+ Method(_L07) {
+ }
+ Method(_L08) {
+ }
+ Method(_L09) {
+ }
+ Method(_L0A) {
+ }
+ Method(_L0B) {
+ }
+ Method(_L0C) {
+ }
+ Method(_L0D) {
+ }
+ Method(_L0E) {
+ }
+ Method(_L0F) {
+ }
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/acpi.c b/qemu/roms/seabios/src/fw/acpi.c
new file mode 100644
index 000000000..ecd1adcf1
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/acpi.c
@@ -0,0 +1,685 @@
+// Support for generating ACPI tables (on emulators)
+// DO NOT ADD NEW FEATURES HERE. (See paravirt.c / biostables.c instead.)
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "byteorder.h" // cpu_to_le16
+#include "config.h" // CONFIG_*
+#include "dev-q35.h"
+#include "dev-piix.h"
+#include "hw/pci.h" // pci_find_init_device
+#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "hw/pci_regs.h" // PCI_INTERRUPT_LINE
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "paravirt.h" // RamSize
+#include "romfile.h" // romfile_loadint
+#include "std/acpi.h" // struct rsdp_descriptor
+#include "string.h" // memset
+#include "util.h" // MaxCountCPUs
+#include "x86.h" // readl
+
+#include "src/fw/acpi-dsdt.hex"
+
+static void
+build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev)
+{
+ h->signature = cpu_to_le32(sig);
+ h->length = cpu_to_le32(len);
+ h->revision = rev;
+ memcpy(h->oem_id, BUILD_APPNAME6, 6);
+ memcpy(h->oem_table_id, BUILD_APPNAME4, 4);
+ memcpy(h->oem_table_id + 4, (void*)&sig, 4);
+ h->oem_revision = cpu_to_le32(1);
+ memcpy(h->asl_compiler_id, BUILD_APPNAME4, 4);
+ h->asl_compiler_revision = cpu_to_le32(1);
+ h->checksum -= checksum(h, len);
+}
+
+static void piix4_fadt_setup(struct pci_device *pci, void *arg)
+{
+ struct fadt_descriptor_rev1 *fadt = arg;
+
+ fadt->model = 1;
+ fadt->reserved1 = 0;
+ fadt->sci_int = cpu_to_le16(PIIX_PM_INTRRUPT);
+ fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
+ fadt->acpi_enable = PIIX_ACPI_ENABLE;
+ fadt->acpi_disable = PIIX_ACPI_DISABLE;
+ fadt->pm1a_evt_blk = cpu_to_le32(acpi_pm_base);
+ fadt->pm1a_cnt_blk = cpu_to_le32(acpi_pm_base + 0x04);
+ fadt->pm_tmr_blk = cpu_to_le32(acpi_pm_base + 0x08);
+ fadt->gpe0_blk = cpu_to_le32(PIIX_GPE0_BLK);
+ fadt->pm1_evt_len = 4;
+ fadt->pm1_cnt_len = 2;
+ fadt->pm_tmr_len = 4;
+ fadt->gpe0_blk_len = PIIX_GPE0_BLK_LEN;
+ fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+ fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+ fadt->flags = cpu_to_le32(ACPI_FADT_F_WBINVD |
+ ACPI_FADT_F_PROC_C1 |
+ ACPI_FADT_F_SLP_BUTTON |
+ ACPI_FADT_F_RTC_S4 |
+ ACPI_FADT_F_USE_PLATFORM_CLOCK);
+}
+
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */
+static void ich9_lpc_fadt_setup(struct pci_device *dev, void *arg)
+{
+ struct fadt_descriptor_rev1 *fadt = arg;
+
+ fadt->model = 1;
+ fadt->reserved1 = 0;
+ fadt->sci_int = cpu_to_le16(9);
+ fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
+ fadt->acpi_enable = ICH9_ACPI_ENABLE;
+ fadt->acpi_disable = ICH9_ACPI_DISABLE;
+ fadt->pm1a_evt_blk = cpu_to_le32(acpi_pm_base);
+ fadt->pm1a_cnt_blk = cpu_to_le32(acpi_pm_base + 0x04);
+ fadt->pm_tmr_blk = cpu_to_le32(acpi_pm_base + 0x08);
+ fadt->gpe0_blk = cpu_to_le32(acpi_pm_base + ICH9_PMIO_GPE0_STS);
+ fadt->pm1_evt_len = 4;
+ fadt->pm1_cnt_len = 2;
+ fadt->pm_tmr_len = 4;
+ fadt->gpe0_blk_len = ICH9_PMIO_GPE0_BLK_LEN;
+ fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+ fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+ fadt->flags = cpu_to_le32(ACPI_FADT_F_WBINVD |
+ ACPI_FADT_F_PROC_C1 |
+ ACPI_FADT_F_SLP_BUTTON |
+ ACPI_FADT_F_RTC_S4 |
+ ACPI_FADT_F_USE_PLATFORM_CLOCK);
+}
+
+static const struct pci_device_id fadt_init_tbl[] = {
+ /* PIIX4 Power Management device (for ACPI) */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+ piix4_fadt_setup),
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC,
+ ich9_lpc_fadt_setup),
+ PCI_DEVICE_END
+};
+
+static void fill_dsdt(struct fadt_descriptor_rev1 *fadt, void *dsdt)
+{
+ if (fadt->dsdt) {
+ free((void *)le32_to_cpu(fadt->dsdt));
+ }
+ fadt->dsdt = cpu_to_le32((u32)dsdt);
+ fadt->checksum -= checksum(fadt, sizeof(*fadt));
+ dprintf(1, "ACPI DSDT=%p\n", dsdt);
+}
+
+static void *
+build_fadt(struct pci_device *pci)
+{
+ struct fadt_descriptor_rev1 *fadt = malloc_high(sizeof(*fadt));
+ struct facs_descriptor_rev1 *facs = memalign_high(64, sizeof(*facs));
+
+ if (!fadt || !facs) {
+ warn_noalloc();
+ return NULL;
+ }
+
+ /* FACS */
+ memset(facs, 0, sizeof(*facs));
+ facs->signature = cpu_to_le32(FACS_SIGNATURE);
+ facs->length = cpu_to_le32(sizeof(*facs));
+
+ /* FADT */
+ memset(fadt, 0, sizeof(*fadt));
+ fadt->firmware_ctrl = cpu_to_le32((u32)facs);
+ fadt->dsdt = 0; /* dsdt will be filled later in acpi_setup()
+ by fill_dsdt() */
+ pci_init_device(fadt_init_tbl, pci, fadt);
+
+ build_header((void*)fadt, FACP_SIGNATURE, sizeof(*fadt), 1);
+
+ return fadt;
+}
+
+static void*
+build_madt(void)
+{
+ int madt_size = (sizeof(struct multiple_apic_table)
+ + sizeof(struct madt_processor_apic) * MaxCountCPUs
+ + sizeof(struct madt_io_apic)
+ + sizeof(struct madt_intsrcovr) * 16
+ + sizeof(struct madt_local_nmi));
+
+ struct multiple_apic_table *madt = malloc_high(madt_size);
+ if (!madt) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(madt, 0, madt_size);
+ madt->local_apic_address = cpu_to_le32(BUILD_APIC_ADDR);
+ madt->flags = cpu_to_le32(1);
+ struct madt_processor_apic *apic = (void*)&madt[1];
+ int i;
+ for (i=0; i<MaxCountCPUs; i++) {
+ apic->type = APIC_PROCESSOR;
+ apic->length = sizeof(*apic);
+ apic->processor_id = i;
+ apic->local_apic_id = i;
+ if (apic_id_is_present(apic->local_apic_id))
+ apic->flags = cpu_to_le32(1);
+ else
+ apic->flags = cpu_to_le32(0);
+ apic++;
+ }
+ struct madt_io_apic *io_apic = (void*)apic;
+ io_apic->type = APIC_IO;
+ io_apic->length = sizeof(*io_apic);
+ io_apic->io_apic_id = BUILD_IOAPIC_ID;
+ io_apic->address = cpu_to_le32(BUILD_IOAPIC_ADDR);
+ io_apic->interrupt = cpu_to_le32(0);
+
+ struct madt_intsrcovr *intsrcovr = (void*)&io_apic[1];
+ if (romfile_loadint("etc/irq0-override", 0)) {
+ memset(intsrcovr, 0, sizeof(*intsrcovr));
+ intsrcovr->type = APIC_XRUPT_OVERRIDE;
+ intsrcovr->length = sizeof(*intsrcovr);
+ intsrcovr->source = 0;
+ intsrcovr->gsi = cpu_to_le32(2);
+ intsrcovr->flags = cpu_to_le16(0); /* conforms to bus specifications */
+ intsrcovr++;
+ }
+ for (i = 1; i < 16; i++) {
+ if (!(BUILD_PCI_IRQS & (1 << i)))
+ /* No need for a INT source override structure. */
+ continue;
+ memset(intsrcovr, 0, sizeof(*intsrcovr));
+ intsrcovr->type = APIC_XRUPT_OVERRIDE;
+ intsrcovr->length = sizeof(*intsrcovr);
+ intsrcovr->source = i;
+ intsrcovr->gsi = cpu_to_le32(i);
+ intsrcovr->flags = cpu_to_le16(0xd); /* active high, level triggered */
+ intsrcovr++;
+ }
+
+ struct madt_local_nmi *local_nmi = (void*)intsrcovr;
+ local_nmi->type = APIC_LOCAL_NMI;
+ local_nmi->length = sizeof(*local_nmi);
+ local_nmi->processor_id = 0xff; /* all processors */
+ local_nmi->flags = cpu_to_le16(0);
+ local_nmi->lint = 1; /* LINT1 */
+ local_nmi++;
+
+ build_header((void*)madt, APIC_SIGNATURE, (void*)local_nmi - (void*)madt, 1);
+ return madt;
+}
+
+// Encode a hex value
+static inline char getHex(u32 val) {
+ val &= 0x0f;
+ return (val <= 9) ? ('0' + val) : ('A' + val - 10);
+}
+
+// Encode a length in an SSDT.
+static u8 *
+encodeLen(u8 *ssdt_ptr, int length, int bytes)
+{
+ switch (bytes) {
+ default:
+ case 4: ssdt_ptr[3] = ((length >> 20) & 0xff);
+ case 3: ssdt_ptr[2] = ((length >> 12) & 0xff);
+ case 2: ssdt_ptr[1] = ((length >> 4) & 0xff);
+ ssdt_ptr[0] = (((bytes-1) & 0x3) << 6) | (length & 0x0f);
+ break;
+ case 1: ssdt_ptr[0] = length & 0x3f;
+ }
+ return ssdt_ptr + bytes;
+}
+
+#include "src/fw/ssdt-proc.hex"
+
+/* 0x5B 0x83 ProcessorOp PkgLength NameString ProcID */
+#define PROC_OFFSET_CPUHEX (*ssdt_proc_name - *ssdt_proc_start + 2)
+#define PROC_OFFSET_CPUID1 (*ssdt_proc_name - *ssdt_proc_start + 4)
+#define PROC_OFFSET_CPUID2 (*ssdt_proc_id - *ssdt_proc_start)
+#define PROC_SIZEOF (*ssdt_proc_end - *ssdt_proc_start)
+#define PROC_AML (ssdp_proc_aml + *ssdt_proc_start)
+
+/* 0x5B 0x82 DeviceOp PkgLength NameString */
+#define PCIHP_OFFSET_HEX (*ssdt_pcihp_name - *ssdt_pcihp_start + 1)
+#define PCIHP_OFFSET_ID (*ssdt_pcihp_id - *ssdt_pcihp_start)
+#define PCIHP_OFFSET_ADR (*ssdt_pcihp_adr - *ssdt_pcihp_start)
+#define PCIHP_OFFSET_EJ0 (*ssdt_pcihp_ej0 - *ssdt_pcihp_start)
+#define PCIHP_SIZEOF (*ssdt_pcihp_end - *ssdt_pcihp_start)
+#define PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start)
+#define PCI_SLOTS 32
+
+#define SSDT_SIGNATURE 0x54445353 // SSDT
+#define SSDT_HEADER_LENGTH 36
+
+#include "src/fw/ssdt-misc.hex"
+#include "src/fw/ssdt-pcihp.hex"
+
+#define PCI_RMV_BASE 0xae0c
+
+static u8*
+build_notify(u8 *ssdt_ptr, const char *name, int skip, int count,
+ const char *target, int ofs)
+{
+ count -= skip;
+
+ *(ssdt_ptr++) = 0x14; // MethodOp
+ ssdt_ptr = encodeLen(ssdt_ptr, 2+5+(12*count), 2);
+ memcpy(ssdt_ptr, name, 4);
+ ssdt_ptr += 4;
+ *(ssdt_ptr++) = 0x02; // MethodOp
+
+ int i;
+ for (i = skip; count-- > 0; i++) {
+ *(ssdt_ptr++) = 0xA0; // IfOp
+ ssdt_ptr = encodeLen(ssdt_ptr, 11, 1);
+ *(ssdt_ptr++) = 0x93; // LEqualOp
+ *(ssdt_ptr++) = 0x68; // Arg0Op
+ *(ssdt_ptr++) = 0x0A; // BytePrefix
+ *(ssdt_ptr++) = i;
+ *(ssdt_ptr++) = 0x86; // NotifyOp
+ memcpy(ssdt_ptr, target, 4);
+ ssdt_ptr[ofs] = getHex(i >> 4);
+ ssdt_ptr[ofs + 1] = getHex(i);
+ ssdt_ptr += 4;
+ *(ssdt_ptr++) = 0x69; // Arg1Op
+ }
+ return ssdt_ptr;
+}
+
+static void patch_pcihp(int slot, u8 *ssdt_ptr, u32 eject)
+{
+ ssdt_ptr[PCIHP_OFFSET_HEX] = getHex(slot >> 4);
+ ssdt_ptr[PCIHP_OFFSET_HEX+1] = getHex(slot);
+ ssdt_ptr[PCIHP_OFFSET_ID] = slot;
+ ssdt_ptr[PCIHP_OFFSET_ADR + 2] = slot;
+
+ /* Runtime patching of EJ0: to disable hotplug for a slot,
+ * replace the method name: _EJ0 by EJ0_. */
+ /* Sanity check */
+ if (memcmp(ssdt_ptr + PCIHP_OFFSET_EJ0, "_EJ0", 4)) {
+ warn_internalerror();
+ }
+ if (!eject) {
+ memcpy(ssdt_ptr + PCIHP_OFFSET_EJ0, "EJ0_", 4);
+ }
+}
+
+static void*
+build_ssdt(void)
+{
+ int acpi_cpus = MaxCountCPUs > 0xff ? 0xff : MaxCountCPUs;
+ int length = (sizeof(ssdp_misc_aml) // _S3_ / _S4_ / _S5_
+ + (1+3+4) // Scope(_SB_)
+ + (acpi_cpus * PROC_SIZEOF) // procs
+ + (1+2+5+(12*acpi_cpus)) // NTFY
+ + (6+2+1+(1*acpi_cpus)) // CPON
+ + (1+3+4) // Scope(PCI0)
+ + ((PCI_SLOTS - 1) * PCIHP_SIZEOF) // slots
+ + (1+2+5+(12*(PCI_SLOTS - 1)))); // PCNT
+ u8 *ssdt = malloc_high(length);
+ if (! ssdt) {
+ warn_noalloc();
+ return NULL;
+ }
+ u8 *ssdt_ptr = ssdt;
+
+ // Copy header and encode fwcfg values in the S3_ / S4_ / S5_ packages
+ int sys_state_size;
+ char *sys_states = romfile_loadfile("etc/system-states", &sys_state_size);
+ if (!sys_states || sys_state_size != 6)
+ sys_states = (char[]){128, 0, 0, 129, 128, 128};
+
+ memcpy(ssdt_ptr, ssdp_misc_aml, sizeof(ssdp_misc_aml));
+ if (!(sys_states[3] & 128))
+ ssdt_ptr[acpi_s3_name[0]] = 'X';
+ if (!(sys_states[4] & 128))
+ ssdt_ptr[acpi_s4_name[0]] = 'X';
+ else
+ ssdt_ptr[acpi_s4_pkg[0] + 1] = ssdt[acpi_s4_pkg[0] + 3] = sys_states[4] & 127;
+
+ // store pci io windows
+ *(u32*)&ssdt_ptr[acpi_pci32_start[0]] = cpu_to_le32(pcimem_start);
+ *(u32*)&ssdt_ptr[acpi_pci32_end[0]] = cpu_to_le32(pcimem_end - 1);
+ if (pcimem64_start) {
+ ssdt_ptr[acpi_pci64_valid[0]] = 1;
+ *(u64*)&ssdt_ptr[acpi_pci64_start[0]] = cpu_to_le64(pcimem64_start);
+ *(u64*)&ssdt_ptr[acpi_pci64_end[0]] = cpu_to_le64(pcimem64_end - 1);
+ *(u64*)&ssdt_ptr[acpi_pci64_length[0]] = cpu_to_le64(
+ pcimem64_end - pcimem64_start);
+ } else {
+ ssdt_ptr[acpi_pci64_valid[0]] = 0;
+ }
+
+ int pvpanic_port = romfile_loadint("etc/pvpanic-port", 0x0);
+ *(u16 *)(ssdt_ptr + *ssdt_isa_pest) = pvpanic_port;
+
+ ssdt_ptr += sizeof(ssdp_misc_aml);
+
+ // build Scope(_SB_) header
+ *(ssdt_ptr++) = 0x10; // ScopeOp
+ ssdt_ptr = encodeLen(ssdt_ptr, length - (ssdt_ptr - ssdt), 3);
+ *(ssdt_ptr++) = '_';
+ *(ssdt_ptr++) = 'S';
+ *(ssdt_ptr++) = 'B';
+ *(ssdt_ptr++) = '_';
+
+ // build Processor object for each processor
+ int i;
+ for (i=0; i<acpi_cpus; i++) {
+ memcpy(ssdt_ptr, PROC_AML, PROC_SIZEOF);
+ ssdt_ptr[PROC_OFFSET_CPUHEX] = getHex(i >> 4);
+ ssdt_ptr[PROC_OFFSET_CPUHEX+1] = getHex(i);
+ ssdt_ptr[PROC_OFFSET_CPUID1] = i;
+ ssdt_ptr[PROC_OFFSET_CPUID2] = i;
+ ssdt_ptr += PROC_SIZEOF;
+ }
+
+ // build "Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...}"
+ // Arg0 = Processor ID = APIC ID
+ ssdt_ptr = build_notify(ssdt_ptr, "NTFY", 0, acpi_cpus, "CP00", 2);
+
+ // build "Name(CPON, Package() { One, One, ..., Zero, Zero, ... })"
+ *(ssdt_ptr++) = 0x08; // NameOp
+ *(ssdt_ptr++) = 'C';
+ *(ssdt_ptr++) = 'P';
+ *(ssdt_ptr++) = 'O';
+ *(ssdt_ptr++) = 'N';
+ *(ssdt_ptr++) = 0x12; // PackageOp
+ ssdt_ptr = encodeLen(ssdt_ptr, 2+1+(1*acpi_cpus), 2);
+ *(ssdt_ptr++) = acpi_cpus;
+ for (i=0; i<acpi_cpus; i++)
+ *(ssdt_ptr++) = (apic_id_is_present(i)) ? 0x01 : 0x00;
+
+ // build Scope(PCI0) opcode
+ *(ssdt_ptr++) = 0x10; // ScopeOp
+ ssdt_ptr = encodeLen(ssdt_ptr, length - (ssdt_ptr - ssdt), 3);
+ *(ssdt_ptr++) = 'P';
+ *(ssdt_ptr++) = 'C';
+ *(ssdt_ptr++) = 'I';
+ *(ssdt_ptr++) = '0';
+
+ // build Device object for each slot
+ u32 rmvc_pcrm = inl(PCI_RMV_BASE);
+ for (i=1; i<PCI_SLOTS; i++) {
+ u32 eject = rmvc_pcrm & (0x1 << i);
+ memcpy(ssdt_ptr, PCIHP_AML, PCIHP_SIZEOF);
+ patch_pcihp(i, ssdt_ptr, eject != 0);
+ ssdt_ptr += PCIHP_SIZEOF;
+ }
+
+ ssdt_ptr = build_notify(ssdt_ptr, "PCNT", 1, PCI_SLOTS, "S00_", 1);
+
+ build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
+
+ //hexdump(ssdt, ssdt_ptr - ssdt);
+
+ return ssdt;
+}
+
+#define HPET_ID 0x000
+#define HPET_PERIOD 0x004
+
+static void*
+build_hpet(void)
+{
+ struct acpi_20_hpet *hpet;
+ const void *hpet_base = (void *)BUILD_HPET_ADDRESS;
+ u32 hpet_vendor = readl(hpet_base + HPET_ID) >> 16;
+ u32 hpet_period = readl(hpet_base + HPET_PERIOD);
+
+ if (hpet_vendor == 0 || hpet_vendor == 0xffff ||
+ hpet_period == 0 || hpet_period > 100000000)
+ return NULL;
+
+ hpet = malloc_high(sizeof(*hpet));
+ if (!hpet) {
+ warn_noalloc();
+ return NULL;
+ }
+
+ memset(hpet, 0, sizeof(*hpet));
+ /* Note timer_block_id value must be kept in sync with value advertised by
+ * emulated hpet
+ */
+ hpet->timer_block_id = cpu_to_le32(0x8086a201);
+ hpet->addr.address = cpu_to_le64(BUILD_HPET_ADDRESS);
+ build_header((void*)hpet, HPET_SIGNATURE, sizeof(*hpet), 1);
+
+ return hpet;
+}
+
+static void
+acpi_build_srat_memory(struct srat_memory_affinity *numamem,
+ u64 base, u64 len, int node, int enabled)
+{
+ numamem->type = SRAT_MEMORY;
+ numamem->length = sizeof(*numamem);
+ memset(numamem->proximity, 0, 4);
+ numamem->proximity[0] = node;
+ numamem->flags = cpu_to_le32(!!enabled);
+ numamem->base_addr = cpu_to_le64(base);
+ numamem->range_length = cpu_to_le64(len);
+}
+
+static void *
+build_srat(void)
+{
+ int numadatasize, numacpusize;
+ u64 *numadata = romfile_loadfile("etc/numa-nodes", &numadatasize);
+ u64 *numacpumap = romfile_loadfile("etc/numa-cpu-map", &numacpusize);
+ if (!numadata || !numacpumap)
+ goto fail;
+ int max_cpu = numacpusize / sizeof(u64);
+ int nb_numa_nodes = numadatasize / sizeof(u64);
+
+ struct system_resource_affinity_table *srat;
+ int srat_size = sizeof(*srat) +
+ sizeof(struct srat_processor_affinity) * max_cpu +
+ sizeof(struct srat_memory_affinity) * (nb_numa_nodes + 2);
+
+ srat = malloc_high(srat_size);
+ if (!srat) {
+ warn_noalloc();
+ goto fail;
+ }
+
+ memset(srat, 0, srat_size);
+ srat->reserved1=cpu_to_le32(1);
+ struct srat_processor_affinity *core = (void*)(srat + 1);
+ int i;
+ u64 curnode;
+
+ for (i = 0; i < max_cpu; ++i) {
+ core->type = SRAT_PROCESSOR;
+ core->length = sizeof(*core);
+ core->local_apic_id = i;
+ curnode = *numacpumap++;
+ core->proximity_lo = curnode;
+ memset(core->proximity_hi, 0, 3);
+ core->local_sapic_eid = 0;
+ if (apic_id_is_present(i))
+ core->flags = cpu_to_le32(1);
+ else
+ core->flags = cpu_to_le32(0);
+ core++;
+ }
+
+
+ /* the memory map is a bit tricky, it contains at least one hole
+ * from 640k-1M and possibly another one from 3.5G-4G.
+ */
+ struct srat_memory_affinity *numamem = (void*)core;
+ int slots = 0;
+ u64 mem_len, mem_base, next_base = 0;
+
+ acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1);
+ next_base = 1024 * 1024;
+ numamem++;
+ slots++;
+ for (i = 1; i < nb_numa_nodes + 1; ++i) {
+ mem_base = next_base;
+ mem_len = *numadata++;
+ if (i == 1)
+ mem_len -= 1024 * 1024;
+ next_base = mem_base + mem_len;
+
+ /* Cut out the PCI hole */
+ if (mem_base <= RamSize && next_base > RamSize) {
+ mem_len -= next_base - RamSize;
+ if (mem_len > 0) {
+ acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+ numamem++;
+ slots++;
+ }
+ mem_base = 1ULL << 32;
+ mem_len = next_base - RamSize;
+ next_base += (1ULL << 32) - RamSize;
+ }
+ acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+ numamem++;
+ slots++;
+ }
+ for (; slots < nb_numa_nodes + 2; slots++) {
+ acpi_build_srat_memory(numamem, 0, 0, 0, 0);
+ numamem++;
+ }
+
+ build_header((void*)srat, SRAT_SIGNATURE, srat_size, 1);
+
+ free(numadata);
+ free(numacpumap);
+ return srat;
+fail:
+ free(numadata);
+ free(numacpumap);
+ return NULL;
+}
+
+static void *
+build_mcfg_q35(void)
+{
+ struct acpi_table_mcfg *mcfg;
+
+ int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]);
+ mcfg = malloc_high(len);
+ if (!mcfg) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(mcfg, 0, len);
+ mcfg->allocation[0].address = cpu_to_le64(Q35_HOST_BRIDGE_PCIEXBAR_ADDR);
+ mcfg->allocation[0].pci_segment = cpu_to_le16(Q35_HOST_PCIE_PCI_SEGMENT);
+ mcfg->allocation[0].start_bus_number = Q35_HOST_PCIE_START_BUS_NUMBER;
+ mcfg->allocation[0].end_bus_number = Q35_HOST_PCIE_END_BUS_NUMBER;
+
+ build_header((void *)mcfg, MCFG_SIGNATURE, len, 1);
+ return mcfg;
+}
+
+static const struct pci_device_id acpi_find_tbl[] = {
+ /* PIIX4 Power Management device. */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL),
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC, NULL),
+ PCI_DEVICE_END,
+};
+
+#define MAX_ACPI_TABLES 20
+void
+acpi_setup(void)
+{
+ if (! CONFIG_ACPI)
+ return;
+
+ dprintf(3, "init ACPI tables\n");
+
+ // This code is hardcoded for PIIX4 Power Management device.
+ struct pci_device *pci = pci_find_init_device(acpi_find_tbl, NULL);
+ if (!pci)
+ // Device not found
+ return;
+
+ // Build ACPI tables
+ u32 tables[MAX_ACPI_TABLES], tbl_idx = 0;
+
+#define ACPI_INIT_TABLE(X) \
+ do { \
+ tables[tbl_idx] = cpu_to_le32((u32)(X)); \
+ if (le32_to_cpu(tables[tbl_idx])) \
+ tbl_idx++; \
+ } while(0)
+
+ struct fadt_descriptor_rev1 *fadt = build_fadt(pci);
+ ACPI_INIT_TABLE(fadt);
+ ACPI_INIT_TABLE(build_ssdt());
+ ACPI_INIT_TABLE(build_madt());
+ ACPI_INIT_TABLE(build_hpet());
+ ACPI_INIT_TABLE(build_srat());
+ if (pci->device == PCI_DEVICE_ID_INTEL_ICH9_LPC)
+ ACPI_INIT_TABLE(build_mcfg_q35());
+
+ struct romfile_s *file = NULL;
+ for (;;) {
+ file = romfile_findprefix("acpi/", file);
+ if (!file)
+ break;
+ struct acpi_table_header *table = malloc_high(file->size);
+ if (!table) {
+ warn_noalloc();
+ continue;
+ }
+ int ret = file->copy(file, table, file->size);
+ if (ret <= sizeof(*table))
+ continue;
+ if (table->signature == DSDT_SIGNATURE) {
+ if (fadt) {
+ fill_dsdt(fadt, table);
+ }
+ } else {
+ ACPI_INIT_TABLE(table);
+ }
+ if (tbl_idx == MAX_ACPI_TABLES) {
+ warn_noalloc();
+ break;
+ }
+ }
+
+ if (CONFIG_ACPI_DSDT && fadt && !fadt->dsdt) {
+ /* default DSDT */
+ struct acpi_table_header *dsdt = malloc_high(sizeof(AmlCode));
+ if (!dsdt) {
+ warn_noalloc();
+ return;
+ }
+ memcpy(dsdt, AmlCode, sizeof(AmlCode));
+ fill_dsdt(fadt, dsdt);
+ /* Strip out compiler-generated header if any */
+ memset(dsdt, 0, sizeof *dsdt);
+ build_header(dsdt, DSDT_SIGNATURE, sizeof(AmlCode), 1);
+ }
+
+ // Build final rsdt table
+ struct rsdt_descriptor_rev1 *rsdt;
+ size_t rsdt_len = sizeof(*rsdt) + sizeof(u32) * tbl_idx;
+ rsdt = malloc_high(rsdt_len);
+ if (!rsdt) {
+ warn_noalloc();
+ return;
+ }
+ memset(rsdt, 0, rsdt_len);
+ memcpy(rsdt->table_offset_entry, tables, sizeof(u32) * tbl_idx);
+ build_header((void*)rsdt, RSDT_SIGNATURE, rsdt_len, 1);
+
+ // Build rsdp pointer table
+ struct rsdp_descriptor rsdp;
+ memset(&rsdp, 0, sizeof(rsdp));
+ rsdp.signature = cpu_to_le64(RSDP_SIGNATURE);
+ memcpy(rsdp.oem_id, BUILD_APPNAME6, 6);
+ rsdp.rsdt_physical_address = cpu_to_le32((u32)rsdt);
+ rsdp.checksum -= checksum(&rsdp, 20);
+ copy_acpi_rsdp(&rsdp);
+}
diff --git a/qemu/roms/seabios/src/fw/biostables.c b/qemu/roms/seabios/src/fw/biostables.c
new file mode 100644
index 000000000..50a891be8
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/biostables.c
@@ -0,0 +1,461 @@
+// Support for manipulating bios tables (pir, mptable, acpi, smbios).
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "byteorder.h" // le32_to_cpu
+#include "config.h" // CONFIG_*
+#include "malloc.h" // malloc_fseg
+#include "output.h" // dprintf
+#include "hw/pci.h" // pci_config_writeb
+#include "std/acpi.h" // struct rsdp_descriptor
+#include "std/mptable.h" // MPTABLE_SIGNATURE
+#include "std/pirtable.h" // struct pir_header
+#include "std/smbios.h" // struct smbios_entry_point
+#include "romfile.h"
+#include "string.h" // memcpy
+#include "util.h" // copy_table
+#include "x86.h" // outb
+
+struct pir_header *PirAddr VARFSEG;
+
+void
+copy_pir(void *pos)
+{
+ struct pir_header *p = pos;
+ if (p->signature != PIR_SIGNATURE)
+ return;
+ if (PirAddr)
+ return;
+ if (p->size < sizeof(*p))
+ return;
+ if (checksum(pos, p->size) != 0)
+ return;
+ void *newpos = malloc_fseg(p->size);
+ if (!newpos) {
+ warn_noalloc();
+ return;
+ }
+ dprintf(1, "Copying PIR from %p to %p\n", pos, newpos);
+ memcpy(newpos, pos, p->size);
+ PirAddr = newpos;
+}
+
+void
+copy_mptable(void *pos)
+{
+ struct mptable_floating_s *p = pos;
+ if (p->signature != MPTABLE_SIGNATURE)
+ return;
+ if (!p->physaddr)
+ return;
+ if (checksum(pos, sizeof(*p)) != 0)
+ return;
+ u32 length = p->length * 16;
+ u16 mpclength = ((struct mptable_config_s *)p->physaddr)->length;
+ // Allocate final memory location. (In theory the config
+ // structure can go in high memory, but Linux kernels before
+ // v2.6.30 crash with that.)
+ struct mptable_floating_s *newpos = malloc_fseg(length + mpclength);
+ if (!newpos) {
+ warn_noalloc();
+ return;
+ }
+ dprintf(1, "Copying MPTABLE from %p/%x to %p\n", pos, p->physaddr, newpos);
+ memcpy(newpos, pos, length);
+ newpos->physaddr = (u32)newpos + length;
+ newpos->checksum -= checksum(newpos, sizeof(*newpos));
+ memcpy((void*)newpos + length, (void*)p->physaddr, mpclength);
+}
+
+
+/****************************************************************
+ * ACPI
+ ****************************************************************/
+
+static int
+get_acpi_rsdp_length(void *pos, unsigned size)
+{
+ struct rsdp_descriptor *p = pos;
+ if (p->signature != RSDP_SIGNATURE)
+ return -1;
+ u32 length = 20;
+ if (length > size)
+ return -1;
+ if (checksum(pos, length) != 0)
+ return -1;
+ if (p->revision > 1) {
+ length = p->length;
+ if (length > size)
+ return -1;
+ if (checksum(pos, length) != 0)
+ return -1;
+ }
+ return length;
+}
+
+struct rsdp_descriptor *RsdpAddr;
+
+void
+copy_acpi_rsdp(void *pos)
+{
+ if (RsdpAddr)
+ return;
+ int length = get_acpi_rsdp_length(pos, -1);
+ if (length < 0)
+ return;
+ void *newpos = malloc_fseg(length);
+ if (!newpos) {
+ warn_noalloc();
+ return;
+ }
+ dprintf(1, "Copying ACPI RSDP from %p to %p\n", pos, newpos);
+ memcpy(newpos, pos, length);
+ RsdpAddr = newpos;
+}
+
+void *find_acpi_rsdp(void)
+{
+ extern u8 zonefseg_start[], zonefseg_end[];
+ unsigned long start = (unsigned long)zonefseg_start;
+ unsigned long end = (unsigned long)zonefseg_end;
+ unsigned long pos;
+
+ for (pos = ALIGN(start, 0x10); pos <= ALIGN_DOWN(end, 0x10); pos += 0x10)
+ if (get_acpi_rsdp_length((void *)pos, end - pos) >= 0)
+ return (void *)pos;
+
+ return NULL;
+}
+
+static struct fadt_descriptor_rev1 *
+find_fadt(void)
+{
+ dprintf(4, "rsdp=%p\n", RsdpAddr);
+ if (!RsdpAddr || RsdpAddr->signature != RSDP_SIGNATURE)
+ return NULL;
+ struct rsdt_descriptor_rev1 *rsdt = (void*)RsdpAddr->rsdt_physical_address;
+ dprintf(4, "rsdt=%p\n", rsdt);
+ if (!rsdt || rsdt->signature != RSDT_SIGNATURE)
+ return NULL;
+ void *end = (void*)rsdt + rsdt->length;
+ int i;
+ for (i=0; (void*)&rsdt->table_offset_entry[i] < end; i++) {
+ struct fadt_descriptor_rev1 *fadt = (void*)rsdt->table_offset_entry[i];
+ if (!fadt || fadt->signature != FACP_SIGNATURE)
+ continue;
+ dprintf(4, "fadt=%p\n", fadt);
+ return fadt;
+ }
+ dprintf(4, "no fadt found\n");
+ return NULL;
+}
+
+u32
+find_resume_vector(void)
+{
+ struct fadt_descriptor_rev1 *fadt = find_fadt();
+ if (!fadt)
+ return 0;
+ struct facs_descriptor_rev1 *facs = (void*)fadt->firmware_ctrl;
+ dprintf(4, "facs=%p\n", facs);
+ if (! facs || facs->signature != FACS_SIGNATURE)
+ return 0;
+ // Found it.
+ dprintf(4, "resume addr=%d\n", facs->firmware_waking_vector);
+ return facs->firmware_waking_vector;
+}
+
+static struct acpi_20_generic_address acpi_reset_reg;
+static u8 acpi_reset_val;
+u32 acpi_pm1a_cnt VARFSEG;
+u16 acpi_pm_base = 0xb000;
+
+#define acpi_ga_to_bdf(addr) pci_to_bdf(0, (addr >> 32) & 0xffff, (addr >> 16) & 0xffff)
+
+void
+acpi_reboot(void)
+{
+ // Check it passed the sanity checks in acpi_set_reset_reg() and was set
+ if (acpi_reset_reg.register_bit_width != 8)
+ return;
+
+ u64 addr = le64_to_cpu(acpi_reset_reg.address);
+
+ dprintf(1, "ACPI hard reset %d:%llx (%x)\n",
+ acpi_reset_reg.address_space_id, addr, acpi_reset_val);
+
+ switch (acpi_reset_reg.address_space_id) {
+ case 0: // System Memory
+ writeb((void *)(u32)addr, acpi_reset_val);
+ break;
+ case 1: // System I/O
+ outb(acpi_reset_val, addr);
+ break;
+ case 2: // PCI config space
+ pci_config_writeb(acpi_ga_to_bdf(addr), addr & 0xffff, acpi_reset_val);
+ break;
+ }
+}
+
+static void
+acpi_set_reset_reg(struct acpi_20_generic_address *reg, u8 val)
+{
+ if (!reg || reg->address_space_id > 2 ||
+ reg->register_bit_width != 8 || reg->register_bit_offset)
+ return;
+
+ acpi_reset_reg = *reg;
+ acpi_reset_val = val;
+}
+
+void
+find_acpi_features(void)
+{
+ struct fadt_descriptor_rev1 *fadt = find_fadt();
+ if (!fadt)
+ return;
+ u32 pm_tmr = le32_to_cpu(fadt->pm_tmr_blk);
+ u32 pm1a_cnt = le32_to_cpu(fadt->pm1a_cnt_blk);
+ dprintf(4, "pm_tmr_blk=%x\n", pm_tmr);
+ if (pm_tmr)
+ pmtimer_setup(pm_tmr);
+ if (pm1a_cnt)
+ acpi_pm1a_cnt = pm1a_cnt;
+
+ // Theoretically we should check the 'reset_reg_sup' flag, but Windows
+ // doesn't and thus nobody seems to *set* it. If the table is large enough
+ // to include it, let the sanity checks in acpi_set_reset_reg() suffice.
+ if (fadt->length >= 129) {
+ void *p = fadt;
+ acpi_set_reset_reg(p + 116, *(u8 *)(p + 128));
+ }
+}
+
+
+/****************************************************************
+ * SMBIOS
+ ****************************************************************/
+
+// Iterator for each sub-table in the smbios blob.
+void *
+smbios_next(struct smbios_entry_point *smbios, void *prev)
+{
+ if (!smbios)
+ return NULL;
+ void *start = (void*)smbios->structure_table_address;
+ void *end = start + smbios->structure_table_length;
+
+ if (!prev) {
+ prev = start;
+ } else {
+ struct smbios_structure_header *hdr = prev;
+ if (prev + sizeof(*hdr) > end)
+ return NULL;
+ prev += hdr->length + 2;
+ while (prev < end && (*(u8*)(prev-1) != '\0' || *(u8*)(prev-2) != '\0'))
+ prev++;
+ }
+ struct smbios_structure_header *hdr = prev;
+ if (prev >= end || prev + sizeof(*hdr) >= end || prev + hdr->length >= end)
+ return NULL;
+ return prev;
+}
+
+struct smbios_entry_point *SMBiosAddr;
+
+void
+copy_smbios(void *pos)
+{
+ if (SMBiosAddr)
+ return;
+ struct smbios_entry_point *p = pos;
+ if (memcmp(p->anchor_string, "_SM_", 4))
+ return;
+ if (checksum(pos, 0x10) != 0)
+ return;
+ if (memcmp(p->intermediate_anchor_string, "_DMI_", 5))
+ return;
+ if (checksum(pos+0x10, p->length-0x10) != 0)
+ return;
+ struct smbios_entry_point *newpos = malloc_fseg(p->length);
+ if (!newpos) {
+ warn_noalloc();
+ return;
+ }
+ dprintf(1, "Copying SMBIOS entry point from %p to %p\n", pos, newpos);
+ memcpy(newpos, pos, p->length);
+ SMBiosAddr = newpos;
+}
+
+void
+display_uuid(void)
+{
+ struct smbios_type_1 *tbl = smbios_next(SMBiosAddr, NULL);
+ int minlen = offsetof(struct smbios_type_1, uuid) + sizeof(tbl->uuid);
+ for (; tbl; tbl = smbios_next(SMBiosAddr, tbl))
+ if (tbl->header.type == 1 && tbl->header.length >= minlen) {
+ u8 *uuid = tbl->uuid;
+ u8 empty_uuid[sizeof(tbl->uuid)] = { 0 };
+ if (memcmp(uuid, empty_uuid, sizeof(empty_uuid)) == 0)
+ return;
+
+ printf("Machine UUID"
+ " %02x%02x%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x%02x%02x%02x%02x\n"
+ , uuid[ 0], uuid[ 1], uuid[ 2], uuid[ 3]
+ , uuid[ 4], uuid[ 5]
+ , uuid[ 6], uuid[ 7]
+ , uuid[ 8], uuid[ 9]
+ , uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
+ return;
+ }
+}
+
+#define set_str_field_or_skip(type, field, value) \
+ do { \
+ int size = (value != NULL) ? strlen(value) + 1 : 0; \
+ if (size > 1) { \
+ memcpy(end, value, size); \
+ end += size; \
+ p->field = ++str_index; \
+ } else { \
+ p->field = 0; \
+ } \
+ } while (0)
+
+static void *
+smbios_new_type_0(void *start,
+ const char *vendor, const char *version, const char *date)
+{
+ struct smbios_type_0 *p = (struct smbios_type_0 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_0);
+ int str_index = 0;
+
+ p->header.type = 0;
+ p->header.length = sizeof(struct smbios_type_0);
+ p->header.handle = 0;
+
+ set_str_field_or_skip(0, vendor_str, vendor);
+ set_str_field_or_skip(0, bios_version_str, version);
+ p->bios_starting_address_segment = 0xe800;
+ set_str_field_or_skip(0, bios_release_date_str, date);
+
+ p->bios_rom_size = 0; /* FIXME */
+
+ /* BIOS characteristics not supported */
+ memset(p->bios_characteristics, 0, 8);
+ p->bios_characteristics[0] = 0x08;
+
+ /* Enable targeted content distribution (needed for SVVP) */
+ p->bios_characteristics_extension_bytes[0] = 0;
+ p->bios_characteristics_extension_bytes[1] = 4;
+
+ p->system_bios_major_release = 0;
+ p->system_bios_minor_release = 0;
+ p->embedded_controller_major_release = 0xFF;
+ p->embedded_controller_minor_release = 0xFF;
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+#define BIOS_NAME "SeaBIOS"
+#define BIOS_DATE "04/01/2014"
+
+static int
+smbios_romfile_setup(void)
+{
+ struct romfile_s *f_anchor = romfile_find("etc/smbios/smbios-anchor");
+ struct romfile_s *f_tables = romfile_find("etc/smbios/smbios-tables");
+ struct smbios_entry_point ep;
+ struct smbios_type_0 *t0;
+ u16 qtables_len, need_t0 = 1;
+ u8 *qtables, *tables;
+
+ if (!f_anchor || !f_tables || f_anchor->size != sizeof(ep))
+ return 0;
+
+ f_anchor->copy(f_anchor, &ep, f_anchor->size);
+
+ if (f_tables->size != ep.structure_table_length)
+ return 0;
+
+ qtables = malloc_tmphigh(f_tables->size);
+ if (!qtables) {
+ warn_noalloc();
+ return 0;
+ }
+ f_tables->copy(f_tables, qtables, f_tables->size);
+ ep.structure_table_address = (u32)qtables; /* for smbios_next(), below */
+
+ /* did we get a type 0 structure ? */
+ for (t0 = smbios_next(&ep, NULL); t0; t0 = smbios_next(&ep, t0))
+ if (t0->header.type == 0) {
+ need_t0 = 0;
+ break;
+ }
+
+ qtables_len = ep.structure_table_length;
+ if (need_t0) {
+ /* common case: add our own type 0, with 3 strings and 4 '\0's */
+ u16 t0_len = sizeof(struct smbios_type_0) + strlen(BIOS_NAME) +
+ strlen(VERSION) + strlen(BIOS_DATE) + 4;
+ ep.structure_table_length += t0_len;
+ if (t0_len > ep.max_structure_size)
+ ep.max_structure_size = t0_len;
+ ep.number_of_structures++;
+ }
+
+ /* allocate final blob and record its address in the entry point */
+ if (ep.structure_table_length > BUILD_MAX_SMBIOS_FSEG)
+ tables = malloc_high(ep.structure_table_length);
+ else
+ tables = malloc_fseg(ep.structure_table_length);
+ if (!tables) {
+ warn_noalloc();
+ free(qtables);
+ return 0;
+ }
+ ep.structure_table_address = (u32)tables;
+
+ /* populate final blob */
+ if (need_t0)
+ tables = smbios_new_type_0(tables, BIOS_NAME, VERSION, BIOS_DATE);
+ memcpy(tables, qtables, qtables_len);
+ free(qtables);
+
+ /* finalize entry point */
+ ep.checksum -= checksum(&ep, 0x10);
+ ep.intermediate_checksum -= checksum((void *)&ep + 0x10, ep.length - 0x10);
+
+ copy_smbios(&ep);
+ return 1;
+}
+
+void
+smbios_setup(void)
+{
+ if (smbios_romfile_setup())
+ return;
+ smbios_legacy_setup();
+}
+
+void
+copy_table(void *pos)
+{
+ copy_pir(pos);
+ copy_mptable(pos);
+ copy_acpi_rsdp(pos);
+ copy_smbios(pos);
+}
diff --git a/qemu/roms/seabios/src/fw/coreboot.c b/qemu/roms/seabios/src/fw/coreboot.c
new file mode 100644
index 000000000..8fd84493b
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/coreboot.c
@@ -0,0 +1,553 @@
+// Coreboot interface support.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "block.h" // MAXDESCSIZE
+#include "byteorder.h" // be32_to_cpu
+#include "config.h" // CONFIG_*
+#include "hw/pci.h" // pci_probe_devices
+#include "lzmadecode.h" // LzmaDecode
+#include "malloc.h" // free
+#include "memmap.h" // add_e820
+#include "output.h" // dprintf
+#include "paravirt.h" // PlatformRunningOn
+#include "romfile.h" // romfile_findprefix
+#include "stacks.h" // yield
+#include "string.h" // memset
+#include "util.h" // coreboot_preinit
+
+
+/****************************************************************
+ * Memory map
+ ****************************************************************/
+
+struct cb_header {
+ u32 signature;
+ u32 header_bytes;
+ u32 header_checksum;
+ u32 table_bytes;
+ u32 table_checksum;
+ u32 table_entries;
+};
+
+#define CB_SIGNATURE 0x4f49424C // "LBIO"
+
+struct cb_memory_range {
+ u64 start;
+ u64 size;
+ u32 type;
+};
+
+#define CB_MEM_TABLE 16
+
+struct cb_memory {
+ u32 tag;
+ u32 size;
+ struct cb_memory_range map[0];
+};
+
+#define CB_TAG_MEMORY 0x01
+
+#define MEM_RANGE_COUNT(_rec) \
+ (((_rec)->size - sizeof(*(_rec))) / sizeof((_rec)->map[0]))
+
+struct cb_mainboard {
+ u32 tag;
+ u32 size;
+ u8 vendor_idx;
+ u8 part_idx;
+ char strings[0];
+};
+
+#define CB_TAG_MAINBOARD 0x0003
+
+struct cb_forward {
+ u32 tag;
+ u32 size;
+ u64 forward;
+};
+
+#define CB_TAG_FORWARD 0x11
+
+struct cb_cbmem_ref {
+ u32 tag;
+ u32 size;
+ u64 cbmem_addr;
+};
+
+#define CB_TAG_CBMEM_CONSOLE 0x17
+
+struct cbmem_console {
+ u32 buffer_size;
+ u32 buffer_cursor;
+ u8 buffer_body[0];
+} PACKED;
+static struct cbmem_console *cbcon = NULL;
+
+static u16
+ipchksum(char *buf, int count)
+{
+ u16 *p = (u16*)buf;
+ u32 sum = 0;
+ while (count > 1) {
+ sum += GET_FARVAR(0, *p);
+ p++;
+ count -= 2;
+ }
+ if (count)
+ sum += GET_FARVAR(0, *(u8*)p);
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+ return ~sum;
+}
+
+// Try to locate the coreboot header in a given address range.
+static struct cb_header *
+find_cb_header(u32 addr, int len)
+{
+ u32 end = addr + len;
+ for (; addr < end; addr += 16) {
+ struct cb_header *cbh = (void*)addr;
+ if (GET_FARVAR(0, cbh->signature) != CB_SIGNATURE)
+ continue;
+ u32 tsize = GET_FARVAR(0, cbh->table_bytes);
+ if (! tsize)
+ continue;
+ if (ipchksum((void*)addr, sizeof(*cbh)) != 0)
+ continue;
+ if (ipchksum((void*)addr + sizeof(*cbh), tsize)
+ != GET_FARVAR(0, cbh->table_checksum))
+ continue;
+ return cbh;
+ }
+ return NULL;
+}
+
+// Try to find the coreboot memory table in the given coreboot table.
+void *
+find_cb_subtable(struct cb_header *cbh, u32 tag)
+{
+ char *tbl = (char *)cbh + sizeof(*cbh);
+ u32 count = GET_FARVAR(0, cbh->table_entries);
+ int i;
+ for (i=0; i<count; i++) {
+ struct cb_memory *cbm = (void*)tbl;
+ tbl += GET_FARVAR(0, cbm->size);
+ if (GET_FARVAR(0, cbm->tag) == tag)
+ return cbm;
+ }
+ return NULL;
+}
+
+struct cb_header *
+find_cb_table(void)
+{
+ struct cb_header *cbh = find_cb_header(0, 0x1000);
+ if (!cbh)
+ return NULL;
+ struct cb_forward *cbf = find_cb_subtable(cbh, CB_TAG_FORWARD);
+ if (cbf) {
+ dprintf(3, "Found coreboot table forwarder.\n");
+ cbh = find_cb_header(GET_FARVAR(0, cbf->forward), 0x100);
+ if (!cbh)
+ return NULL;
+ }
+ return cbh;
+}
+
+static struct cb_memory *CBMemTable;
+const char *CBvendor = "", *CBpart = "";
+
+// Populate max ram and e820 map info by scanning for a coreboot table.
+void
+coreboot_preinit(void)
+{
+ if (!CONFIG_COREBOOT)
+ return;
+
+ dprintf(3, "Attempting to find coreboot table\n");
+
+ // Find coreboot table.
+ struct cb_header *cbh = find_cb_table();
+ if (!cbh)
+ goto fail;
+ dprintf(3, "Now attempting to find coreboot memory map\n");
+ struct cb_memory *cbm = CBMemTable = find_cb_subtable(cbh, CB_TAG_MEMORY);
+ if (!cbm)
+ goto fail;
+
+ int i, count = MEM_RANGE_COUNT(cbm);
+ for (i=0; i<count; i++) {
+ struct cb_memory_range *m = &cbm->map[i];
+ u32 type = m->type;
+ if (type == CB_MEM_TABLE)
+ type = E820_RESERVED;
+ add_e820(m->start, m->size, type);
+ }
+
+ // Ughh - coreboot likes to set a map at 0x0000-0x1000, but this
+ // confuses grub. So, override it.
+ add_e820(0, 16*1024, E820_RAM);
+
+ struct cb_cbmem_ref *cbref = find_cb_subtable(cbh, CB_TAG_CBMEM_CONSOLE);
+ if (cbref) {
+ cbcon = (void*)(u32)cbref->cbmem_addr;
+ debug_banner();
+ dprintf(1, "Found coreboot cbmem console @ %llx\n", cbref->cbmem_addr);
+ }
+
+ struct cb_mainboard *cbmb = find_cb_subtable(cbh, CB_TAG_MAINBOARD);
+ if (cbmb) {
+ CBvendor = &cbmb->strings[cbmb->vendor_idx];
+ CBpart = &cbmb->strings[cbmb->part_idx];
+ dprintf(1, "Found mainboard %s %s\n", CBvendor, CBpart);
+ }
+
+ return;
+
+fail:
+ // No table found.. Use 16Megs as a dummy value.
+ dprintf(1, "Unable to find coreboot table!\n");
+ add_e820(0, 16*1024*1024, E820_RAM);
+ return;
+}
+
+void coreboot_debug_putc(char c)
+{
+ if (!CONFIG_DEBUG_COREBOOT)
+ return;
+ if (!cbcon)
+ return;
+ u32 cursor = cbcon->buffer_cursor++;
+ if (cursor < cbcon->buffer_size)
+ cbcon->buffer_body[cursor] = c;
+}
+
+/****************************************************************
+ * BIOS table copying
+ ****************************************************************/
+
+// Attempt to find (and relocate) any standard bios tables found in a
+// given address range.
+static void
+scan_tables(u32 start, u32 size)
+{
+ void *p = (void*)ALIGN(start, 16);
+ void *end = (void*)start + size;
+ for (; p<end; p += 16)
+ copy_table(p);
+}
+
+void
+coreboot_platform_setup(void)
+{
+ if (!CONFIG_COREBOOT)
+ return;
+ pci_probe_devices();
+
+ struct cb_memory *cbm = CBMemTable;
+ if (!cbm)
+ return;
+
+ dprintf(3, "Relocating coreboot bios tables\n");
+
+ // Scan CB_MEM_TABLE areas for bios tables.
+ int i, count = MEM_RANGE_COUNT(cbm);
+ for (i=0; i<count; i++) {
+ struct cb_memory_range *m = &cbm->map[i];
+ if (m->type == CB_MEM_TABLE)
+ scan_tables(m->start, m->size);
+ }
+
+ find_acpi_features();
+}
+
+
+/****************************************************************
+ * ulzma
+ ****************************************************************/
+
+// Uncompress data in flash to an area of memory.
+static int
+ulzma(u8 *dst, u32 maxlen, const u8 *src, u32 srclen)
+{
+ dprintf(3, "Uncompressing data %d@%p to %d@%p\n", srclen, src, maxlen, dst);
+ CLzmaDecoderState state;
+ int ret = LzmaDecodeProperties(&state.Properties, src, LZMA_PROPERTIES_SIZE);
+ if (ret != LZMA_RESULT_OK) {
+ dprintf(1, "LzmaDecodeProperties error - %d\n", ret);
+ return -1;
+ }
+ u8 scratch[15980];
+ int need = (LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+ if (need > sizeof(scratch)) {
+ dprintf(1, "LzmaDecode need %d have %d\n", need, (unsigned int)sizeof(scratch));
+ return -1;
+ }
+ state.Probs = (CProb *)scratch;
+
+ u32 dstlen = *(u32*)(src + LZMA_PROPERTIES_SIZE);
+ if (dstlen > maxlen) {
+ dprintf(1, "LzmaDecode too large (max %d need %d)\n", maxlen, dstlen);
+ return -1;
+ }
+ u32 inProcessed, outProcessed;
+ ret = LzmaDecode(&state, src + LZMA_PROPERTIES_SIZE + 8, srclen
+ , &inProcessed, dst, dstlen, &outProcessed);
+ if (ret) {
+ dprintf(1, "LzmaDecode returned %d\n", ret);
+ return -1;
+ }
+ return dstlen;
+}
+
+
+/****************************************************************
+ * Coreboot flash format
+ ****************************************************************/
+
+#define CBFS_HEADER_MAGIC 0x4F524243
+#define CBFS_VERSION1 0x31313131
+
+struct cbfs_header {
+ u32 magic;
+ u32 version;
+ u32 romsize;
+ u32 bootblocksize;
+ u32 align;
+ u32 offset;
+ u32 pad[2];
+} PACKED;
+
+#define CBFS_FILE_MAGIC 0x455649484352414cLL // LARCHIVE
+
+struct cbfs_file {
+ u64 magic;
+ u32 len;
+ u32 type;
+ u32 checksum;
+ u32 offset;
+ char filename[0];
+} PACKED;
+
+struct cbfs_romfile_s {
+ struct romfile_s file;
+ struct cbfs_file *fhdr;
+ void *data;
+ u32 rawsize, flags;
+};
+
+// Copy a file to memory (uncompressing if necessary)
+static int
+cbfs_copyfile(struct romfile_s *file, void *dst, u32 maxlen)
+{
+ if (!CONFIG_COREBOOT_FLASH)
+ return -1;
+
+ struct cbfs_romfile_s *cfile;
+ cfile = container_of(file, struct cbfs_romfile_s, file);
+ u32 size = cfile->rawsize;
+ void *src = cfile->data;
+ if (cfile->flags) {
+ // Compressed - copy to temp ram and uncompress it.
+ void *temp = malloc_tmphigh(size);
+ if (!temp) {
+ warn_noalloc();
+ return -1;
+ }
+ iomemcpy(temp, src, size);
+ int ret = ulzma(dst, maxlen, temp, size);
+ yield();
+ free(temp);
+ return ret;
+ }
+
+ // Not compressed.
+ dprintf(3, "Copying data %d@%p to %d@%p\n", size, src, maxlen, dst);
+ if (size > maxlen) {
+ warn_noalloc();
+ return -1;
+ }
+ iomemcpy(dst, src, size);
+ return size;
+}
+
+// Process CBFS links file. The links file is a newline separated
+// file where each line has a "link name" and a "destination name"
+// separated by a space character.
+static void
+process_links_file(void)
+{
+ char *links = romfile_loadfile("links", NULL), *next = links;
+ while (next) {
+ // Parse out linkname and destname
+ char *linkname = next;
+ next = strchr(linkname, '\n');
+ if (next)
+ *next++ = '\0';
+ char *comment = strchr(linkname, '#');
+ if (comment)
+ *comment = '\0';
+ linkname = nullTrailingSpace(linkname);
+ char *destname = strchr(linkname, ' ');
+ if (!destname)
+ continue;
+ *destname++ = '\0';
+ destname = nullTrailingSpace(destname);
+ // Lookup destname and create new romfile entry for linkname
+ struct romfile_s *ufile = romfile_find(destname);
+ if (!ufile)
+ continue;
+ struct cbfs_romfile_s *cufile
+ = container_of(ufile, struct cbfs_romfile_s, file);
+ struct cbfs_romfile_s *cfile = malloc_tmp(sizeof(*cfile));
+ if (!cfile) {
+ warn_noalloc();
+ break;
+ }
+ memcpy(cfile, cufile, sizeof(*cfile));
+ strtcpy(cfile->file.name, linkname, sizeof(cfile->file.name));
+ romfile_add(&cfile->file);
+ }
+ free(links);
+}
+
+void
+coreboot_cbfs_init(void)
+{
+ if (!CONFIG_COREBOOT_FLASH)
+ return;
+
+ struct cbfs_header *hdr = *(void **)(CONFIG_CBFS_LOCATION - 4);
+ if (hdr->magic != cpu_to_be32(CBFS_HEADER_MAGIC)) {
+ dprintf(1, "Unable to find CBFS (ptr=%p; got %x not %x)\n"
+ , hdr, hdr->magic, cpu_to_be32(CBFS_HEADER_MAGIC));
+ return;
+ }
+ dprintf(1, "Found CBFS header at %p\n", hdr);
+
+ u32 romsize = be32_to_cpu(hdr->romsize);
+ u32 romstart = CONFIG_CBFS_LOCATION - romsize;
+ struct cbfs_file *fhdr = (void*)romstart + be32_to_cpu(hdr->offset);
+ for (;;) {
+ if ((u32)fhdr - romstart > romsize)
+ break;
+ u64 magic = fhdr->magic;
+ if (magic != CBFS_FILE_MAGIC)
+ break;
+ struct cbfs_romfile_s *cfile = malloc_tmp(sizeof(*cfile));
+ if (!cfile) {
+ warn_noalloc();
+ break;
+ }
+ memset(cfile, 0, sizeof(*cfile));
+ strtcpy(cfile->file.name, fhdr->filename, sizeof(cfile->file.name));
+ cfile->file.size = cfile->rawsize = be32_to_cpu(fhdr->len);
+ cfile->fhdr = fhdr;
+ cfile->file.copy = cbfs_copyfile;
+ cfile->data = (void*)fhdr + be32_to_cpu(fhdr->offset);
+ int len = strlen(cfile->file.name);
+ if (len > 5 && strcmp(&cfile->file.name[len-5], ".lzma") == 0) {
+ // Using compression.
+ cfile->flags = 1;
+ cfile->file.name[len-5] = '\0';
+ cfile->file.size = *(u32*)(cfile->data + LZMA_PROPERTIES_SIZE);
+ }
+ romfile_add(&cfile->file);
+
+ fhdr = (void*)ALIGN((u32)cfile->data + cfile->rawsize
+ , be32_to_cpu(hdr->align));
+ }
+
+ process_links_file();
+}
+
+struct cbfs_payload_segment {
+ u32 type;
+ u32 compression;
+ u32 offset;
+ u64 load_addr;
+ u32 len;
+ u32 mem_len;
+} PACKED;
+
+#define PAYLOAD_SEGMENT_BSS 0x20535342
+#define PAYLOAD_SEGMENT_ENTRY 0x52544E45
+
+#define CBFS_COMPRESS_NONE 0
+#define CBFS_COMPRESS_LZMA 1
+
+struct cbfs_payload {
+ struct cbfs_payload_segment segments[1];
+};
+
+void
+cbfs_run_payload(struct cbfs_file *fhdr)
+{
+ if (!CONFIG_COREBOOT_FLASH || !fhdr)
+ return;
+ dprintf(1, "Run %s\n", fhdr->filename);
+ struct cbfs_payload *pay = (void*)fhdr + be32_to_cpu(fhdr->offset);
+ struct cbfs_payload_segment *seg = pay->segments;
+ for (;;) {
+ void *src = (void*)pay + be32_to_cpu(seg->offset);
+ void *dest = (void*)(u32)be64_to_cpu(seg->load_addr);
+ u32 src_len = be32_to_cpu(seg->len);
+ u32 dest_len = be32_to_cpu(seg->mem_len);
+ switch (seg->type) {
+ case PAYLOAD_SEGMENT_BSS:
+ dprintf(3, "BSS segment %d@%p\n", dest_len, dest);
+ memset(dest, 0, dest_len);
+ break;
+ case PAYLOAD_SEGMENT_ENTRY: {
+ dprintf(1, "Calling addr %p\n", dest);
+ void (*func)() = dest;
+ func();
+ return;
+ }
+ default:
+ dprintf(3, "Segment %x %d@%p -> %d@%p\n"
+ , seg->type, src_len, src, dest_len, dest);
+ if (seg->compression == cpu_to_be32(CBFS_COMPRESS_NONE)) {
+ if (src_len > dest_len)
+ src_len = dest_len;
+ memcpy(dest, src, src_len);
+ } else if (CONFIG_LZMA
+ && seg->compression == cpu_to_be32(CBFS_COMPRESS_LZMA)) {
+ int ret = ulzma(dest, dest_len, src, src_len);
+ if (ret < 0)
+ return;
+ src_len = ret;
+ } else {
+ dprintf(1, "No support for compression type %x\n"
+ , seg->compression);
+ return;
+ }
+ if (dest_len > src_len)
+ memset(dest + src_len, 0, dest_len - src_len);
+ break;
+ }
+ seg++;
+ }
+}
+
+// Register payloads in "img/" directory with boot system.
+void
+cbfs_payload_setup(void)
+{
+ if (!CONFIG_COREBOOT_FLASH)
+ return;
+ struct romfile_s *file = NULL;
+ for (;;) {
+ file = romfile_findprefix("img/", file);
+ if (!file)
+ break;
+ struct cbfs_romfile_s *cfile;
+ cfile = container_of(file, struct cbfs_romfile_s, file);
+ const char *filename = file->name;
+ char *desc = znprintf(MAXDESCSIZE, "Payload [%s]", &filename[4]);
+ boot_add_cbfs(cfile->fhdr, desc, bootprio_find_named_rom(filename, 0));
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/csm.c b/qemu/roms/seabios/src/fw/csm.c
new file mode 100644
index 000000000..7cdb398f2
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/csm.c
@@ -0,0 +1,344 @@
+// Compatibility Support Module (CSM) for UEFI / EDK-II
+//
+// Copyright © 2013 Intel Corporation
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "bregs.h"
+#include "config.h" // CONFIG_*
+#include "farptr.h" // MAKE_FLATPTR
+#include "hw/pci.h"
+#include "hw/pic.h"
+#include "malloc.h" // csm_malloc_preinit
+#include "memmap.h"
+#include "output.h" // dprintf
+#include "stacks.h" // wait_threads
+#include "std/acpi.h" // RSDP_SIGNATURE
+#include "std/bda.h" // struct bios_data_area_s
+#include "std/optionrom.h" // struct rom_header
+#include "util.h" // copy_smbios
+#include "paravirt.h" // qemu_preinit
+
+#define UINT8 u8
+#define UINT16 u16
+#define UINT32 u32
+#include "std/LegacyBios.h"
+
+struct rsdp_descriptor csm_rsdp VARFSEG __aligned(16);
+
+EFI_COMPATIBILITY16_TABLE csm_compat_table VARFSEG __aligned(16) = {
+ .Signature = 0x24454649,
+ .TableChecksum = 0 /* Filled in by checkrom.py */,
+ .TableLength = sizeof(csm_compat_table),
+ .Compatibility16CallSegment = SEG_BIOS,
+ .Compatibility16CallOffset = 0 /* Filled in by checkrom.py */,
+ .OemIdStringPointer = (u32)"SeaBIOS",
+ .AcpiRsdPtrPointer = (u32)&csm_rsdp,
+};
+
+EFI_TO_COMPATIBILITY16_INIT_TABLE *csm_init_table;
+EFI_TO_COMPATIBILITY16_BOOT_TABLE *csm_boot_table;
+
+static u16 PICMask = PIC_IRQMASK_DEFAULT;
+
+extern void __csm_return(struct bregs *regs) __noreturn;
+
+static void
+csm_return(struct bregs *regs)
+{
+ u32 rommax = rom_get_max();
+ extern u8 final_readonly_start[];
+
+ dprintf(3, "handle_csm returning AX=%04x\n", regs->ax);
+
+ csm_compat_table.UmaAddress = rommax;
+ csm_compat_table.UmaSize = (u32)final_readonly_start - rommax;
+
+ PICMask = pic_irqmask_read();
+ __csm_return(regs);
+}
+
+static void
+csm_maininit(struct bregs *regs)
+{
+ interface_init();
+ pci_probe_devices();
+
+ csm_compat_table.PnPInstallationCheckSegment = SEG_BIOS;
+ csm_compat_table.PnPInstallationCheckOffset = get_pnp_offset();
+
+ regs->ax = 0;
+
+ csm_return(regs);
+}
+
+/* Legacy16InitializeYourself */
+static void
+handle_csm_0000(struct bregs *regs)
+{
+ qemu_preinit();
+
+ dprintf(3, "Legacy16InitializeYourself table %04x:%04x\n", regs->es,
+ regs->bx);
+
+ csm_init_table = MAKE_FLATPTR(regs->es, regs->bx);
+
+ dprintf(3, "BiosLessThan1MB %08x\n", csm_init_table->BiosLessThan1MB);
+ dprintf(3, "HiPmmMemory %08x\n", csm_init_table->HiPmmMemory);
+ dprintf(3, "HiPmmMemorySize %08x\n", csm_init_table->HiPmmMemorySizeInBytes);
+ dprintf(3, "ReverseThunk %04x:%04x\n", csm_init_table->ReverseThunkCallSegment,
+ csm_init_table->ReverseThunkCallOffset);
+ dprintf(3, "NumE820Entries %08x\n", csm_init_table->NumberE820Entries);
+ dprintf(3, "OsMemoryAbove1M %08x\n", csm_init_table->OsMemoryAbove1Mb);
+ dprintf(3, "ThunkStart %08x\n", csm_init_table->ThunkStart);
+ dprintf(3, "ThunkSize %08x\n", csm_init_table->ThunkSizeInBytes);
+ dprintf(3, "LoPmmMemory %08x\n", csm_init_table->LowPmmMemory);
+ dprintf(3, "LoPmmMemorySize %08x\n", csm_init_table->LowPmmMemorySizeInBytes);
+
+ csm_malloc_preinit(csm_init_table->LowPmmMemory,
+ csm_init_table->LowPmmMemorySizeInBytes,
+ csm_init_table->HiPmmMemory,
+ csm_init_table->HiPmmMemorySizeInBytes);
+ reloc_preinit(csm_maininit, regs);
+}
+
+/* Legacy16UpdateBbs */
+static void
+handle_csm_0001(struct bregs *regs)
+{
+ if (!CONFIG_BOOT) {
+ regs->ax = 1;
+ return;
+ }
+
+ dprintf(3, "Legacy16UpdateBbs table %04x:%04x\n", regs->es, regs->bx);
+
+ csm_boot_table = MAKE_FLATPTR(regs->es, regs->bx);
+ dprintf(3, "MajorVersion %04x\n", csm_boot_table->MajorVersion);
+ dprintf(3, "MinorVersion %04x\n", csm_boot_table->MinorVersion);
+ dprintf(3, "AcpiTable %08x\n", csm_boot_table->AcpiTable);
+ dprintf(3, "SmbiosTable %08x\n", csm_boot_table->SmbiosTable);
+ dprintf(3, "SmbiosTableLength %08x\n", csm_boot_table->SmbiosTableLength);
+// dprintf(3, "SioData %08x\n", csm_boot_table->SioData);
+ dprintf(3, "DevicePathType %04x\n", csm_boot_table->DevicePathType);
+ dprintf(3, "PciIrqMask %04x\n", csm_boot_table->PciIrqMask);
+ dprintf(3, "NumberE820Entries %08x\n", csm_boot_table->NumberE820Entries);
+// dprintf(3, "HddInfo %08x\n", csm_boot_table->HddInfo);
+ dprintf(3, "NumberBbsEntries %08x\n", csm_boot_table->NumberBbsEntries);
+ dprintf(3, "BBsTable %08x\n", csm_boot_table->BbsTable);
+ dprintf(3, "SmmTable %08x\n", csm_boot_table->SmmTable);
+ dprintf(3, "OsMemoryAbove1Mb %08x\n", csm_boot_table->OsMemoryAbove1Mb);
+ dprintf(3, "UnconventionalDeviceTable %08x\n", csm_boot_table->UnconventionalDeviceTable);
+
+ regs->ax = 0;
+}
+
+/* PrepareToBoot */
+static void
+handle_csm_0002(struct bregs *regs)
+{
+ if (!CONFIG_BOOT) {
+ regs->ax = 1;
+ return;
+ }
+
+ dprintf(3, "PrepareToBoot table %04x:%04x\n", regs->es, regs->bx);
+
+ struct e820entry *p = (void *)csm_compat_table.E820Pointer;
+ int i;
+ for (i=0; i < csm_compat_table.E820Length / sizeof(struct e820entry); i++)
+ add_e820(p[i].start, p[i].size, p[i].type);
+
+ if (csm_init_table->HiPmmMemorySizeInBytes > BUILD_MAX_HIGHTABLE) {
+ u32 hi_pmm_end = csm_init_table->HiPmmMemory + csm_init_table->HiPmmMemorySizeInBytes;
+ add_e820(hi_pmm_end - BUILD_MAX_HIGHTABLE, BUILD_MAX_HIGHTABLE, E820_RESERVED);
+ }
+
+ // For PCIBIOS 1ab10e
+ if (csm_compat_table.IrqRoutingTablePointer &&
+ csm_compat_table.IrqRoutingTableLength) {
+ PirAddr = (void *)csm_compat_table.IrqRoutingTablePointer;
+ dprintf(3, "CSM PIRQ table at %p\n", PirAddr);
+ }
+
+ // For find_resume_vector()... and find_acpi_features()
+ if (csm_rsdp.signature == RSDP_SIGNATURE) {
+ RsdpAddr = &csm_rsdp;
+ dprintf(3, "CSM ACPI RSDP at %p\n", RsdpAddr);
+
+ find_acpi_features();
+ }
+
+ // SMBIOS table needs to be copied into the f-seg
+ // XX: OVMF doesn't seem to set SmbiosTableLength so don't check it
+ if (csm_boot_table->SmbiosTable && !SMBiosAddr)
+ copy_smbios((void *)csm_boot_table->SmbiosTable);
+
+ // MPTABLE is just there; we don't care where.
+
+ // EFI may have reinitialised the video using its *own* driver.
+ enable_vga_console();
+
+ // EFI fills this in for us. Zero it for now...
+ struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
+ bda->hdcount = 0;
+
+ mathcp_setup();
+ timer_setup();
+ clock_setup();
+ device_hardware_setup();
+ wait_threads();
+ interactive_bootmenu();
+
+ prepareboot();
+
+ regs->ax = 0;
+}
+
+/* Boot */
+static void
+handle_csm_0003(struct bregs *regs)
+{
+ if (!CONFIG_BOOT) {
+ regs->ax = 1;
+ return;
+ }
+
+ dprintf(3, "Boot\n");
+
+ startBoot();
+
+ regs->ax = 1;
+}
+
+/* Legacy16DispatchOprom */
+static void
+handle_csm_0005(struct bregs *regs)
+{
+ EFI_DISPATCH_OPROM_TABLE *table = MAKE_FLATPTR(regs->es, regs->bx);
+ struct rom_header *rom;
+ u16 bdf;
+
+ if (!CONFIG_OPTIONROMS) {
+ regs->ax = 1;
+ return;
+ }
+
+ dprintf(3, "Legacy16DispatchOprom rom %p\n", table);
+
+ dprintf(3, "OpromSegment %04x\n", table->OpromSegment);
+ dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
+ dprintf(3, "PnPInstallationCheck %04x:%04x\n",
+ table->PnPInstallationCheckSegment,
+ table->PnPInstallationCheckOffset);
+ dprintf(3, "RuntimeSegment %04x\n", table->RuntimeSegment);
+
+ rom = MAKE_FLATPTR(table->OpromSegment, 0);
+ bdf = pci_bus_devfn_to_bdf(table->PciBus, table->PciDeviceFunction);
+
+ rom_reserve(rom->size * 512);
+
+ // XX PnP seg/ofs should never be other than default
+ callrom(rom, bdf);
+
+ rom_confirm(rom->size * 512);
+
+ regs->bx = 0; // FIXME
+ regs->ax = 0;
+}
+
+/* Legacy16GetTableAddress */
+static void
+handle_csm_0006(struct bregs *regs)
+{
+ u16 size = regs->cx;
+ u16 align = regs->dx;
+ u16 region = regs->bx; // (1 for F000 seg, 2 for E000 seg, 0 for either)
+ void *chunk = NULL;
+
+ if (!region)
+ region = 3;
+
+ dprintf(3, "Legacy16GetTableAddress size %x align %x region %d\n",
+ size, align, region);
+
+ if (region & 2)
+ chunk = _malloc(&ZoneLow, size, align);
+ if (!chunk && (region & 1))
+ chunk = _malloc(&ZoneFSeg, size, align);
+
+ dprintf(3, "Legacy16GetTableAddress size %x align %x region %d yields %p\n",
+ size, align, region, chunk);
+ if (chunk) {
+ regs->ds = FLATPTR_TO_SEG(chunk);
+ regs->bx = FLATPTR_TO_OFFSET(chunk);
+ regs->ax = 0;
+ } else {
+ regs->ax = 1;
+ }
+}
+
+void VISIBLE32INIT
+handle_csm(struct bregs *regs)
+{
+ ASSERT32FLAT();
+
+ if (!CONFIG_CSM)
+ return;
+
+ dprintf(3, "handle_csm regs %p AX=%04x\n", regs, regs->ax);
+
+ pic_irqmask_write(PICMask);
+
+ switch(regs->ax) {
+ case 0000: handle_csm_0000(regs); break;
+ case 0001: handle_csm_0001(regs); break;
+ case 0002: handle_csm_0002(regs); break;
+ case 0003: handle_csm_0003(regs); break;
+// case 0004: handle_csm_0004(regs); break;
+ case 0005: handle_csm_0005(regs); break;
+ case 0006: handle_csm_0006(regs); break;
+// case 0007: handle_csm_0007(regs); break;
+// case 0008: hamdle_csm_0008(regs); break;
+ default: regs->al = 1;
+ }
+
+ csm_return(regs);
+}
+
+int csm_bootprio_ata(struct pci_device *pci, int chanid, int slave)
+{
+ if (!csm_boot_table)
+ return -1;
+ BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
+ int index = 1 + (chanid * 2) + slave;
+ dprintf(3, "CSM bootprio for ATA%d,%d (index %d) is %d\n", chanid, slave,
+ index, bbs[index].BootPriority);
+ return bbs[index].BootPriority;
+}
+
+int csm_bootprio_fdc(struct pci_device *pci, int port, int fdid)
+{
+ if (!csm_boot_table)
+ return -1;
+ BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
+ dprintf(3, "CSM bootprio for FDC is %d\n", bbs[0].BootPriority);
+ return bbs[0].BootPriority;
+}
+
+int csm_bootprio_pci(struct pci_device *pci)
+{
+ if (!csm_boot_table)
+ return -1;
+ BBS_TABLE *bbs = (void *)csm_boot_table->BbsTable;
+ int i;
+
+ for (i = 5; i < csm_boot_table->NumberBbsEntries; i++) {
+ if (pci->bdf == pci_to_bdf(bbs[i].Bus, bbs[i].Device, bbs[i].Function)) {
+ dprintf(3, "CSM bootprio for PCI(%d,%d,%d) is %d\n", bbs[i].Bus,
+ bbs[i].Device, bbs[i].Function, bbs[i].BootPriority);
+ return bbs[i].BootPriority;
+ }
+ }
+ return -1;
+}
diff --git a/qemu/roms/seabios/src/fw/dev-piix.h b/qemu/roms/seabios/src/fw/dev-piix.h
new file mode 100644
index 000000000..c389f171a
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/dev-piix.h
@@ -0,0 +1,29 @@
+#ifndef __DEV_PIIX_H
+#define __DEV_PIIX_H
+
+#define I440FX_PAM0 0x59
+#define I440FX_SMRAM 0x72
+
+#define PIIX_PMBASE 0x40
+#define PIIX_PMREGMISC 0x80
+#define PIIX_SMBHSTBASE 0x90
+#define PIIX_SMBHSTCFG 0xd2
+#define PIIX_DEVACTB 0x58
+#define PIIX_DEVACTB_APMC_EN (1 << 25)
+
+#define PIIX_PORT_ELCR1 0x4d0
+#define PIIX_PORT_ELCR2 0x4d1
+
+/* ICH9 PM I/O registers */
+#define PIIX_GPE0_BLK 0xafe0
+#define PIIX_GPE0_BLK_LEN 4
+#define PIIX_PMIO_GLBCTL 0x28
+#define PIIX_PMIO_GLBCTL_SMI_EN 1
+
+/* FADT ACPI_ENABLE/ACPI_DISABLE */
+#define PIIX_ACPI_ENABLE 0xf1
+#define PIIX_ACPI_DISABLE 0xf0
+
+#define PIIX_PM_INTRRUPT 9 // irq 9
+
+#endif // dev-piix.h
diff --git a/qemu/roms/seabios/src/fw/dev-q35.h b/qemu/roms/seabios/src/fw/dev-q35.h
new file mode 100644
index 000000000..c6f8bd9e7
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/dev-q35.h
@@ -0,0 +1,49 @@
+#ifndef __DEV_Q35_H
+#define __DEV_Q35_H
+
+#include "types.h" // u16
+
+#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0
+#define Q35_HOST_BRIDGE_PAM0 0x90
+#define Q35_HOST_BRIDGE_SMRAM 0x9d
+#define Q35_HOST_BRIDGE_PCIEXBAR 0x60
+#define Q35_HOST_BRIDGE_PCIEXBAR_SIZE (256 * 1024 * 1024)
+#define Q35_HOST_BRIDGE_PCIEXBAR_ADDR 0xb0000000
+#define Q35_HOST_BRIDGE_PCIEXBAREN ((u64)1)
+#define Q35_HOST_PCIE_PCI_SEGMENT 0
+#define Q35_HOST_PCIE_START_BUS_NUMBER 0
+#define Q35_HOST_PCIE_END_BUS_NUMBER 255
+
+#define PCI_DEVICE_ID_INTEL_ICH9_LPC 0x2918
+#define ICH9_LPC_PMBASE 0x40
+#define ICH9_LPC_PMBASE_RTE 0x1
+
+#define ICH9_LPC_ACPI_CTRL 0x44
+#define ICH9_LPC_ACPI_CTRL_ACPI_EN 0x80
+#define ICH9_LPC_PIRQA_ROUT 0x60
+#define ICH9_LPC_PIRQE_ROUT 0x68
+#define ICH9_LPC_PIRQ_ROUT_IRQEN 0x80
+#define ICH9_LPC_GEN_PMCON_1 0xa0
+#define ICH9_LPC_GEN_PMCON_1_SMI_LOCK (1 << 4)
+#define ICH9_LPC_PORT_ELCR1 0x4d0
+#define ICH9_LPC_PORT_ELCR2 0x4d1
+#define PCI_DEVICE_ID_INTEL_ICH9_SMBUS 0x2930
+#define ICH9_SMB_SMB_BASE 0x20
+#define ICH9_SMB_HOSTC 0x40
+#define ICH9_SMB_HOSTC_HST_EN 0x01
+
+#define ICH9_ACPI_ENABLE 0x2
+#define ICH9_ACPI_DISABLE 0x3
+
+/* ICH9 LPC PM I/O registers are 128 ports and 128-aligned */
+#define ICH9_PMIO_GPE0_STS 0x20
+#define ICH9_PMIO_GPE0_BLK_LEN 0x10
+#define ICH9_PMIO_SMI_EN 0x30
+#define ICH9_PMIO_SMI_EN_APMC_EN (1 << 5)
+#define ICH9_PMIO_SMI_EN_GLB_SMI_EN (1 << 0)
+
+/* FADT ACPI_ENABLE/ACPI_DISABLE */
+#define ICH9_APM_ACPI_ENABLE 0x2
+#define ICH9_APM_ACPI_DISABLE 0x3
+
+#endif // dev-q35.h
diff --git a/qemu/roms/seabios/src/fw/lzmadecode.c b/qemu/roms/seabios/src/fw/lzmadecode.c
new file mode 100644
index 000000000..65819b53c
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/lzmadecode.c
@@ -0,0 +1,398 @@
+/*
+ LzmaDecode.c
+ LZMA Decoder (optimized for Speed version)
+
+ LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this Code, expressly permits you to
+ statically or dynamically link your Code (or bind by name) to the
+ interfaces of this file without subjecting your linked Code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "lzmadecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+ { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+
+
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+ { UpdateBit0(p); mi <<= 1; A0; } else \
+ { UpdateBit1(p); mi = (mi + mi) + 1; A1; }
+
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+ { int i = numLevels; res = 1; \
+ do { CProb *cp = probs + res; RC_GET_BIT(cp, res) } while(--i != 0); \
+ res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+ unsigned char prop0;
+ if (size < LZMA_PROPERTIES_SIZE)
+ return LZMA_RESULT_DATA_ERROR;
+ prop0 = propsData[0];
+ if (prop0 >= (9 * 5 * 5))
+ return LZMA_RESULT_DATA_ERROR;
+ {
+ for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+ for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+ propsRes->lc = prop0;
+ /*
+ unsigned char remainder = (unsigned char)(prop0 / 9);
+ propsRes->lc = prop0 % 9;
+ propsRes->pb = remainder / 5;
+ propsRes->lp = remainder % 5;
+ */
+ }
+
+ return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+ CProb *p = vs->Probs;
+ SizeT nowPos = 0;
+ Byte previousByte = 0;
+ UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+ UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+ int lc = vs->Properties.lc;
+
+
+ int state = 0;
+ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+ int len = 0;
+ const Byte *Buffer;
+ const Byte *BufferLim;
+ UInt32 Range;
+ UInt32 Code;
+
+ *inSizeProcessed = 0;
+ *outSizeProcessed = 0;
+
+ {
+ UInt32 i;
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ }
+
+ RC_INIT(inStream, inSize);
+
+
+ while(nowPos < outSize)
+ {
+ CProb *prob;
+ UInt32 bound;
+ int posState = (int)(
+ (nowPos
+ )
+ & posStateMask);
+
+ prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ int symbol = 1;
+ UpdateBit0(prob)
+ prob = p + Literal + (LZMA_LIT_SIZE *
+ (((
+ (nowPos
+ )
+ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+ if (state >= kNumLitStates)
+ {
+ int matchByte;
+ matchByte = outStream[nowPos - rep0];
+ do
+ {
+ int bit;
+ CProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & 0x100);
+ probLit = prob + 0x100 + bit + symbol;
+ RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+ }
+ while (symbol < 0x100);
+ }
+ while (symbol < 0x100)
+ {
+ CProb *probLit = prob + symbol;
+ RC_GET_BIT(probLit, symbol)
+ }
+ previousByte = (Byte)symbol;
+
+ outStream[nowPos++] = previousByte;
+ if (state < 4) state = 0;
+ else if (state < 10) state -= 3;
+ else state -= 6;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRep + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < kNumLitStates ? 0 : 3;
+ prob = p + LenCoder;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG0 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+
+ if (nowPos == 0)
+ return LZMA_RESULT_DATA_ERROR;
+
+ state = state < kNumLitStates ? 9 : 11;
+ previousByte = outStream[nowPos - rep0];
+ outStream[nowPos++] = previousByte;
+
+ continue;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ }
+ }
+ else
+ {
+ UInt32 distance;
+ UpdateBit1(prob);
+ prob = p + IsRepG1 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG2 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = p + RepLenCoder;
+ }
+ {
+ int numBits, offset;
+ CProb *probLen = prob + LenChoice;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ numBits = kLenNumLowBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenChoice2;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ numBits = kLenNumMidBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ numBits = kLenNumHighBits;
+ }
+ }
+ RangeDecoderBitTreeDecode(probLen, numBits, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ int posSlot;
+ state += kNumLitStates;
+ prob = p + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+ rep0 = (2 | ((UInt32)posSlot & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ rep0 <<= numDirectBits;
+ prob = p + SpecPos + rep0 - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ RC_NORMALIZE
+ Range >>= 1;
+ rep0 <<= 1;
+ if (Code >= Range)
+ {
+ Code -= Range;
+ rep0 |= 1;
+ }
+ }
+ while (--numDirectBits != 0);
+ prob = p + Align;
+ rep0 <<= kNumAlignBits;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ int i = 1;
+ int mi = 1;
+ do
+ {
+ CProb *prob3 = prob + mi;
+ RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+ i <<= 1;
+ }
+ while(--numDirectBits != 0);
+ }
+ }
+ else
+ rep0 = posSlot;
+ if (++rep0 == (UInt32)(0))
+ {
+ /* it's for stream version */
+ len = kLzmaStreamWasFinishedId;
+ break;
+ }
+ }
+
+ len += kMatchMinLen;
+ if (rep0 > nowPos)
+ return LZMA_RESULT_DATA_ERROR;
+
+
+ do
+ {
+ previousByte = outStream[nowPos - rep0];
+ len--;
+ outStream[nowPos++] = previousByte;
+ }
+ while(len != 0 && nowPos < outSize);
+ }
+ }
+ RC_NORMALIZE;
+
+
+ *inSizeProcessed = (SizeT)(Buffer - inStream);
+ *outSizeProcessed = nowPos;
+ return LZMA_RESULT_OK;
+}
diff --git a/qemu/roms/seabios/src/fw/lzmadecode.h b/qemu/roms/seabios/src/fw/lzmadecode.h
new file mode 100644
index 000000000..dedde0de6
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/lzmadecode.h
@@ -0,0 +1,67 @@
+/*
+ LzmaDecode.h
+ LZMA Decoder interface
+
+ LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+typedef unsigned char Byte;
+typedef unsigned short UInt16;
+typedef unsigned int UInt32;
+typedef UInt32 SizeT;
+
+#define CProb UInt16
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+ int lc;
+ int lp;
+ int pb;
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+ CLzmaProperties Properties;
+ CProb *Probs;
+
+
+} CLzmaDecoderState;
+
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
diff --git a/qemu/roms/seabios/src/fw/mptable.c b/qemu/roms/seabios/src/fw/mptable.c
new file mode 100644
index 000000000..8e01e0043
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/mptable.c
@@ -0,0 +1,196 @@
+// MPTable generation (on emulators)
+// DO NOT ADD NEW FEATURES HERE. (See paravirt.c / biostables.c instead.)
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "hw/pci.h"
+#include "hw/pci_regs.h"
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "romfile.h" // romfile_loadint
+#include "std/mptable.h" // MPTABLE_SIGNATURE
+#include "string.h" // memset
+#include "util.h" // MaxCountCPUs
+#include "x86.h" // cpuid
+
+void
+mptable_setup(void)
+{
+ if (! CONFIG_MPTABLE)
+ return;
+
+ dprintf(3, "init MPTable\n");
+
+ // Config structure in temp area.
+ struct mptable_config_s *config = malloc_tmp(32*1024);
+ if (!config) {
+ warn_noalloc();
+ return;
+ }
+ memset(config, 0, sizeof(*config));
+ config->signature = MPCONFIG_SIGNATURE;
+ config->spec = 4;
+ memcpy(config->oemid, BUILD_CPUNAME8, sizeof(config->oemid));
+ memcpy(config->productid, "0.1 ", sizeof(config->productid));
+ config->lapic = BUILD_APIC_ADDR;
+
+ // Detect cpu info
+ u32 cpuid_signature, ebx, ecx, cpuid_features;
+ cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features);
+ if (! cpuid_signature) {
+ // Use default values.
+ cpuid_signature = 0x600;
+ cpuid_features = 0x201;
+ }
+ int pkgcpus = 1;
+ if (cpuid_features & (1 << 28)) {
+ /* Only populate the MPS tables with the first logical CPU in
+ each package */
+ pkgcpus = (ebx >> 16) & 0xff;
+ pkgcpus = 1 << (__fls(pkgcpus - 1) + 1); /* round up to power of 2 */
+ }
+ u8 apic_version = readl((u8*)BUILD_APIC_ADDR + 0x30) & 0xff;
+
+ // CPU definitions.
+ struct mpt_cpu *cpus = (void*)&config[1], *cpu = cpus;
+ int i;
+ for (i = 0; i < MaxCountCPUs; i+=pkgcpus) {
+ memset(cpu, 0, sizeof(*cpu));
+ cpu->type = MPT_TYPE_CPU;
+ cpu->apicid = i;
+ cpu->apicver = apic_version;
+ /* cpu flags: enabled, bootstrap cpu */
+ cpu->cpuflag = (apic_id_is_present(i) ? 0x01 : 0x00) | ((i==0) ? 0x02 : 0x00);
+ cpu->cpusignature = cpuid_signature;
+ cpu->featureflag = cpuid_features;
+ cpu++;
+ }
+ int entrycount = cpu - cpus;
+
+ // PCI bus
+ struct mpt_bus *buses = (void*)cpu, *bus = buses;
+ if (!hlist_empty(&PCIDevices)) {
+ memset(bus, 0, sizeof(*bus));
+ bus->type = MPT_TYPE_BUS;
+ bus->busid = 0;
+ memcpy(bus->bustype, "PCI ", sizeof(bus->bustype));
+ bus++;
+ entrycount++;
+ }
+
+ /* isa bus */
+ int isabusid = bus - buses;
+ memset(bus, 0, sizeof(*bus));
+ bus->type = MPT_TYPE_BUS;
+ bus->busid = isabusid;
+ memcpy(bus->bustype, "ISA ", sizeof(bus->bustype));
+ bus++;
+ entrycount++;
+
+ /* ioapic */
+ u8 ioapic_id = BUILD_IOAPIC_ID;
+ struct mpt_ioapic *ioapic = (void*)bus;
+ memset(ioapic, 0, sizeof(*ioapic));
+ ioapic->type = MPT_TYPE_IOAPIC;
+ ioapic->apicid = ioapic_id;
+ ioapic->apicver = 0x11;
+ ioapic->flags = 1; // enable
+ ioapic->apicaddr = BUILD_IOAPIC_ADDR;
+ entrycount++;
+
+ /* irqs */
+ struct mpt_intsrc *intsrcs = (void*)&ioapic[1], *intsrc = intsrcs;
+ int dev = -1;
+ unsigned short pinmask = 0;
+
+ struct pci_device *pci;
+ foreachpci(pci) {
+ u16 bdf = pci->bdf;
+ if (pci_bdf_to_bus(bdf) != 0)
+ break;
+ int pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
+ int irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+ if (pin == 0)
+ continue;
+ if (dev != pci_bdf_to_busdev(bdf)) {
+ dev = pci_bdf_to_busdev(bdf);
+ pinmask = 0;
+ }
+ if (pinmask & (1 << pin)) /* pin was seen already */
+ continue;
+ pinmask |= (1 << pin);
+ memset(intsrc, 0, sizeof(*intsrc));
+ intsrc->type = MPT_TYPE_INTSRC;
+ intsrc->irqtype = 0; /* INT */
+ intsrc->irqflag = 1; /* active high */
+ intsrc->srcbus = pci_bdf_to_bus(bdf); /* PCI bus */
+ intsrc->srcbusirq = (pci_bdf_to_dev(bdf) << 2) | (pin - 1);
+ intsrc->dstapic = ioapic_id;
+ intsrc->dstirq = irq;
+ intsrc++;
+ }
+
+ int irq0_override = romfile_loadint("etc/irq0-override", 0);
+ for (i = 0; i < 16; i++) {
+ memset(intsrc, 0, sizeof(*intsrc));
+ if (BUILD_PCI_IRQS & (1 << i))
+ continue;
+ intsrc->type = MPT_TYPE_INTSRC;
+ intsrc->irqtype = 0; /* INT */
+ intsrc->irqflag = 0; /* conform to bus spec */
+ intsrc->srcbus = isabusid; /* ISA bus */
+ intsrc->srcbusirq = i;
+ intsrc->dstapic = ioapic_id;
+ intsrc->dstirq = i;
+ if (irq0_override) {
+ /* Destination 2 is covered by irq0->inti2 override (i ==
+ 0). Source IRQ 2 is unused */
+ if (i == 0)
+ intsrc->dstirq = 2;
+ else if (i == 2)
+ intsrc--;
+ }
+ intsrc++;
+ }
+
+ /* Local interrupt assignment */
+ intsrc->type = MPT_TYPE_LOCAL_INT;
+ intsrc->irqtype = 3; /* ExtINT */
+ intsrc->irqflag = 0; /* PO, EL default */
+ intsrc->srcbus = isabusid; /* ISA */
+ intsrc->srcbusirq = 0;
+ intsrc->dstapic = 0; /* BSP == APIC #0 */
+ intsrc->dstirq = 0; /* LINTIN0 */
+ intsrc++;
+
+ intsrc->type = MPT_TYPE_LOCAL_INT;
+ intsrc->irqtype = 1; /* NMI */
+ intsrc->irqflag = 0; /* PO, EL default */
+ intsrc->srcbus = isabusid; /* ISA */
+ intsrc->srcbusirq = 0;
+ intsrc->dstapic = 0xff; /* to all local APICs */
+ intsrc->dstirq = 1; /* LINTIN1 */
+ intsrc++;
+ entrycount += intsrc - intsrcs;
+
+ // Finalize config structure.
+ int length = (void*)intsrc - (void*)config;
+ config->entrycount = entrycount;
+ config->length = length;
+ config->checksum -= checksum(config, length);
+
+ // floating pointer structure
+ struct mptable_floating_s floating;
+ memset(&floating, 0, sizeof(floating));
+ floating.signature = MPTABLE_SIGNATURE;
+ floating.physaddr = (u32)config;
+ floating.length = 1;
+ floating.spec_rev = 4;
+ floating.checksum -= checksum(&floating, sizeof(floating));
+ copy_mptable(&floating);
+ free(config);
+}
diff --git a/qemu/roms/seabios/src/fw/mtrr.c b/qemu/roms/seabios/src/fw/mtrr.c
new file mode 100644
index 000000000..913580e7d
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/mtrr.c
@@ -0,0 +1,106 @@
+// Initialize MTRRs - mostly useful on KVM.
+//
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "hw/pci.h" // pcimem_start
+#include "output.h" // dprintf
+#include "paravirt.h" // RamSize
+#include "util.h" // mtrr_setup
+#include "x86.h" // cpuid
+
+#define MSR_MTRRcap 0x000000fe
+#define MSR_MTRRfix64K_00000 0x00000250
+#define MSR_MTRRfix16K_80000 0x00000258
+#define MSR_MTRRfix16K_A0000 0x00000259
+#define MSR_MTRRfix4K_C0000 0x00000268
+#define MSR_MTRRfix4K_C8000 0x00000269
+#define MSR_MTRRfix4K_D0000 0x0000026a
+#define MSR_MTRRfix4K_D8000 0x0000026b
+#define MSR_MTRRfix4K_E0000 0x0000026c
+#define MSR_MTRRfix4K_E8000 0x0000026d
+#define MSR_MTRRfix4K_F0000 0x0000026e
+#define MSR_MTRRfix4K_F8000 0x0000026f
+#define MSR_MTRRdefType 0x000002ff
+
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
+#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+#define MTRR_MEMTYPE_UC 0
+#define MTRR_MEMTYPE_WC 1
+#define MTRR_MEMTYPE_WT 4
+#define MTRR_MEMTYPE_WP 5
+#define MTRR_MEMTYPE_WB 6
+
+void mtrr_setup(void)
+{
+ if (!CONFIG_MTRR_INIT)
+ return;
+
+ u32 eax, ebx, ecx, edx, cpuid_features;
+ cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+ if (!(cpuid_features & CPUID_MTRR))
+ return;
+ if (!(cpuid_features & CPUID_MSR))
+ return;
+
+ dprintf(3, "init mtrr\n");
+
+ u32 mtrr_cap = rdmsr(MSR_MTRRcap);
+ int vcnt = mtrr_cap & 0xff;
+ int fix = mtrr_cap & 0x100;
+ if (!vcnt || !fix)
+ return;
+
+ // Disable MTRRs
+ wrmsr_smp(MSR_MTRRdefType, 0);
+
+ // Set fixed MTRRs
+ union u64b {
+ u8 valb[8];
+ u64 val;
+ } u;
+ u.val = 0;
+ int i;
+ for (i = 0; i < 8; i++)
+ if (RamSize >= 65536 * (i + 1))
+ u.valb[i] = MTRR_MEMTYPE_WB;
+ wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
+ u.val = 0;
+ for (i = 0; i < 8; i++)
+ if (RamSize >= 0x80000 + 16384 * (i + 1))
+ u.valb[i] = MTRR_MEMTYPE_WB;
+ wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
+ wrmsr_smp(MSR_MTRRfix16K_A0000, 0); // 0xA0000-0xC0000 is uncached
+ int j;
+ for (j = 0; j < 8; j++) {
+ u.val = 0;
+ for (i = 0; i < 8; i++)
+ if (RamSize >= 0xC0000 + j * 0x8000 + 4096 * (i + 1))
+ u.valb[i] = MTRR_MEMTYPE_WP;
+ wrmsr_smp(MSR_MTRRfix4K_C0000 + j, u.val);
+ }
+
+ // Set variable MTRRs
+ int phys_bits = 36;
+ cpuid(0x80000000u, &eax, &ebx, &ecx, &edx);
+ if (eax >= 0x80000008) {
+ /* Get physical bits from leaf 0x80000008 (if available) */
+ cpuid(0x80000008u, &eax, &ebx, &ecx, &edx);
+ phys_bits = eax & 0xff;
+ }
+ u64 phys_mask = ((1ull << phys_bits) - 1);
+ for (i=0; i<vcnt; i++) {
+ wrmsr_smp(MTRRphysBase_MSR(i), 0);
+ wrmsr_smp(MTRRphysMask_MSR(i), 0);
+ }
+ /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
+ wrmsr_smp(MTRRphysBase_MSR(0), pcimem_start | MTRR_MEMTYPE_UC);
+ wrmsr_smp(MTRRphysMask_MSR(0)
+ , (-((1ull<<32)-pcimem_start) & phys_mask) | 0x800);
+
+ // Enable fixed and variable MTRRs; set default type.
+ wrmsr_smp(MSR_MTRRdefType, 0xc00 | MTRR_MEMTYPE_WB);
+}
diff --git a/qemu/roms/seabios/src/fw/paravirt.c b/qemu/roms/seabios/src/fw/paravirt.c
new file mode 100644
index 000000000..db22ae8fc
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/paravirt.c
@@ -0,0 +1,448 @@
+// Paravirtualization support.
+//
+// Copyright (C) 2013 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2009 Red Hat Inc.
+//
+// Authors:
+// Gleb Natapov <gnatapov@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "byteorder.h" // be32_to_cpu
+#include "config.h" // CONFIG_QEMU
+#include "hw/pci.h" // create_pirtable
+#include "hw/pci_regs.h" // PCI_DEVICE_ID
+#include "hw/rtc.h" // CMOS_*
+#include "malloc.h" // malloc_tmp
+#include "memmap.h" // add_e820
+#include "output.h" // dprintf
+#include "paravirt.h" // qemu_cfg_preinit
+#include "romfile.h" // romfile_loadint
+#include "romfile_loader.h" // romfile_loader_execute
+#include "string.h" // memset
+#include "util.h" // pci_setup
+#include "x86.h" // cpuid
+#include "xen.h" // xen_biostable_setup
+
+// Amount of continuous ram under 4Gig
+u32 RamSize;
+// Amount of continuous ram >4Gig
+u64 RamSizeOver4G;
+// Type of emulator platform.
+int PlatformRunningOn VARFSEG;
+
+/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
+ * should be used to determine that a VM is running under KVM.
+ */
+#define KVM_CPUID_SIGNATURE 0x40000000
+
+static void kvm_detect(void)
+{
+ unsigned int eax, ebx, ecx, edx;
+ char signature[13];
+
+ cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
+ memcpy(signature + 0, &ebx, 4);
+ memcpy(signature + 4, &ecx, 4);
+ memcpy(signature + 8, &edx, 4);
+ signature[12] = 0;
+
+ if (strcmp(signature, "KVMKVMKVM") == 0) {
+ dprintf(1, "Running on KVM\n");
+ PlatformRunningOn |= PF_KVM;
+ }
+}
+
+static void qemu_detect(void)
+{
+ if (!CONFIG_QEMU_HARDWARE)
+ return;
+
+ // check northbridge @ 00:00.0
+ u16 v = pci_config_readw(0, PCI_VENDOR_ID);
+ if (v == 0x0000 || v == 0xffff)
+ return;
+ u16 d = pci_config_readw(0, PCI_DEVICE_ID);
+ u16 sv = pci_config_readw(0, PCI_SUBSYSTEM_VENDOR_ID);
+ u16 sd = pci_config_readw(0, PCI_SUBSYSTEM_ID);
+
+ if (sv != 0x1af4 || /* Red Hat, Inc */
+ sd != 0x1100) /* Qemu virtual machine */
+ return;
+
+ PlatformRunningOn |= PF_QEMU;
+ switch (d) {
+ case 0x1237:
+ dprintf(1, "Running on QEMU (i440fx)\n");
+ break;
+ case 0x29c0:
+ dprintf(1, "Running on QEMU (q35)\n");
+ break;
+ default:
+ dprintf(1, "Running on QEMU (unknown nb: %04x:%04x)\n", v, d);
+ break;
+ }
+ kvm_detect();
+}
+
+void
+qemu_preinit(void)
+{
+ qemu_detect();
+
+ if (!CONFIG_QEMU)
+ return;
+
+ if (runningOnXen()) {
+ xen_ramsize_preinit();
+ return;
+ }
+
+ if (!runningOnQEMU()) {
+ dprintf(1, "Warning: No QEMU Northbridge found (isapc?)\n");
+ PlatformRunningOn |= PF_QEMU;
+ kvm_detect();
+ }
+
+ // On emulators, get memory size from nvram.
+ u32 rs = ((rtc_read(CMOS_MEM_EXTMEM2_LOW) << 16)
+ | (rtc_read(CMOS_MEM_EXTMEM2_HIGH) << 24));
+ if (rs)
+ rs += 16 * 1024 * 1024;
+ else
+ rs = (((rtc_read(CMOS_MEM_EXTMEM_LOW) << 10)
+ | (rtc_read(CMOS_MEM_EXTMEM_HIGH) << 18))
+ + 1 * 1024 * 1024);
+ RamSize = rs;
+ add_e820(0, rs, E820_RAM);
+
+ /* reserve 256KB BIOS area at the end of 4 GB */
+ add_e820(0xfffc0000, 256*1024, E820_RESERVED);
+
+ dprintf(1, "RamSize: 0x%08x [cmos]\n", RamSize);
+}
+
+void
+qemu_platform_setup(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ if (runningOnXen()) {
+ pci_probe_devices();
+ xen_hypercall_setup();
+ xen_biostable_setup();
+ return;
+ }
+
+ // Initialize pci
+ pci_setup();
+ smm_device_setup();
+ smm_setup();
+
+ // Initialize mtrr and smp
+ mtrr_setup();
+ smp_setup();
+
+ // Create bios tables
+ pirtable_setup();
+ mptable_setup();
+ smbios_setup();
+
+ if (CONFIG_FW_ROMFILE_LOAD) {
+ int loader_err;
+
+ dprintf(3, "load ACPI tables\n");
+
+ loader_err = romfile_loader_execute("etc/table-loader");
+
+ RsdpAddr = find_acpi_rsdp();
+
+ if (RsdpAddr)
+ return;
+
+ /* If present, loader should have installed an RSDP.
+ * Not installed? We might still be able to continue
+ * using the builtin RSDP.
+ */
+ if (!loader_err)
+ warn_internalerror();
+ }
+
+ acpi_setup();
+}
+
+
+/****************************************************************
+ * QEMU firmware config (fw_cfg) interface
+ ****************************************************************/
+
+// List of QEMU fw_cfg entries. DO NOT ADD MORE. (All new content
+// should be passed via the fw_cfg "file" interface.)
+#define QEMU_CFG_SIGNATURE 0x00
+#define QEMU_CFG_ID 0x01
+#define QEMU_CFG_UUID 0x02
+#define QEMU_CFG_NUMA 0x0d
+#define QEMU_CFG_BOOT_MENU 0x0e
+#define QEMU_CFG_MAX_CPUS 0x0f
+#define QEMU_CFG_FILE_DIR 0x19
+#define QEMU_CFG_ARCH_LOCAL 0x8000
+#define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0)
+#define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1)
+#define QEMU_CFG_IRQ0_OVERRIDE (QEMU_CFG_ARCH_LOCAL + 2)
+#define QEMU_CFG_E820_TABLE (QEMU_CFG_ARCH_LOCAL + 3)
+
+static void
+qemu_cfg_select(u16 f)
+{
+ outw(f, PORT_QEMU_CFG_CTL);
+}
+
+static void
+qemu_cfg_read(void *buf, int len)
+{
+ insb(PORT_QEMU_CFG_DATA, buf, len);
+}
+
+static void
+qemu_cfg_skip(int len)
+{
+ while (len--)
+ inb(PORT_QEMU_CFG_DATA);
+}
+
+static void
+qemu_cfg_read_entry(void *buf, int e, int len)
+{
+ qemu_cfg_select(e);
+ qemu_cfg_read(buf, len);
+}
+
+struct qemu_romfile_s {
+ struct romfile_s file;
+ int select, skip;
+};
+
+static int
+qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen)
+{
+ if (file->size > maxlen)
+ return -1;
+ struct qemu_romfile_s *qfile;
+ qfile = container_of(file, struct qemu_romfile_s, file);
+ qemu_cfg_select(qfile->select);
+ qemu_cfg_skip(qfile->skip);
+ qemu_cfg_read(dst, file->size);
+ return file->size;
+}
+
+static void
+qemu_romfile_add(char *name, int select, int skip, int size)
+{
+ struct qemu_romfile_s *qfile = malloc_tmp(sizeof(*qfile));
+ if (!qfile) {
+ warn_noalloc();
+ return;
+ }
+ memset(qfile, 0, sizeof(*qfile));
+ strtcpy(qfile->file.name, name, sizeof(qfile->file.name));
+ qfile->file.size = size;
+ qfile->select = select;
+ qfile->skip = skip;
+ qfile->file.copy = qemu_cfg_read_file;
+ romfile_add(&qfile->file);
+}
+
+struct e820_reservation {
+ u64 address;
+ u64 length;
+ u32 type;
+};
+
+#define SMBIOS_FIELD_ENTRY 0
+#define SMBIOS_TABLE_ENTRY 1
+
+struct qemu_smbios_header {
+ u16 length;
+ u8 headertype;
+ u8 tabletype;
+ u16 fieldoffset;
+} PACKED;
+
+static void
+qemu_cfg_e820(void)
+{
+ struct e820_reservation *table;
+ int i, size;
+
+ if (!CONFIG_QEMU)
+ return;
+
+ // "etc/e820" has both ram and reservations
+ table = romfile_loadfile("etc/e820", &size);
+ if (table) {
+ for (i = 0; i < size / sizeof(struct e820_reservation); i++) {
+ switch (table[i].type) {
+ case E820_RAM:
+ dprintf(1, "RamBlock: addr 0x%016llx len 0x%016llx [e820]\n",
+ table[i].address, table[i].length);
+ if (table[i].address < RamSize)
+ // ignore, preinit got it from cmos already and
+ // adding this again would ruin any reservations
+ // done so far
+ continue;
+ if (table[i].address < 0x100000000LL) {
+ // below 4g -- adjust RamSize to mark highest lowram addr
+ if (RamSize < table[i].address + table[i].length)
+ RamSize = table[i].address + table[i].length;
+ } else {
+ // above 4g -- adjust RamSizeOver4G to mark highest ram addr
+ if (0x100000000LL + RamSizeOver4G < table[i].address + table[i].length)
+ RamSizeOver4G = table[i].address + table[i].length - 0x100000000LL;
+ }
+ /* fall through */
+ case E820_RESERVED:
+ add_e820(table[i].address, table[i].length, table[i].type);
+ break;
+ default:
+ /*
+ * Qemu 1.7 uses RAM + RESERVED only. Ignore
+ * everything else, so we have the option to
+ * extend this in the future without breakage.
+ */
+ break;
+ }
+ }
+ return;
+ }
+
+ // QEMU_CFG_E820_TABLE has reservations only
+ u32 count32;
+ qemu_cfg_read_entry(&count32, QEMU_CFG_E820_TABLE, sizeof(count32));
+ if (count32) {
+ struct e820_reservation entry;
+ int i;
+ for (i = 0; i < count32; i++) {
+ qemu_cfg_read(&entry, sizeof(entry));
+ add_e820(entry.address, entry.length, entry.type);
+ }
+ } else if (runningOnKVM()) {
+ // Backwards compatibility - provide hard coded range.
+ // 4 pages before the bios, 3 pages for vmx tss pages, the
+ // other page for EPT real mode pagetable
+ add_e820(0xfffbc000, 4*4096, E820_RESERVED);
+ }
+
+ // Check for memory over 4Gig in cmos
+ u64 high = ((rtc_read(CMOS_MEM_HIGHMEM_LOW) << 16)
+ | ((u32)rtc_read(CMOS_MEM_HIGHMEM_MID) << 24)
+ | ((u64)rtc_read(CMOS_MEM_HIGHMEM_HIGH) << 32));
+ RamSizeOver4G = high;
+ add_e820(0x100000000ull, high, E820_RAM);
+ dprintf(1, "RamSizeOver4G: 0x%016llx [cmos]\n", RamSizeOver4G);
+}
+
+// Populate romfile entries for legacy fw_cfg ports (that predate the
+// "file" interface).
+static void
+qemu_cfg_legacy(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ // Misc config items.
+ qemu_romfile_add("etc/show-boot-menu", QEMU_CFG_BOOT_MENU, 0, 2);
+ qemu_romfile_add("etc/irq0-override", QEMU_CFG_IRQ0_OVERRIDE, 0, 1);
+ qemu_romfile_add("etc/max-cpus", QEMU_CFG_MAX_CPUS, 0, 2);
+
+ // NUMA data
+ u64 numacount;
+ qemu_cfg_read_entry(&numacount, QEMU_CFG_NUMA, sizeof(numacount));
+ int max_cpu = romfile_loadint("etc/max-cpus", 0);
+ qemu_romfile_add("etc/numa-cpu-map", QEMU_CFG_NUMA, sizeof(numacount)
+ , max_cpu*sizeof(u64));
+ qemu_romfile_add("etc/numa-nodes", QEMU_CFG_NUMA
+ , sizeof(numacount) + max_cpu*sizeof(u64)
+ , numacount*sizeof(u64));
+
+ // ACPI tables
+ char name[128];
+ u16 cnt;
+ qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
+ int i, offset = sizeof(cnt);
+ for (i = 0; i < cnt; i++) {
+ u16 len;
+ qemu_cfg_read(&len, sizeof(len));
+ offset += sizeof(len);
+ snprintf(name, sizeof(name), "acpi/table%d", i);
+ qemu_romfile_add(name, QEMU_CFG_ACPI_TABLES, offset, len);
+ qemu_cfg_skip(len);
+ offset += len;
+ }
+
+ // SMBIOS info
+ qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
+ offset = sizeof(cnt);
+ for (i = 0; i < cnt; i++) {
+ struct qemu_smbios_header header;
+ qemu_cfg_read(&header, sizeof(header));
+ if (header.headertype == SMBIOS_FIELD_ENTRY) {
+ snprintf(name, sizeof(name), "smbios/field%d-%d"
+ , header.tabletype, header.fieldoffset);
+ qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
+ , offset + sizeof(header)
+ , header.length - sizeof(header));
+ } else {
+ snprintf(name, sizeof(name), "smbios/table%d-%d"
+ , header.tabletype, i);
+ qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
+ , offset + 3, header.length - 3);
+ }
+ qemu_cfg_skip(header.length - sizeof(header));
+ offset += header.length;
+ }
+}
+
+struct QemuCfgFile {
+ u32 size; /* file size */
+ u16 select; /* write this to 0x510 to read it */
+ u16 reserved;
+ char name[56];
+};
+
+void qemu_cfg_init(void)
+{
+ if (!runningOnQEMU())
+ return;
+
+ // Detect fw_cfg interface.
+ qemu_cfg_select(QEMU_CFG_SIGNATURE);
+ char *sig = "QEMU";
+ int i;
+ for (i = 0; i < 4; i++)
+ if (inb(PORT_QEMU_CFG_DATA) != sig[i])
+ return;
+ dprintf(1, "Found QEMU fw_cfg\n");
+
+ // Populate romfiles for legacy fw_cfg entries
+ qemu_cfg_legacy();
+
+ // Load files found in the fw_cfg file directory
+ u32 count;
+ qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
+ count = be32_to_cpu(count);
+ u32 e;
+ for (e = 0; e < count; e++) {
+ struct QemuCfgFile qfile;
+ qemu_cfg_read(&qfile, sizeof(qfile));
+ qemu_romfile_add(qfile.name, be16_to_cpu(qfile.select)
+ , 0, be32_to_cpu(qfile.size));
+ }
+
+ qemu_cfg_e820();
+
+ if (romfile_find("etc/table-loader")) {
+ acpi_pm_base = 0x0600;
+ dprintf(1, "Moving pm_base to 0x%x\n", acpi_pm_base);
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/paravirt.h b/qemu/roms/seabios/src/fw/paravirt.h
new file mode 100644
index 000000000..95ffb92ad
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/paravirt.h
@@ -0,0 +1,37 @@
+#ifndef __PV_H
+#define __PV_H
+
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+
+// Types of paravirtualized platforms.
+#define PF_QEMU (1<<0)
+#define PF_XEN (1<<1)
+#define PF_KVM (1<<2)
+
+extern u32 RamSize;
+extern u64 RamSizeOver4G;
+extern int PlatformRunningOn;
+
+static inline int runningOnQEMU(void) {
+ return CONFIG_QEMU || (
+ CONFIG_QEMU_HARDWARE && GET_GLOBAL(PlatformRunningOn) & PF_QEMU);
+}
+static inline int runningOnXen(void) {
+ return CONFIG_XEN && GET_GLOBAL(PlatformRunningOn) & PF_XEN;
+}
+static inline int runningOnKVM(void) {
+ return CONFIG_QEMU && GET_GLOBAL(PlatformRunningOn) & PF_KVM;
+}
+
+// Common paravirt ports.
+#define PORT_SMI_CMD 0x00b2
+#define PORT_SMI_STATUS 0x00b3
+#define PORT_QEMU_CFG_CTL 0x0510
+#define PORT_QEMU_CFG_DATA 0x0511
+
+void qemu_preinit(void);
+void qemu_platform_setup(void);
+void qemu_cfg_init(void);
+
+#endif
diff --git a/qemu/roms/seabios/src/fw/pciinit.c b/qemu/roms/seabios/src/fw/pciinit.c
new file mode 100644
index 000000000..46ae7090e
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/pciinit.c
@@ -0,0 +1,954 @@
+// Initialize PCI devices (on emulators)
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "byteorder.h" // le64_to_cpu
+#include "config.h" // CONFIG_*
+#include "dev-q35.h" // Q35_HOST_BRIDGE_PCIEXBAR_ADDR
+#include "dev-piix.h" // PIIX_*
+#include "hw/ata.h" // PORT_ATA1_CMD_BASE
+#include "hw/pci.h" // pci_config_readl
+#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "hw/pci_regs.h" // PCI_COMMAND
+#include "list.h" // struct hlist_node
+#include "malloc.h" // free
+#include "memmap.h" // add_e820
+#include "output.h" // dprintf
+#include "paravirt.h" // RamSize
+#include "romfile.h" // romfile_loadint
+#include "string.h" // memset
+#include "util.h" // pci_setup
+#include "x86.h" // outb
+
+#define PCI_DEVICE_MEM_MIN (1<<12) // 4k == page size
+#define PCI_BRIDGE_MEM_MIN (1<<21) // 2M == hugepage size
+#define PCI_BRIDGE_IO_MIN 0x1000 // mandated by pci bridge spec
+
+static const char *region_type_name[] = {
+ [ PCI_REGION_TYPE_IO ] = "io",
+ [ PCI_REGION_TYPE_MEM ] = "mem",
+ [ PCI_REGION_TYPE_PREFMEM ] = "prefmem",
+};
+
+u64 pcimem_start = BUILD_PCIMEM_START;
+u64 pcimem_end = BUILD_PCIMEM_END;
+u64 pcimem64_start = BUILD_PCIMEM64_START;
+u64 pcimem64_end = BUILD_PCIMEM64_END;
+u64 pci_io_low_end = 0xa000;
+
+struct pci_region_entry {
+ struct pci_device *dev;
+ int bar;
+ u64 size;
+ u64 align;
+ int is64;
+ enum pci_region_type type;
+ struct hlist_node node;
+};
+
+struct pci_region {
+ /* pci region assignments */
+ u64 base;
+ struct hlist_head list;
+};
+
+struct pci_bus {
+ struct pci_region r[PCI_REGION_TYPE_COUNT];
+ struct pci_device *bus_dev;
+};
+
+static u32 pci_bar(struct pci_device *pci, int region_num)
+{
+ if (region_num != PCI_ROM_SLOT) {
+ return PCI_BASE_ADDRESS_0 + region_num * 4;
+ }
+
+#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
+ u8 type = pci->header_type & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
+ return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS;
+}
+
+static void
+pci_set_io_region_addr(struct pci_device *pci, int bar, u64 addr, int is64)
+{
+ u32 ofs = pci_bar(pci, bar);
+ pci_config_writel(pci->bdf, ofs, addr);
+ if (is64)
+ pci_config_writel(pci->bdf, ofs + 4, addr >> 32);
+}
+
+
+/****************************************************************
+ * Misc. device init
+ ****************************************************************/
+
+/* host irqs corresponding to PCI irqs A-D */
+const u8 pci_irqs[4] = {
+ 10, 10, 11, 11
+};
+
+static int dummy_pci_slot_get_irq(struct pci_device *pci, int pin)
+{
+ dprintf(1, "pci_slot_get_irq called with unknown routing\n");
+
+ return 0xff; /* PCI defined "unknown" or "no connection" for x86 */
+}
+
+static int (*pci_slot_get_irq)(struct pci_device *pci, int pin) =
+ dummy_pci_slot_get_irq;
+
+// Return the global irq number corresponding to a host bus device irq pin.
+static int piix_pci_slot_get_irq(struct pci_device *pci, int pin)
+{
+ int slot_addend = 0;
+
+ while (pci->parent != NULL) {
+ slot_addend += pci_bdf_to_dev(pci->bdf);
+ pci = pci->parent;
+ }
+ slot_addend += pci_bdf_to_dev(pci->bdf) - 1;
+ return pci_irqs[(pin - 1 + slot_addend) & 3];
+}
+
+static int mch_pci_slot_get_irq(struct pci_device *pci, int pin)
+{
+ int pin_addend = 0;
+ while (pci->parent != NULL) {
+ pin_addend += pci_bdf_to_dev(pci->bdf);
+ pci = pci->parent;
+ }
+ u8 slot = pci_bdf_to_dev(pci->bdf);
+ if (slot <= 24)
+ /* Slots 0-24 rotate slot:pin mapping similar to piix above, but
+ with a different starting index - see q35-acpi-dsdt.dsl */
+ return pci_irqs[(pin - 1 + pin_addend + slot) & 3];
+ /* Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H) */
+ return pci_irqs[(pin - 1 + pin_addend) & 3];
+}
+
+/* PIIX3/PIIX4 PCI to ISA bridge */
+static void piix_isa_bridge_setup(struct pci_device *pci, void *arg)
+{
+ int i, irq;
+ u8 elcr[2];
+
+ elcr[0] = 0x00;
+ elcr[1] = 0x00;
+ for (i = 0; i < 4; i++) {
+ irq = pci_irqs[i];
+ /* set to trigger level */
+ elcr[irq >> 3] |= (1 << (irq & 7));
+ /* activate irq remapping in PIIX */
+ pci_config_writeb(pci->bdf, 0x60 + i, irq);
+ }
+ outb(elcr[0], PIIX_PORT_ELCR1);
+ outb(elcr[1], PIIX_PORT_ELCR2);
+ dprintf(1, "PIIX3/PIIX4 init: elcr=%02x %02x\n", elcr[0], elcr[1]);
+}
+
+/* ICH9 LPC PCI to ISA bridge */
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */
+static void mch_isa_bridge_setup(struct pci_device *dev, void *arg)
+{
+ u16 bdf = dev->bdf;
+ int i, irq;
+ u8 elcr[2];
+
+ elcr[0] = 0x00;
+ elcr[1] = 0x00;
+
+ for (i = 0; i < 4; i++) {
+ irq = pci_irqs[i];
+ /* set to trigger level */
+ elcr[irq >> 3] |= (1 << (irq & 7));
+
+ /* activate irq remapping in LPC */
+
+ /* PIRQ[A-D] routing */
+ pci_config_writeb(bdf, ICH9_LPC_PIRQA_ROUT + i, irq);
+ /* PIRQ[E-H] routing */
+ pci_config_writeb(bdf, ICH9_LPC_PIRQE_ROUT + i, irq);
+ }
+ outb(elcr[0], ICH9_LPC_PORT_ELCR1);
+ outb(elcr[1], ICH9_LPC_PORT_ELCR2);
+ dprintf(1, "Q35 LPC init: elcr=%02x %02x\n", elcr[0], elcr[1]);
+
+ /* pm io base */
+ pci_config_writel(bdf, ICH9_LPC_PMBASE,
+ acpi_pm_base | ICH9_LPC_PMBASE_RTE);
+
+ /* acpi enable, SCI: IRQ9 000b = irq9*/
+ pci_config_writeb(bdf, ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_ACPI_EN);
+
+ acpi_pm1a_cnt = acpi_pm_base + 0x04;
+ pmtimer_setup(acpi_pm_base + 0x08);
+}
+
+static void storage_ide_setup(struct pci_device *pci, void *arg)
+{
+ /* IDE: we map it as in ISA mode */
+ pci_set_io_region_addr(pci, 0, PORT_ATA1_CMD_BASE, 0);
+ pci_set_io_region_addr(pci, 1, PORT_ATA1_CTRL_BASE, 0);
+ pci_set_io_region_addr(pci, 2, PORT_ATA2_CMD_BASE, 0);
+ pci_set_io_region_addr(pci, 3, PORT_ATA2_CTRL_BASE, 0);
+}
+
+/* PIIX3/PIIX4 IDE */
+static void piix_ide_setup(struct pci_device *pci, void *arg)
+{
+ u16 bdf = pci->bdf;
+ pci_config_writew(bdf, 0x40, 0x8000); // enable IDE0
+ pci_config_writew(bdf, 0x42, 0x8000); // enable IDE1
+}
+
+static void pic_ibm_setup(struct pci_device *pci, void *arg)
+{
+ /* PIC, IBM, MPIC & MPIC2 */
+ pci_set_io_region_addr(pci, 0, 0x80800000 + 0x00040000, 0);
+}
+
+static void apple_macio_setup(struct pci_device *pci, void *arg)
+{
+ /* macio bridge */
+ pci_set_io_region_addr(pci, 0, 0x80800000, 0);
+}
+
+static void piix4_pm_config_setup(u16 bdf)
+{
+ // acpi sci is hardwired to 9
+ pci_config_writeb(bdf, PCI_INTERRUPT_LINE, 9);
+
+ pci_config_writel(bdf, PIIX_PMBASE, acpi_pm_base | 1);
+ pci_config_writeb(bdf, PIIX_PMREGMISC, 0x01); /* enable PM io space */
+ pci_config_writel(bdf, PIIX_SMBHSTBASE, (acpi_pm_base + 0x100) | 1);
+ pci_config_writeb(bdf, PIIX_SMBHSTCFG, 0x09); /* enable SMBus io space */
+}
+
+static int PiixPmBDF = -1;
+
+/* PIIX4 Power Management device (for ACPI) */
+static void piix4_pm_setup(struct pci_device *pci, void *arg)
+{
+ PiixPmBDF = pci->bdf;
+ piix4_pm_config_setup(pci->bdf);
+
+ acpi_pm1a_cnt = acpi_pm_base + 0x04;
+ pmtimer_setup(acpi_pm_base + 0x08);
+}
+
+/* ICH9 SMBUS */
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_SMBUS */
+static void ich9_smbus_setup(struct pci_device *dev, void *arg)
+{
+ u16 bdf = dev->bdf;
+ /* map smbus into io space */
+ pci_config_writel(bdf, ICH9_SMB_SMB_BASE,
+ (acpi_pm_base + 0x100) | PCI_BASE_ADDRESS_SPACE_IO);
+
+ /* enable SMBus */
+ pci_config_writeb(bdf, ICH9_SMB_HOSTC, ICH9_SMB_HOSTC_HST_EN);
+}
+
+static const struct pci_device_id pci_device_tbl[] = {
+ /* PIIX3/PIIX4 PCI to ISA bridge */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0,
+ piix_isa_bridge_setup),
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
+ piix_isa_bridge_setup),
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC,
+ mch_isa_bridge_setup),
+
+ /* STORAGE IDE */
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1,
+ PCI_CLASS_STORAGE_IDE, piix_ide_setup),
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,
+ PCI_CLASS_STORAGE_IDE, piix_ide_setup),
+ PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE,
+ storage_ide_setup),
+
+ /* PIC, IBM, MIPC & MPIC2 */
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0x0046, PCI_CLASS_SYSTEM_PIC,
+ pic_ibm_setup),
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0xFFFF, PCI_CLASS_SYSTEM_PIC,
+ pic_ibm_setup),
+
+ /* PIIX4 Power Management device (for ACPI) */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+ piix4_pm_setup),
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_SMBUS,
+ ich9_smbus_setup),
+
+ /* 0xff00 */
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0017, 0xff00, apple_macio_setup),
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0022, 0xff00, apple_macio_setup),
+
+ PCI_DEVICE_END,
+};
+
+void pci_resume(void)
+{
+ if (!CONFIG_QEMU) {
+ return;
+ }
+
+ if (PiixPmBDF >= 0) {
+ piix4_pm_config_setup(PiixPmBDF);
+ }
+}
+
+static void pci_bios_init_device(struct pci_device *pci)
+{
+ u16 bdf = pci->bdf;
+ dprintf(1, "PCI: init bdf=%02x:%02x.%x id=%04x:%04x\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf)
+ , pci->vendor, pci->device);
+
+ /* map the interrupt */
+ int pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
+ if (pin != 0)
+ pci_config_writeb(bdf, PCI_INTERRUPT_LINE, pci_slot_get_irq(pci, pin));
+
+ pci_init_device(pci_device_tbl, pci, NULL);
+
+ /* enable memory mappings */
+ pci_config_maskw(bdf, PCI_COMMAND, 0,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_SERR);
+}
+
+static void pci_bios_init_devices(void)
+{
+ struct pci_device *pci;
+ foreachpci(pci) {
+ pci_bios_init_device(pci);
+ }
+}
+
+static void pci_enable_default_vga(void)
+{
+ struct pci_device *pci;
+
+ foreachpci(pci) {
+ if (is_pci_vga(pci)) {
+ dprintf(1, "PCI: Using %02x:%02x.%x for primary VGA\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ pci_bdf_to_fn(pci->bdf));
+ return;
+ }
+ }
+
+ pci = pci_find_class(PCI_CLASS_DISPLAY_VGA);
+ if (!pci) {
+ dprintf(1, "PCI: No VGA devices found\n");
+ return;
+ }
+
+ dprintf(1, "PCI: Enabling %02x:%02x.%x for primary VGA\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ pci_bdf_to_fn(pci->bdf));
+
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+ while (pci->parent) {
+ pci = pci->parent;
+
+ dprintf(1, "PCI: Setting VGA enable on bridge %02x:%02x.%x\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ pci_bdf_to_fn(pci->bdf));
+
+ pci_config_maskw(pci->bdf, PCI_BRIDGE_CONTROL, 0, PCI_BRIDGE_CTL_VGA);
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+ }
+}
+
+/****************************************************************
+ * Platform device initialization
+ ****************************************************************/
+
+static void i440fx_mem_addr_setup(struct pci_device *dev, void *arg)
+{
+ if (RamSize <= 0x80000000)
+ pcimem_start = 0x80000000;
+ else if (RamSize <= 0xc0000000)
+ pcimem_start = 0xc0000000;
+
+ pci_slot_get_irq = piix_pci_slot_get_irq;
+}
+
+static void mch_mem_addr_setup(struct pci_device *dev, void *arg)
+{
+ u64 addr = Q35_HOST_BRIDGE_PCIEXBAR_ADDR;
+ u32 size = Q35_HOST_BRIDGE_PCIEXBAR_SIZE;
+
+ /* setup mmconfig */
+ u16 bdf = dev->bdf;
+ u32 upper = addr >> 32;
+ u32 lower = (addr & 0xffffffff) | Q35_HOST_BRIDGE_PCIEXBAREN;
+ pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, 0);
+ pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR + 4, upper);
+ pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, lower);
+ add_e820(addr, size, E820_RESERVED);
+
+ /* setup pci i/o window (above mmconfig) */
+ pcimem_start = addr + size;
+
+ pci_slot_get_irq = mch_pci_slot_get_irq;
+
+ /* setup io address space */
+ if (acpi_pm_base < 0x1000)
+ pci_io_low_end = 0x10000;
+ else
+ pci_io_low_end = acpi_pm_base;
+}
+
+static const struct pci_device_id pci_platform_tbl[] = {
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
+ i440fx_mem_addr_setup),
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH,
+ mch_mem_addr_setup),
+ PCI_DEVICE_END
+};
+
+static void pci_bios_init_platform(void)
+{
+ struct pci_device *pci;
+ foreachpci(pci) {
+ pci_init_device(pci_platform_tbl, pci, NULL);
+ }
+}
+
+
+/****************************************************************
+ * Bus initialization
+ ****************************************************************/
+
+static void
+pci_bios_init_bus_rec(int bus, u8 *pci_bus)
+{
+ int bdf;
+ u16 class;
+
+ dprintf(1, "PCI: %s bus = 0x%x\n", __func__, bus);
+
+ /* prevent accidental access to unintended devices */
+ foreachbdf(bdf, bus) {
+ class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
+ if (class == PCI_CLASS_BRIDGE_PCI) {
+ pci_config_writeb(bdf, PCI_SECONDARY_BUS, 255);
+ pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 0);
+ }
+ }
+
+ foreachbdf(bdf, bus) {
+ class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
+ if (class != PCI_CLASS_BRIDGE_PCI) {
+ continue;
+ }
+ dprintf(1, "PCI: %s bdf = 0x%x\n", __func__, bdf);
+
+ u8 pribus = pci_config_readb(bdf, PCI_PRIMARY_BUS);
+ if (pribus != bus) {
+ dprintf(1, "PCI: primary bus = 0x%x -> 0x%x\n", pribus, bus);
+ pci_config_writeb(bdf, PCI_PRIMARY_BUS, bus);
+ } else {
+ dprintf(1, "PCI: primary bus = 0x%x\n", pribus);
+ }
+
+ u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
+ (*pci_bus)++;
+ if (*pci_bus != secbus) {
+ dprintf(1, "PCI: secondary bus = 0x%x -> 0x%x\n",
+ secbus, *pci_bus);
+ secbus = *pci_bus;
+ pci_config_writeb(bdf, PCI_SECONDARY_BUS, secbus);
+ } else {
+ dprintf(1, "PCI: secondary bus = 0x%x\n", secbus);
+ }
+
+ /* set to max for access to all subordinate buses.
+ later set it to accurate value */
+ u8 subbus = pci_config_readb(bdf, PCI_SUBORDINATE_BUS);
+ pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 255);
+
+ pci_bios_init_bus_rec(secbus, pci_bus);
+
+ if (subbus != *pci_bus) {
+ dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n",
+ subbus, *pci_bus);
+ subbus = *pci_bus;
+ } else {
+ dprintf(1, "PCI: subordinate bus = 0x%x\n", subbus);
+ }
+ pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, subbus);
+ }
+}
+
+static void
+pci_bios_init_bus(void)
+{
+ u8 extraroots = romfile_loadint("etc/extra-pci-roots", 0);
+ u8 pci_bus = 0;
+
+ pci_bios_init_bus_rec(0 /* host bus */, &pci_bus);
+
+ if (extraroots) {
+ while (pci_bus < 0xff) {
+ pci_bus++;
+ pci_bios_init_bus_rec(pci_bus, &pci_bus);
+ }
+ }
+}
+
+
+/****************************************************************
+ * Bus sizing
+ ****************************************************************/
+
+static void
+pci_bios_get_bar(struct pci_device *pci, int bar,
+ int *ptype, u64 *psize, int *pis64)
+{
+ u32 ofs = pci_bar(pci, bar);
+ u16 bdf = pci->bdf;
+ u32 old = pci_config_readl(bdf, ofs);
+ int is64 = 0, type = PCI_REGION_TYPE_MEM;
+ u64 mask;
+
+ if (bar == PCI_ROM_SLOT) {
+ mask = PCI_ROM_ADDRESS_MASK;
+ pci_config_writel(bdf, ofs, mask);
+ } else {
+ if (old & PCI_BASE_ADDRESS_SPACE_IO) {
+ mask = PCI_BASE_ADDRESS_IO_MASK;
+ type = PCI_REGION_TYPE_IO;
+ } else {
+ mask = PCI_BASE_ADDRESS_MEM_MASK;
+ if (old & PCI_BASE_ADDRESS_MEM_PREFETCH)
+ type = PCI_REGION_TYPE_PREFMEM;
+ is64 = ((old & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
+ == PCI_BASE_ADDRESS_MEM_TYPE_64);
+ }
+ pci_config_writel(bdf, ofs, ~0);
+ }
+ u64 val = pci_config_readl(bdf, ofs);
+ pci_config_writel(bdf, ofs, old);
+ if (is64) {
+ u32 hold = pci_config_readl(bdf, ofs + 4);
+ pci_config_writel(bdf, ofs + 4, ~0);
+ u32 high = pci_config_readl(bdf, ofs + 4);
+ pci_config_writel(bdf, ofs + 4, hold);
+ val |= ((u64)high << 32);
+ mask |= ((u64)0xffffffff << 32);
+ *psize = (~(val & mask)) + 1;
+ } else {
+ *psize = ((~(val & mask)) + 1) & 0xffffffff;
+ }
+ *ptype = type;
+ *pis64 = is64;
+}
+
+static int pci_bios_bridge_region_is64(struct pci_region *r,
+ struct pci_device *pci, int type)
+{
+ if (type != PCI_REGION_TYPE_PREFMEM)
+ return 0;
+ u32 pmem = pci_config_readl(pci->bdf, PCI_PREF_MEMORY_BASE);
+ if (!pmem) {
+ pci_config_writel(pci->bdf, PCI_PREF_MEMORY_BASE, 0xfff0fff0);
+ pmem = pci_config_readl(pci->bdf, PCI_PREF_MEMORY_BASE);
+ pci_config_writel(pci->bdf, PCI_PREF_MEMORY_BASE, 0x0);
+ }
+ if ((pmem & PCI_PREF_RANGE_TYPE_MASK) != PCI_PREF_RANGE_TYPE_64)
+ return 0;
+ struct pci_region_entry *entry;
+ hlist_for_each_entry(entry, &r->list, node) {
+ if (!entry->is64)
+ return 0;
+ }
+ return 1;
+}
+
+static u64 pci_region_align(struct pci_region *r)
+{
+ struct pci_region_entry *entry;
+ hlist_for_each_entry(entry, &r->list, node) {
+ // The first entry in the sorted list has the largest alignment
+ return entry->align;
+ }
+ return 1;
+}
+
+static u64 pci_region_sum(struct pci_region *r)
+{
+ u64 sum = 0;
+ struct pci_region_entry *entry;
+ hlist_for_each_entry(entry, &r->list, node) {
+ sum += entry->size;
+ }
+ return sum;
+}
+
+static void pci_region_migrate_64bit_entries(struct pci_region *from,
+ struct pci_region *to)
+{
+ struct hlist_node *n, **last = &to->list.first;
+ struct pci_region_entry *entry;
+ hlist_for_each_entry_safe(entry, n, &from->list, node) {
+ if (!entry->is64)
+ continue;
+ if (entry->dev->class == PCI_CLASS_SERIAL_USB)
+ continue;
+ // Move from source list to destination list.
+ hlist_del(&entry->node);
+ hlist_add(&entry->node, last);
+ last = &entry->node.next;
+ }
+}
+
+static struct pci_region_entry *
+pci_region_create_entry(struct pci_bus *bus, struct pci_device *dev,
+ int bar, u64 size, u64 align, int type, int is64)
+{
+ struct pci_region_entry *entry = malloc_tmp(sizeof(*entry));
+ if (!entry) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(entry, 0, sizeof(*entry));
+ entry->dev = dev;
+ entry->bar = bar;
+ entry->size = size;
+ entry->align = align;
+ entry->is64 = is64;
+ entry->type = type;
+ // Insert into list in sorted order.
+ struct hlist_node **pprev;
+ struct pci_region_entry *pos;
+ hlist_for_each_entry_pprev(pos, pprev, &bus->r[type].list, node) {
+ if (pos->align < align || (pos->align == align && pos->size < size))
+ break;
+ }
+ hlist_add(&entry->node, pprev);
+ return entry;
+}
+
+static int pci_bus_hotplug_support(struct pci_bus *bus)
+{
+ u8 pcie_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_EXP);
+ u8 shpc_cap;
+
+ if (pcie_cap) {
+ u16 pcie_flags = pci_config_readw(bus->bus_dev->bdf,
+ pcie_cap + PCI_EXP_FLAGS);
+ u8 port_type = ((pcie_flags & PCI_EXP_FLAGS_TYPE) >>
+ (__builtin_ffs(PCI_EXP_FLAGS_TYPE) - 1));
+ u8 downstream_port = (port_type == PCI_EXP_TYPE_DOWNSTREAM) ||
+ (port_type == PCI_EXP_TYPE_ROOT_PORT);
+ /*
+ * PCI Express SPEC, 7.8.2:
+ * Slot Implemented – When Set, this bit indicates that the Link
+ * HwInit associated with this Port is connected to a slot (as
+ * compared to being connected to a system-integrated device or
+ * being disabled).
+ * This bit is valid for Downstream Ports. This bit is undefined
+ * for Upstream Ports.
+ */
+ u16 slot_implemented = pcie_flags & PCI_EXP_FLAGS_SLOT;
+
+ return downstream_port && slot_implemented;
+ }
+
+ shpc_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_SHPC);
+ return !!shpc_cap;
+}
+
+static int pci_bios_check_devices(struct pci_bus *busses)
+{
+ dprintf(1, "PCI: check devices\n");
+
+ // Calculate resources needed for regular (non-bus) devices.
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->class == PCI_CLASS_BRIDGE_PCI)
+ busses[pci->secondary_bus].bus_dev = pci;
+
+ struct pci_bus *bus = &busses[pci_bdf_to_bus(pci->bdf)];
+ if (!bus->bus_dev)
+ /*
+ * Resources for all root busses go in busses[0]
+ */
+ bus = &busses[0];
+ int i;
+ for (i = 0; i < PCI_NUM_REGIONS; i++) {
+ if ((pci->class == PCI_CLASS_BRIDGE_PCI) &&
+ (i >= PCI_BRIDGE_NUM_REGIONS && i < PCI_ROM_SLOT))
+ continue;
+ int type, is64;
+ u64 size;
+ pci_bios_get_bar(pci, i, &type, &size, &is64);
+ if (size == 0)
+ continue;
+
+ if (type != PCI_REGION_TYPE_IO && size < PCI_DEVICE_MEM_MIN)
+ size = PCI_DEVICE_MEM_MIN;
+ struct pci_region_entry *entry = pci_region_create_entry(
+ bus, pci, i, size, size, type, is64);
+ if (!entry)
+ return -1;
+
+ if (is64)
+ i++;
+ }
+ }
+
+ // Propagate required bus resources to parent busses.
+ int secondary_bus;
+ for (secondary_bus=MaxPCIBus; secondary_bus>0; secondary_bus--) {
+ struct pci_bus *s = &busses[secondary_bus];
+ if (!s->bus_dev)
+ continue;
+ struct pci_bus *parent = &busses[pci_bdf_to_bus(s->bus_dev->bdf)];
+ if (!parent->bus_dev)
+ /*
+ * Resources for all root busses go in busses[0]
+ */
+ parent = &busses[0];
+ int type;
+ int hotplug_support = pci_bus_hotplug_support(s);
+ for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
+ u64 align = (type == PCI_REGION_TYPE_IO) ?
+ PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN;
+ if (!pci_bridge_has_region(s->bus_dev, type))
+ continue;
+ if (pci_region_align(&s->r[type]) > align)
+ align = pci_region_align(&s->r[type]);
+ u64 sum = pci_region_sum(&s->r[type]);
+ if (!sum && hotplug_support)
+ sum = align; /* reserve min size for hot-plug */
+ u64 size = ALIGN(sum, align);
+ int is64 = pci_bios_bridge_region_is64(&s->r[type],
+ s->bus_dev, type);
+ // entry->bar is -1 if the entry represents a bridge region
+ struct pci_region_entry *entry = pci_region_create_entry(
+ parent, s->bus_dev, -1, size, align, type, is64);
+ if (!entry)
+ return -1;
+ dprintf(1, "PCI: secondary bus %d size %08llx type %s\n",
+ entry->dev->secondary_bus, size,
+ region_type_name[entry->type]);
+ }
+ }
+ return 0;
+}
+
+
+/****************************************************************
+ * BAR assignment
+ ****************************************************************/
+
+// Setup region bases (given the regions' size and alignment)
+static int pci_bios_init_root_regions_io(struct pci_bus *bus)
+{
+ /*
+ * QEMU I/O address space usage:
+ * 0000 - 0fff legacy isa, pci config, pci root bus, ...
+ * 1000 - 9fff free
+ * a000 - afff hotplug (cpu, pci via acpi, i440fx/piix only)
+ * b000 - bfff power management (PORT_ACPI_PM_BASE)
+ * [ qemu 1.4+ implements pci config registers
+ * properly so guests can place the registers
+ * where they want, on older versions its fixed ]
+ * c000 - ffff free, traditionally used for pci io
+ */
+ struct pci_region *r_io = &bus->r[PCI_REGION_TYPE_IO];
+ u64 sum = pci_region_sum(r_io);
+ if (sum < 0x4000) {
+ /* traditional region is big enougth, use it */
+ r_io->base = 0xc000;
+ } else if (sum < pci_io_low_end - 0x1000) {
+ /* use the larger region at 0x1000 */
+ r_io->base = 0x1000;
+ } else {
+ /* not enouth io address space -> error out */
+ return -1;
+ }
+ dprintf(1, "PCI: IO: %4llx - %4llx\n", r_io->base, r_io->base + sum - 1);
+ return 0;
+}
+
+static int pci_bios_init_root_regions_mem(struct pci_bus *bus)
+{
+ struct pci_region *r_end = &bus->r[PCI_REGION_TYPE_PREFMEM];
+ struct pci_region *r_start = &bus->r[PCI_REGION_TYPE_MEM];
+
+ if (pci_region_align(r_start) < pci_region_align(r_end)) {
+ // Swap regions to improve alignment.
+ r_end = r_start;
+ r_start = &bus->r[PCI_REGION_TYPE_PREFMEM];
+ }
+ u64 sum = pci_region_sum(r_end);
+ u64 align = pci_region_align(r_end);
+ r_end->base = ALIGN_DOWN((pcimem_end - sum), align);
+ sum = pci_region_sum(r_start);
+ align = pci_region_align(r_start);
+ r_start->base = ALIGN_DOWN((r_end->base - sum), align);
+
+ if ((r_start->base < pcimem_start) ||
+ (r_start->base > pcimem_end))
+ // Memory range requested is larger than available.
+ return -1;
+ return 0;
+}
+
+#define PCI_IO_SHIFT 8
+#define PCI_MEMORY_SHIFT 16
+#define PCI_PREF_MEMORY_SHIFT 16
+
+static void
+pci_region_map_one_entry(struct pci_region_entry *entry, u64 addr)
+{
+ u16 bdf = entry->dev->bdf;
+ if (entry->bar >= 0) {
+ dprintf(1, "PCI: map device bdf=%02x:%02x.%x"
+ " bar %d, addr %08llx, size %08llx [%s]\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf),
+ entry->bar, addr, entry->size, region_type_name[entry->type]);
+
+ pci_set_io_region_addr(entry->dev, entry->bar, addr, entry->is64);
+ return;
+ }
+
+ u64 limit = addr + entry->size - 1;
+ if (entry->type == PCI_REGION_TYPE_IO) {
+ pci_config_writeb(bdf, PCI_IO_BASE, addr >> PCI_IO_SHIFT);
+ pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0);
+ pci_config_writeb(bdf, PCI_IO_LIMIT, limit >> PCI_IO_SHIFT);
+ pci_config_writew(bdf, PCI_IO_LIMIT_UPPER16, 0);
+ }
+ if (entry->type == PCI_REGION_TYPE_MEM) {
+ pci_config_writew(bdf, PCI_MEMORY_BASE, addr >> PCI_MEMORY_SHIFT);
+ pci_config_writew(bdf, PCI_MEMORY_LIMIT, limit >> PCI_MEMORY_SHIFT);
+ }
+ if (entry->type == PCI_REGION_TYPE_PREFMEM) {
+ pci_config_writew(bdf, PCI_PREF_MEMORY_BASE, addr >> PCI_PREF_MEMORY_SHIFT);
+ pci_config_writew(bdf, PCI_PREF_MEMORY_LIMIT, limit >> PCI_PREF_MEMORY_SHIFT);
+ pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, addr >> 32);
+ pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, limit >> 32);
+ }
+}
+
+static void pci_region_map_entries(struct pci_bus *busses, struct pci_region *r)
+{
+ struct hlist_node *n;
+ struct pci_region_entry *entry;
+ hlist_for_each_entry_safe(entry, n, &r->list, node) {
+ u64 addr = r->base;
+ r->base += entry->size;
+ if (entry->bar == -1)
+ // Update bus base address if entry is a bridge region
+ busses[entry->dev->secondary_bus].r[entry->type].base = addr;
+ pci_region_map_one_entry(entry, addr);
+ hlist_del(&entry->node);
+ free(entry);
+ }
+}
+
+static void pci_bios_map_devices(struct pci_bus *busses)
+{
+ if (pci_bios_init_root_regions_io(busses))
+ panic("PCI: out of I/O address space\n");
+
+ dprintf(1, "PCI: 32: %016llx - %016llx\n", pcimem_start, pcimem_end);
+ if (pci_bios_init_root_regions_mem(busses)) {
+ struct pci_region r64_mem, r64_pref;
+ r64_mem.list.first = NULL;
+ r64_pref.list.first = NULL;
+ pci_region_migrate_64bit_entries(&busses[0].r[PCI_REGION_TYPE_MEM],
+ &r64_mem);
+ pci_region_migrate_64bit_entries(&busses[0].r[PCI_REGION_TYPE_PREFMEM],
+ &r64_pref);
+
+ if (pci_bios_init_root_regions_mem(busses))
+ panic("PCI: out of 32bit address space\n");
+
+ u64 sum_mem = pci_region_sum(&r64_mem);
+ u64 sum_pref = pci_region_sum(&r64_pref);
+ u64 align_mem = pci_region_align(&r64_mem);
+ u64 align_pref = pci_region_align(&r64_pref);
+
+ r64_mem.base = le64_to_cpu(romfile_loadint("etc/reserved-memory-end", 0));
+ if (r64_mem.base < 0x100000000LL + RamSizeOver4G)
+ r64_mem.base = 0x100000000LL + RamSizeOver4G;
+ r64_mem.base = ALIGN(r64_mem.base, align_mem);
+ r64_mem.base = ALIGN(r64_mem.base, (1LL<<30)); // 1G hugepage
+ r64_pref.base = r64_mem.base + sum_mem;
+ r64_pref.base = ALIGN(r64_pref.base, align_pref);
+ r64_pref.base = ALIGN(r64_pref.base, (1LL<<30)); // 1G hugepage
+ pcimem64_start = r64_mem.base;
+ pcimem64_end = r64_pref.base + sum_pref;
+ pcimem64_end = ALIGN(pcimem64_end, (1LL<<30)); // 1G hugepage
+ dprintf(1, "PCI: 64: %016llx - %016llx\n", pcimem64_start, pcimem64_end);
+
+ pci_region_map_entries(busses, &r64_mem);
+ pci_region_map_entries(busses, &r64_pref);
+ } else {
+ // no bars mapped high -> drop 64bit window (see dsdt)
+ pcimem64_start = 0;
+ }
+ // Map regions on each device.
+ int bus;
+ for (bus = 0; bus<=MaxPCIBus; bus++) {
+ int type;
+ for (type = 0; type < PCI_REGION_TYPE_COUNT; type++)
+ pci_region_map_entries(busses, &busses[bus].r[type]);
+ }
+}
+
+
+/****************************************************************
+ * Main setup code
+ ****************************************************************/
+
+void
+pci_setup(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ dprintf(3, "pci setup\n");
+
+ dprintf(1, "=== PCI bus & bridge init ===\n");
+ if (pci_probe_host() != 0) {
+ return;
+ }
+ pci_bios_init_bus();
+
+ dprintf(1, "=== PCI device probing ===\n");
+ pci_probe_devices();
+
+ pcimem_start = RamSize;
+ pci_bios_init_platform();
+
+ dprintf(1, "=== PCI new allocation pass #1 ===\n");
+ struct pci_bus *busses = malloc_tmp(sizeof(*busses) * (MaxPCIBus + 1));
+ if (!busses) {
+ warn_noalloc();
+ return;
+ }
+ memset(busses, 0, sizeof(*busses) * (MaxPCIBus + 1));
+ if (pci_bios_check_devices(busses))
+ return;
+
+ dprintf(1, "=== PCI new allocation pass #2 ===\n");
+ pci_bios_map_devices(busses);
+
+ pci_bios_init_devices();
+
+ free(busses);
+
+ pci_enable_default_vga();
+}
diff --git a/qemu/roms/seabios/src/fw/pirtable.c b/qemu/roms/seabios/src/fw/pirtable.c
new file mode 100644
index 000000000..a49440808
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/pirtable.c
@@ -0,0 +1,103 @@
+// PIR table generation (for emulators)
+// DO NOT ADD NEW FEATURES HERE. (See paravirt.c / biostables.c instead.)
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "output.h" // dprintf
+#include "std/pirtable.h" // struct pir_header
+#include "string.h" // checksum
+#include "util.h" // PirAddr
+
+struct pir_table {
+ struct pir_header pir;
+ struct pir_slot slots[6];
+} PACKED;
+
+static struct pir_table PIR_TABLE = {
+ .pir = {
+ .version = 0x0100,
+ .size = sizeof(struct pir_table),
+ .router_devfunc = 0x08,
+ .compatible_devid = 0x122e8086,
+ },
+ .slots = {
+ {
+ // first slot entry PCI-to-ISA (embedded)
+ .dev = 1<<3,
+ .links = {
+ {.link = 0x60, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x61, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 0, // embedded
+ }, {
+ // second slot entry: 1st PCI slot
+ .dev = 2<<3,
+ .links = {
+ {.link = 0x61, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x60, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 1,
+ }, {
+ // third slot entry: 2nd PCI slot
+ .dev = 3<<3,
+ .links = {
+ {.link = 0x62, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x60, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x61, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 2,
+ }, {
+ // 4th slot entry: 3rd PCI slot
+ .dev = 4<<3,
+ .links = {
+ {.link = 0x63, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x60, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x61, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 3,
+ }, {
+ // 5th slot entry: 4rd PCI slot
+ .dev = 5<<3,
+ .links = {
+ {.link = 0x60, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x61, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 4,
+ }, {
+ // 6th slot entry: 5rd PCI slot
+ .dev = 6<<3,
+ .links = {
+ {.link = 0x61, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x60, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 5,
+ },
+ }
+};
+
+void
+pirtable_setup(void)
+{
+ if (! CONFIG_PIRTABLE)
+ return;
+
+ dprintf(3, "init PIR table\n");
+
+ PIR_TABLE.pir.signature = PIR_SIGNATURE;
+ PIR_TABLE.pir.checksum -= checksum(&PIR_TABLE, sizeof(PIR_TABLE));
+ copy_pir(&PIR_TABLE);
+}
diff --git a/qemu/roms/seabios/src/fw/q35-acpi-dsdt.dsl b/qemu/roms/seabios/src/fw/q35-acpi-dsdt.dsl
new file mode 100644
index 000000000..5dec54146
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/q35-acpi-dsdt.dsl
@@ -0,0 +1,450 @@
+/*
+ * Bochs/QEMU ACPI DSDT ASL definition
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/*
+ * Copyright (c) 2010 Isaku Yamahata
+ * yamahata at valinux co jp
+ * Based on acpi-dsdt.dsl, but heavily modified for q35 chipset.
+ */
+
+DefinitionBlock (
+ "q35-acpi-dsdt.aml",// Output Filename
+ "DSDT", // Signature
+ 0x01, // DSDT Compliance Revision
+ "BXPC", // OEMID
+ "BXDSDT", // TABLE ID
+ 0x2 // OEM Revision
+ )
+{
+
+#include "acpi-dsdt-dbug.dsl"
+
+ Scope(\_SB) {
+ OperationRegion(PCST, SystemIO, 0xae00, 0x0c)
+ OperationRegion(PCSB, SystemIO, 0xae0c, 0x01)
+ Field(PCSB, AnyAcc, NoLock, WriteAsZeros) {
+ PCIB, 8,
+ }
+ }
+
+
+/****************************************************************
+ * PCI Bus definition
+ ****************************************************************/
+
+ Scope(\_SB) {
+ Device(PCI0) {
+ Name(_HID, EisaId("PNP0A08"))
+ Name(_CID, EisaId("PNP0A03"))
+ Name(_ADR, 0x00)
+ Name(_UID, 1)
+
+ // _OSC: based on sample of ACPI3.0b spec
+ Name(SUPP, 0) // PCI _OSC Support Field value
+ Name(CTRL, 0) // PCI _OSC Control Field value
+ Method(_OSC, 4) {
+ // Create DWORD-addressable fields from the Capabilities Buffer
+ CreateDWordField(Arg3, 0, CDW1)
+
+ // Check for proper UUID
+ If (LEqual(Arg0, ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766"))) {
+ // Create DWORD-addressable fields from the Capabilities Buffer
+ CreateDWordField(Arg3, 4, CDW2)
+ CreateDWordField(Arg3, 8, CDW3)
+
+ // Save Capabilities DWORD2 & 3
+ Store(CDW2, SUPP)
+ Store(CDW3, CTRL)
+
+ // Always allow native PME, AER (no dependencies)
+ // Never allow SHPC (no SHPC controller in this system)
+ And(CTRL, 0x1D, CTRL)
+
+#if 0 // For now, nothing to do
+ If (Not(And(CDW1, 1))) { // Query flag clear?
+ // Disable GPEs for features granted native control.
+ If (And(CTRL, 0x01)) { // Hot plug control granted?
+ Store(0, HPCE) // clear the hot plug SCI enable bit
+ Store(1, HPCS) // clear the hot plug SCI status bit
+ }
+ If (And(CTRL, 0x04)) { // PME control granted?
+ Store(0, PMCE) // clear the PME SCI enable bit
+ Store(1, PMCS) // clear the PME SCI status bit
+ }
+ If (And(CTRL, 0x10)) { // OS restoring PCI Express cap structure?
+ // Set status to not restore PCI Express cap structure
+ // upon resume from S3
+ Store(1, S3CR)
+ }
+ }
+#endif
+ If (LNotEqual(Arg1, One)) {
+ // Unknown revision
+ Or(CDW1, 0x08, CDW1)
+ }
+ If (LNotEqual(CDW3, CTRL)) {
+ // Capabilities bits were masked
+ Or(CDW1, 0x10, CDW1)
+ }
+ // Update DWORD3 in the buffer
+ Store(CTRL, CDW3)
+ } Else {
+ Or(CDW1, 4, CDW1) // Unrecognized UUID
+ }
+ Return (Arg3)
+ }
+ }
+ }
+
+#include "acpi-dsdt-pci-crs.dsl"
+#include "acpi-dsdt-hpet.dsl"
+
+
+/****************************************************************
+ * VGA
+ ****************************************************************/
+
+ Scope(\_SB.PCI0) {
+ Device(VGA) {
+ Name(_ADR, 0x00010000)
+ Method(_S1D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S2D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ Method(_S3D, 0, NotSerialized) {
+ Return (0x00)
+ }
+ }
+ }
+
+
+/****************************************************************
+ * LPC ISA bridge
+ ****************************************************************/
+
+ Scope(\_SB.PCI0) {
+ /* PCI D31:f0 LPC ISA bridge */
+ Device(ISA) {
+ /* PCI D31:f0 */
+ Name(_ADR, 0x001f0000)
+
+ /* ICH9 PCI to ISA irq remapping */
+ OperationRegion(PIRQ, PCI_Config, 0x60, 0x0C)
+
+ OperationRegion(LPCD, PCI_Config, 0x80, 0x2)
+ Field(LPCD, AnyAcc, NoLock, Preserve) {
+ COMA, 3,
+ , 1,
+ COMB, 3,
+
+ Offset(0x01),
+ LPTD, 2,
+ , 2,
+ FDCD, 2
+ }
+ OperationRegion(LPCE, PCI_Config, 0x82, 0x2)
+ Field(LPCE, AnyAcc, NoLock, Preserve) {
+ CAEN, 1,
+ CBEN, 1,
+ LPEN, 1,
+ FDEN, 1
+ }
+ }
+ }
+
+#include "acpi-dsdt-isa.dsl"
+
+
+/****************************************************************
+ * PCI IRQs
+ ****************************************************************/
+
+ /* Zero => PIC mode, One => APIC Mode */
+ Name(\PICF, Zero)
+ Method(\_PIC, 1, NotSerialized) {
+ Store(Arg0, \PICF)
+ }
+
+ Scope(\_SB) {
+ Scope(PCI0) {
+#define prt_slot_lnk(nr, lnk0, lnk1, lnk2, lnk3) \
+ Package() { nr##ffff, 0, lnk0, 0 }, \
+ Package() { nr##ffff, 1, lnk1, 0 }, \
+ Package() { nr##ffff, 2, lnk2, 0 }, \
+ Package() { nr##ffff, 3, lnk3, 0 }
+
+#define prt_slot_lnkA(nr) prt_slot_lnk(nr, LNKA, LNKB, LNKC, LNKD)
+#define prt_slot_lnkB(nr) prt_slot_lnk(nr, LNKB, LNKC, LNKD, LNKA)
+#define prt_slot_lnkC(nr) prt_slot_lnk(nr, LNKC, LNKD, LNKA, LNKB)
+#define prt_slot_lnkD(nr) prt_slot_lnk(nr, LNKD, LNKA, LNKB, LNKC)
+
+#define prt_slot_lnkE(nr) prt_slot_lnk(nr, LNKE, LNKF, LNKG, LNKH)
+#define prt_slot_lnkF(nr) prt_slot_lnk(nr, LNKF, LNKG, LNKH, LNKE)
+#define prt_slot_lnkG(nr) prt_slot_lnk(nr, LNKG, LNKH, LNKE, LNKF)
+#define prt_slot_lnkH(nr) prt_slot_lnk(nr, LNKH, LNKE, LNKF, LNKG)
+
+ Name(PRTP, package() {
+ prt_slot_lnkE(0x0000),
+ prt_slot_lnkF(0x0001),
+ prt_slot_lnkG(0x0002),
+ prt_slot_lnkH(0x0003),
+ prt_slot_lnkE(0x0004),
+ prt_slot_lnkF(0x0005),
+ prt_slot_lnkG(0x0006),
+ prt_slot_lnkH(0x0007),
+ prt_slot_lnkE(0x0008),
+ prt_slot_lnkF(0x0009),
+ prt_slot_lnkG(0x000a),
+ prt_slot_lnkH(0x000b),
+ prt_slot_lnkE(0x000c),
+ prt_slot_lnkF(0x000d),
+ prt_slot_lnkG(0x000e),
+ prt_slot_lnkH(0x000f),
+ prt_slot_lnkE(0x0010),
+ prt_slot_lnkF(0x0011),
+ prt_slot_lnkG(0x0012),
+ prt_slot_lnkH(0x0013),
+ prt_slot_lnkE(0x0014),
+ prt_slot_lnkF(0x0015),
+ prt_slot_lnkG(0x0016),
+ prt_slot_lnkH(0x0017),
+ prt_slot_lnkE(0x0018),
+
+ /* INTA -> PIRQA for slot 25 - 31
+ see the default value of D<N>IR */
+ prt_slot_lnkA(0x0019),
+ prt_slot_lnkA(0x001a),
+ prt_slot_lnkA(0x001b),
+ prt_slot_lnkA(0x001c),
+ prt_slot_lnkA(0x001d),
+
+ /* PCIe->PCI bridge. use PIRQ[E-H] */
+ prt_slot_lnkE(0x001e),
+
+ prt_slot_lnkA(0x001f)
+ })
+
+#define prt_slot_gsi(nr, gsi0, gsi1, gsi2, gsi3) \
+ Package() { nr##ffff, 0, gsi0, 0 }, \
+ Package() { nr##ffff, 1, gsi1, 0 }, \
+ Package() { nr##ffff, 2, gsi2, 0 }, \
+ Package() { nr##ffff, 3, gsi3, 0 }
+
+#define prt_slot_gsiA(nr) prt_slot_gsi(nr, GSIA, GSIB, GSIC, GSID)
+#define prt_slot_gsiB(nr) prt_slot_gsi(nr, GSIB, GSIC, GSID, GSIA)
+#define prt_slot_gsiC(nr) prt_slot_gsi(nr, GSIC, GSID, GSIA, GSIB)
+#define prt_slot_gsiD(nr) prt_slot_gsi(nr, GSID, GSIA, GSIB, GSIC)
+
+#define prt_slot_gsiE(nr) prt_slot_gsi(nr, GSIE, GSIF, GSIG, GSIH)
+#define prt_slot_gsiF(nr) prt_slot_gsi(nr, GSIF, GSIG, GSIH, GSIE)
+#define prt_slot_gsiG(nr) prt_slot_gsi(nr, GSIG, GSIH, GSIE, GSIF)
+#define prt_slot_gsiH(nr) prt_slot_gsi(nr, GSIH, GSIE, GSIF, GSIG)
+
+ Name(PRTA, package() {
+ prt_slot_gsiE(0x0000),
+ prt_slot_gsiF(0x0001),
+ prt_slot_gsiG(0x0002),
+ prt_slot_gsiH(0x0003),
+ prt_slot_gsiE(0x0004),
+ prt_slot_gsiF(0x0005),
+ prt_slot_gsiG(0x0006),
+ prt_slot_gsiH(0x0007),
+ prt_slot_gsiE(0x0008),
+ prt_slot_gsiF(0x0009),
+ prt_slot_gsiG(0x000a),
+ prt_slot_gsiH(0x000b),
+ prt_slot_gsiE(0x000c),
+ prt_slot_gsiF(0x000d),
+ prt_slot_gsiG(0x000e),
+ prt_slot_gsiH(0x000f),
+ prt_slot_gsiE(0x0010),
+ prt_slot_gsiF(0x0011),
+ prt_slot_gsiG(0x0012),
+ prt_slot_gsiH(0x0013),
+ prt_slot_gsiE(0x0014),
+ prt_slot_gsiF(0x0015),
+ prt_slot_gsiG(0x0016),
+ prt_slot_gsiH(0x0017),
+ prt_slot_gsiE(0x0018),
+
+ /* INTA -> PIRQA for slot 25 - 31, but 30
+ see the default value of D<N>IR */
+ prt_slot_gsiA(0x0019),
+ prt_slot_gsiA(0x001a),
+ prt_slot_gsiA(0x001b),
+ prt_slot_gsiA(0x001c),
+ prt_slot_gsiA(0x001d),
+
+ /* PCIe->PCI bridge. use PIRQ[E-H] */
+ prt_slot_gsiE(0x001e),
+
+ prt_slot_gsiA(0x001f)
+ })
+
+ Method(_PRT, 0, NotSerialized) {
+ /* PCI IRQ routing table, example from ACPI 2.0a specification,
+ section 6.2.8.1 */
+ /* Note: we provide the same info as the PCI routing
+ table of the Bochs BIOS */
+ If (LEqual(\PICF, Zero)) {
+ Return (PRTP)
+ } Else {
+ Return (PRTA)
+ }
+ }
+ }
+
+ Field(PCI0.ISA.PIRQ, ByteAcc, NoLock, Preserve) {
+ PRQA, 8,
+ PRQB, 8,
+ PRQC, 8,
+ PRQD, 8,
+
+ Offset(0x08),
+ PRQE, 8,
+ PRQF, 8,
+ PRQG, 8,
+ PRQH, 8
+ }
+
+ Method(IQST, 1, NotSerialized) {
+ // _STA method - get status
+ If (And(0x80, Arg0)) {
+ Return (0x09)
+ }
+ Return (0x0B)
+ }
+ Method(IQCR, 1, Serialized) {
+ // _CRS method - get current settings
+ Name(PRR0, ResourceTemplate() {
+ Interrupt(, Level, ActiveHigh, Shared) { 0 }
+ })
+ CreateDWordField(PRR0, 0x05, PRRI)
+ Store(And(Arg0, 0x0F), PRRI)
+ Return (PRR0)
+ }
+
+#define define_link(link, uid, reg) \
+ Device(link) { \
+ Name(_HID, EISAID("PNP0C0F")) \
+ Name(_UID, uid) \
+ Name(_PRS, ResourceTemplate() { \
+ Interrupt(, Level, ActiveHigh, Shared) { \
+ 5, 10, 11 \
+ } \
+ }) \
+ Method(_STA, 0, NotSerialized) { \
+ Return (IQST(reg)) \
+ } \
+ Method(_DIS, 0, NotSerialized) { \
+ Or(reg, 0x80, reg) \
+ } \
+ Method(_CRS, 0, NotSerialized) { \
+ Return (IQCR(reg)) \
+ } \
+ Method(_SRS, 1, NotSerialized) { \
+ CreateDWordField(Arg0, 0x05, PRRI) \
+ Store(PRRI, reg) \
+ } \
+ }
+
+ define_link(LNKA, 0, PRQA)
+ define_link(LNKB, 1, PRQB)
+ define_link(LNKC, 2, PRQC)
+ define_link(LNKD, 3, PRQD)
+ define_link(LNKE, 4, PRQE)
+ define_link(LNKF, 5, PRQF)
+ define_link(LNKG, 6, PRQG)
+ define_link(LNKH, 7, PRQH)
+
+#define define_gsi_link(link, uid, gsi) \
+ Device(link) { \
+ Name(_HID, EISAID("PNP0C0F")) \
+ Name(_UID, uid) \
+ Name(_PRS, ResourceTemplate() { \
+ Interrupt(, Level, ActiveHigh, Shared) { \
+ gsi \
+ } \
+ }) \
+ Name(_CRS, ResourceTemplate() { \
+ Interrupt(, Level, ActiveHigh, Shared) { \
+ gsi \
+ } \
+ }) \
+ Method(_SRS, 1, NotSerialized) { \
+ } \
+ }
+
+ define_gsi_link(GSIA, 0, 0x10)
+ define_gsi_link(GSIB, 0, 0x11)
+ define_gsi_link(GSIC, 0, 0x12)
+ define_gsi_link(GSID, 0, 0x13)
+ define_gsi_link(GSIE, 0, 0x14)
+ define_gsi_link(GSIF, 0, 0x15)
+ define_gsi_link(GSIG, 0, 0x16)
+ define_gsi_link(GSIH, 0, 0x17)
+ }
+
+#include "acpi-dsdt-cpu-hotplug.dsl"
+
+
+/****************************************************************
+ * General purpose events
+ ****************************************************************/
+
+ Scope(\_GPE) {
+ Name(_HID, "ACPI0006")
+
+ Method(_L00) {
+ }
+ Method(_L01) {
+ // CPU hotplug event
+ \_SB.PRSC()
+ }
+ Method(_L02) {
+ }
+ Method(_L03) {
+ }
+ Method(_L04) {
+ }
+ Method(_L05) {
+ }
+ Method(_L06) {
+ }
+ Method(_L07) {
+ }
+ Method(_L08) {
+ }
+ Method(_L09) {
+ }
+ Method(_L0A) {
+ }
+ Method(_L0B) {
+ }
+ Method(_L0C) {
+ }
+ Method(_L0D) {
+ }
+ Method(_L0E) {
+ }
+ Method(_L0F) {
+ }
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/romfile_loader.c b/qemu/roms/seabios/src/fw/romfile_loader.c
new file mode 100644
index 000000000..f4b17ff90
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/romfile_loader.c
@@ -0,0 +1,177 @@
+#include "romfile_loader.h"
+#include "byteorder.h" // leXX_to_cpu/cpu_to_leXX
+#include "util.h" // checksum
+#include "string.h" // strcmp
+#include "romfile.h" // struct romfile_s
+#include "malloc.h" // Zone*, _malloc
+#include "output.h" // warn_*
+
+struct romfile_loader_file {
+ struct romfile_s *file;
+ void *data;
+};
+struct romfile_loader_files {
+ int nfiles;
+ struct romfile_loader_file files[];
+};
+
+static struct romfile_loader_file *
+romfile_loader_find(const char *name,
+ struct romfile_loader_files *files)
+{
+ int i;
+ if (name[ROMFILE_LOADER_FILESZ - 1])
+ return NULL;
+ for (i = 0; i < files->nfiles; ++i)
+ if (!strcmp(files->files[i].file->name, name))
+ return &files->files[i];
+ return NULL;
+}
+
+static void romfile_loader_allocate(struct romfile_loader_entry_s *entry,
+ struct romfile_loader_files *files)
+{
+ struct zone_s *zone;
+ struct romfile_loader_file *file = &files->files[files->nfiles];
+ void *data;
+ int ret;
+ unsigned alloc_align = le32_to_cpu(entry->alloc_align);
+
+ if (alloc_align & (alloc_align - 1))
+ goto err;
+
+ switch (entry->alloc_zone) {
+ case ROMFILE_LOADER_ALLOC_ZONE_HIGH:
+ zone = &ZoneHigh;
+ break;
+ case ROMFILE_LOADER_ALLOC_ZONE_FSEG:
+ zone = &ZoneFSeg;
+ break;
+ default:
+ goto err;
+ }
+ if (alloc_align < MALLOC_MIN_ALIGN)
+ alloc_align = MALLOC_MIN_ALIGN;
+ if (entry->alloc_file[ROMFILE_LOADER_FILESZ - 1])
+ goto err;
+ file->file = romfile_find(entry->alloc_file);
+ if (!file->file || !file->file->size)
+ return;
+ data = _malloc(zone, file->file->size, alloc_align);
+ if (!data) {
+ warn_noalloc();
+ return;
+ }
+ ret = file->file->copy(file->file, data, file->file->size);
+ if (ret != file->file->size)
+ goto file_err;
+ file->data = data;
+ files->nfiles++;
+ return;
+
+file_err:
+ free(data);
+err:
+ warn_internalerror();
+}
+
+static void romfile_loader_add_pointer(struct romfile_loader_entry_s *entry,
+ struct romfile_loader_files *files)
+{
+ struct romfile_loader_file *dest_file;
+ struct romfile_loader_file *src_file;
+ unsigned offset = le32_to_cpu(entry->pointer_offset);
+ u64 pointer = 0;
+
+ dest_file = romfile_loader_find(entry->pointer_dest_file, files);
+ src_file = romfile_loader_find(entry->pointer_src_file, files);
+
+ if (!dest_file || !src_file || !dest_file->data || !src_file->data ||
+ offset + entry->pointer_size < offset ||
+ offset + entry->pointer_size > dest_file->file->size ||
+ entry->pointer_size < 1 || entry->pointer_size > 8 ||
+ entry->pointer_size & (entry->pointer_size - 1))
+ goto err;
+
+ memcpy(&pointer, dest_file->data + offset, entry->pointer_size);
+ pointer = le64_to_cpu(pointer);
+ pointer += (unsigned long)src_file->data;
+ pointer = cpu_to_le64(pointer);
+ memcpy(dest_file->data + offset, &pointer, entry->pointer_size);
+
+ return;
+err:
+ warn_internalerror();
+}
+
+static void romfile_loader_add_checksum(struct romfile_loader_entry_s *entry,
+ struct romfile_loader_files *files)
+{
+ struct romfile_loader_file *file;
+ unsigned offset = le32_to_cpu(entry->cksum_offset);
+ unsigned start = le32_to_cpu(entry->cksum_start);
+ unsigned len = le32_to_cpu(entry->cksum_length);
+ u8 *data;
+
+ file = romfile_loader_find(entry->cksum_file, files);
+
+ if (!file || !file->data || offset >= file->file->size ||
+ start + len < start || start + len > file->file->size)
+ goto err;
+
+ data = file->data + offset;
+ *data -= checksum(file->data + start, len);
+
+ return;
+err:
+ warn_internalerror();
+}
+
+int romfile_loader_execute(const char *name)
+{
+ struct romfile_loader_entry_s *entry;
+ int size, offset = 0, nfiles;
+ struct romfile_loader_files *files;
+ void *data = romfile_loadfile(name, &size);
+ if (!data)
+ return -1;
+
+ if (size % sizeof(*entry)) {
+ warn_internalerror();
+ goto err;
+ }
+
+ /* (over)estimate the number of files to load. */
+ nfiles = size / sizeof(*entry);
+ files = malloc_tmp(sizeof(*files) + nfiles * sizeof(files->files[0]));
+ if (!files) {
+ warn_noalloc();
+ goto err;
+ }
+ files->nfiles = 0;
+
+ for (offset = 0; offset < size; offset += sizeof(*entry)) {
+ entry = data + offset;
+ switch (le32_to_cpu(entry->command)) {
+ case ROMFILE_LOADER_COMMAND_ALLOCATE:
+ romfile_loader_allocate(entry, files);
+ break;
+ case ROMFILE_LOADER_COMMAND_ADD_POINTER:
+ romfile_loader_add_pointer(entry, files);
+ break;
+ case ROMFILE_LOADER_COMMAND_ADD_CHECKSUM:
+ romfile_loader_add_checksum(entry, files);
+ default:
+ /* Skip commands that we don't recognize. */
+ break;
+ }
+ }
+
+ free(files);
+ free(data);
+ return 0;
+
+err:
+ free(data);
+ return -1;
+}
diff --git a/qemu/roms/seabios/src/fw/romfile_loader.h b/qemu/roms/seabios/src/fw/romfile_loader.h
new file mode 100644
index 000000000..15eab2ac6
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/romfile_loader.h
@@ -0,0 +1,72 @@
+#ifndef __ROMFILE_LOADER_H
+#define __ROMFILE_LOADER_H
+
+#include "types.h" // u8
+#include "util.h" // romfile_s
+
+#define ROMFILE_LOADER_FILESZ 56
+
+/* ROM file linker/loader interface. Linker uses little endian format */
+struct romfile_loader_entry_s {
+ u32 command;
+ union {
+ /*
+ * COMMAND_ALLOCATE - allocate a table from @alloc_file
+ * subject to @alloc_align alignment (must be power of 2)
+ * and @alloc_zone (can be HIGH or FSEG) requirements.
+ *
+ * Must appear exactly once for each file, and before
+ * this file is referenced by any other command.
+ */
+ struct {
+ char alloc_file[ROMFILE_LOADER_FILESZ];
+ u32 alloc_align;
+ u8 alloc_zone;
+ };
+
+ /*
+ * COMMAND_ADD_POINTER - patch the table (originating from
+ * @dest_file) at @pointer_offset, by adding a pointer to the table
+ * originating from @src_file. 1,2,4 or 8 byte unsigned
+ * addition is used depending on @pointer_size.
+ */
+ struct {
+ char pointer_dest_file[ROMFILE_LOADER_FILESZ];
+ char pointer_src_file[ROMFILE_LOADER_FILESZ];
+ u32 pointer_offset;
+ u8 pointer_size;
+ };
+
+ /*
+ * COMMAND_ADD_CHECKSUM - calculate checksum of the range specified by
+ * @cksum_start and @cksum_length fields,
+ * and then add the value at @cksum_offset.
+ * Checksum simply sums -X for each byte X in the range
+ * using 8-bit math.
+ */
+ struct {
+ char cksum_file[ROMFILE_LOADER_FILESZ];
+ u32 cksum_offset;
+ u32 cksum_start;
+ u32 cksum_length;
+ };
+
+ /* padding */
+ char pad[124];
+ };
+};
+
+enum {
+ ROMFILE_LOADER_COMMAND_ALLOCATE = 0x1,
+ ROMFILE_LOADER_COMMAND_ADD_POINTER = 0x2,
+ ROMFILE_LOADER_COMMAND_ADD_CHECKSUM = 0x3,
+};
+
+enum {
+ ROMFILE_LOADER_ALLOC_ZONE_HIGH = 0x1,
+ ROMFILE_LOADER_ALLOC_ZONE_FSEG = 0x2,
+};
+
+int romfile_loader_execute(const char *name);
+
+#endif
diff --git a/qemu/roms/seabios/src/fw/shadow.c b/qemu/roms/seabios/src/fw/shadow.c
new file mode 100644
index 000000000..4f00006bf
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/shadow.c
@@ -0,0 +1,171 @@
+// Support for enabling/disabling BIOS ram shadowing.
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "dev-q35.h" // PCI_VENDOR_ID_INTEL
+#include "dev-piix.h" // I440FX_PAM0
+#include "hw/pci.h" // pci_config_writeb
+#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "hw/pci_regs.h" // PCI_VENDOR_ID
+#include "malloc.h" // rom_get_last
+#include "output.h" // dprintf
+#include "paravirt.h" // runningOnXen
+#include "string.h" // memset
+#include "util.h" // make_bios_writable
+#include "x86.h" // wbinvd
+
+// On the emulators, the bios at 0xf0000 is also at 0xffff0000
+#define BIOS_SRC_OFFSET 0xfff00000
+
+// Enable shadowing and copy bios.
+static void
+__make_bios_writable_intel(u16 bdf, u32 pam0)
+{
+ // Make ram from 0xc0000-0xf0000 writable
+ int clear = 0;
+ int i;
+ for (i=0; i<6; i++) {
+ u32 pam = pam0 + 1 + i;
+ int reg = pci_config_readb(bdf, pam);
+ if (CONFIG_OPTIONROMS_DEPLOYED && (reg & 0x11) != 0x11) {
+ // Need to copy optionroms to work around qemu implementation
+ void *mem = (void*)(BUILD_ROM_START + i * 32*1024);
+ memcpy((void*)BUILD_BIOS_TMP_ADDR, mem, 32*1024);
+ pci_config_writeb(bdf, pam, 0x33);
+ memcpy(mem, (void*)BUILD_BIOS_TMP_ADDR, 32*1024);
+ clear = 1;
+ } else {
+ pci_config_writeb(bdf, pam, 0x33);
+ }
+ }
+ if (clear)
+ memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024);
+
+ // Make ram from 0xf0000-0x100000 writable
+ int reg = pci_config_readb(bdf, pam0);
+ pci_config_writeb(bdf, pam0, 0x30);
+ if (reg & 0x10)
+ // Ram already present.
+ return;
+
+ // Copy bios.
+ extern u8 code32flat_start[], code32flat_end[];
+ memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
+ , code32flat_end - code32flat_start);
+}
+
+static void
+make_bios_writable_intel(u16 bdf, u32 pam0)
+{
+ int reg = pci_config_readb(bdf, pam0);
+ if (!(reg & 0x10)) {
+ // QEMU doesn't fully implement the piix shadow capabilities -
+ // if ram isn't backing the bios segment when shadowing is
+ // disabled, the code itself wont be in memory. So, run the
+ // code from the high-memory flash location.
+ u32 pos = (u32)__make_bios_writable_intel + BIOS_SRC_OFFSET;
+ void (*func)(u16 bdf, u32 pam0) = (void*)pos;
+ func(bdf, pam0);
+ return;
+ }
+ // Ram already present - just enable writes
+ __make_bios_writable_intel(bdf, pam0);
+}
+
+static void
+make_bios_readonly_intel(u16 bdf, u32 pam0)
+{
+ // Flush any pending writes before locking memory.
+ wbinvd();
+
+ // Write protect roms from 0xc0000-0xf0000
+ u32 romlast = BUILD_BIOS_ADDR, rommax = BUILD_BIOS_ADDR;
+ if (CONFIG_WRITABLE_UPPERMEMORY)
+ romlast = rom_get_last();
+ if (CONFIG_MALLOC_UPPERMEMORY)
+ rommax = rom_get_max();
+ int i;
+ for (i=0; i<6; i++) {
+ u32 mem = BUILD_ROM_START + i * 32*1024;
+ u32 pam = pam0 + 1 + i;
+ if (romlast < mem + 16*1024 || rommax < mem + 32*1024) {
+ if (romlast >= mem && rommax >= mem + 16*1024)
+ pci_config_writeb(bdf, pam, 0x31);
+ break;
+ }
+ pci_config_writeb(bdf, pam, 0x11);
+ }
+
+ // Write protect 0xf0000-0x100000
+ pci_config_writeb(bdf, pam0, 0x10);
+}
+
+static int ShadowBDF = -1;
+
+// Make the 0xc0000-0x100000 area read/writable.
+void
+make_bios_writable(void)
+{
+ if (!CONFIG_QEMU || runningOnXen())
+ return;
+
+ dprintf(3, "enabling shadow ram\n");
+
+ // At this point, statically allocated variables can't be written,
+ // so do this search manually.
+ int bdf;
+ foreachbdf(bdf, 0) {
+ u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
+ u16 vendor = vendev & 0xffff, device = vendev >> 16;
+ if (vendor == PCI_VENDOR_ID_INTEL
+ && device == PCI_DEVICE_ID_INTEL_82441) {
+ make_bios_writable_intel(bdf, I440FX_PAM0);
+ ShadowBDF = bdf;
+ return;
+ }
+ if (vendor == PCI_VENDOR_ID_INTEL
+ && device == PCI_DEVICE_ID_INTEL_Q35_MCH) {
+ make_bios_writable_intel(bdf, Q35_HOST_BRIDGE_PAM0);
+ ShadowBDF = bdf;
+ return;
+ }
+ }
+ dprintf(1, "Unable to unlock ram - bridge not found\n");
+}
+
+// Make the BIOS code segment area (0xf0000) read-only.
+void
+make_bios_readonly(void)
+{
+ if (!CONFIG_QEMU || runningOnXen())
+ return;
+ dprintf(3, "locking shadow ram\n");
+
+ if (ShadowBDF < 0) {
+ dprintf(1, "Unable to lock ram - bridge not found\n");
+ return;
+ }
+
+ u16 device = pci_config_readw(ShadowBDF, PCI_DEVICE_ID);
+ if (device == PCI_DEVICE_ID_INTEL_82441)
+ make_bios_readonly_intel(ShadowBDF, I440FX_PAM0);
+ else
+ make_bios_readonly_intel(ShadowBDF, Q35_HOST_BRIDGE_PAM0);
+}
+
+void
+qemu_prep_reset(void)
+{
+ if (!CONFIG_QEMU || runningOnXen())
+ return;
+ // QEMU doesn't map 0xc0000-0xfffff back to the original rom on a
+ // reset, so do that manually before invoking a hard reset.
+ make_bios_writable();
+ extern u8 code32flat_start[], code32flat_end[];
+ memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
+ , code32flat_end - code32flat_start);
+}
diff --git a/qemu/roms/seabios/src/fw/smbios.c b/qemu/roms/seabios/src/fw/smbios.c
new file mode 100644
index 000000000..dba054133
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/smbios.c
@@ -0,0 +1,585 @@
+// smbios table generation (on emulators)
+// DO NOT ADD NEW FEATURES HERE. (See paravirt.c / biostables.c instead.)
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "paravirt.h" // RamSize
+#include "romfile.h" // romfile_findprefix
+#include "std/smbios.h" // struct smbios_entry_point
+#include "string.h" // memset
+#include "util.h" // MaxCountCPUs
+#include "x86.h" // cpuid
+
+static void
+smbios_entry_point_setup(u16 max_structure_size,
+ u16 structure_table_length,
+ void *structure_table_address,
+ u16 number_of_structures)
+{
+ void *finaltable;
+ if (structure_table_length <= BUILD_MAX_SMBIOS_FSEG)
+ // Table is small enough for f-seg - allocate there. This
+ // works around a bug in JunOS (at least for small SMBIOS tables).
+ finaltable = malloc_fseg(structure_table_length);
+ else
+ finaltable = malloc_high(structure_table_length);
+ if (!finaltable) {
+ warn_noalloc();
+ return;
+ }
+ memcpy(finaltable, structure_table_address, structure_table_length);
+
+ struct smbios_entry_point ep;
+ memset(&ep, 0, sizeof(ep));
+ memcpy(ep.anchor_string, "_SM_", 4);
+ ep.length = 0x1f;
+ ep.smbios_major_version = 2;
+ ep.smbios_minor_version = 4;
+ ep.max_structure_size = max_structure_size;
+ memcpy(ep.intermediate_anchor_string, "_DMI_", 5);
+
+ ep.structure_table_length = structure_table_length;
+ ep.structure_table_address = (u32)finaltable;
+ ep.number_of_structures = number_of_structures;
+ ep.smbios_bcd_revision = 0x24;
+
+ ep.checksum -= checksum(&ep, 0x10);
+
+ ep.intermediate_checksum -= checksum((void*)&ep + 0x10, ep.length - 0x10);
+
+ copy_smbios(&ep);
+}
+
+static int
+get_field(int type, int offset, void *dest)
+{
+ char name[128];
+ snprintf(name, sizeof(name), "smbios/field%d-%d", type, offset);
+ struct romfile_s *file = romfile_find(name);
+ if (!file)
+ return 0;
+ file->copy(file, dest, file->size);
+ return file->size;
+}
+
+static int
+get_external(int type, char **p, unsigned *nr_structs,
+ unsigned *max_struct_size, char *end)
+{
+ static u64 used_bitmap[4] = { 0 };
+ char *start = *p;
+
+ /* Check if we've already reported these tables */
+ if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
+ return 1;
+
+ /* Don't introduce spurious end markers */
+ if (type == 127)
+ return 0;
+
+ char prefix[128];
+ snprintf(prefix, sizeof(prefix), "smbios/table%d-", type);
+ struct romfile_s *file = NULL;
+ for (;;) {
+ file = romfile_findprefix(prefix, file);
+ if (!file)
+ break;
+
+ if (end - *p < file->size) {
+ warn_noalloc();
+ break;
+ }
+
+ struct smbios_structure_header *header = (void*)*p;
+ file->copy(file, header, file->size);
+ *p += file->size;
+
+ /* Entries end with a double NULL char, if there's a string at
+ * the end (length is greater than formatted length), the string
+ * terminator provides the first NULL. */
+ *((u8*)*p) = 0;
+ (*p)++;
+ if (header->length >= file->size) {
+ *((u8*)*p) = 0;
+ (*p)++;
+ }
+
+ (*nr_structs)++;
+ if (*p - (char*)header > *max_struct_size)
+ *max_struct_size = *p - (char*)header;
+ }
+
+ if (start == *p)
+ return 0;
+
+ /* Mark that we've reported on this type */
+ used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
+ return 1;
+}
+
+#define load_str_field_with_default(type, field, def) \
+ do { \
+ size = get_field(type, offsetof(struct smbios_type_##type, \
+ field), end); \
+ if (size == 1) { \
+ /* zero-length string, skip to avoid bogus end marker */ \
+ p->field = 0; \
+ } else if (size > 1) { \
+ end += size; \
+ p->field = ++str_index; \
+ } else { \
+ memcpy(end, def, sizeof(def)); \
+ end += sizeof(def); \
+ p->field = ++str_index; \
+ } \
+ } while (0)
+
+#define load_str_field_or_skip(type, field) \
+ do { \
+ size = get_field(type, offsetof(struct smbios_type_##type, \
+ field), end); \
+ if (size > 1) { \
+ end += size; \
+ p->field = ++str_index; \
+ } else { \
+ p->field = 0; \
+ } \
+ } while (0)
+
+#define set_field_with_default(type, field, def) \
+ do { \
+ if (!get_field(type, offsetof(struct smbios_type_##type, \
+ field), &p->field)) { \
+ p->field = def; \
+ } \
+ } while (0)
+
+/* Type 0 -- BIOS Information */
+#define RELEASE_DATE_STR "01/01/2011"
+static void *
+smbios_init_type_0(void *start)
+{
+ struct smbios_type_0 *p = (struct smbios_type_0 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_0);
+ size_t size;
+ int str_index = 0;
+
+ p->header.type = 0;
+ p->header.length = sizeof(struct smbios_type_0);
+ p->header.handle = 0;
+
+ load_str_field_with_default(0, vendor_str, BUILD_APPNAME);
+ load_str_field_with_default(0, bios_version_str, BUILD_APPNAME);
+
+ p->bios_starting_address_segment = 0xe800;
+
+ load_str_field_with_default(0, bios_release_date_str, RELEASE_DATE_STR);
+
+ p->bios_rom_size = 0; /* FIXME */
+
+ if (!get_field(0, offsetof(struct smbios_type_0, bios_characteristics),
+ &p->bios_characteristics)) {
+ memset(p->bios_characteristics, 0, 8);
+ /* BIOS characteristics not supported */
+ p->bios_characteristics[0] = 0x08;
+ }
+
+ if (!get_field(0, offsetof(struct smbios_type_0,
+ bios_characteristics_extension_bytes),
+ &p->bios_characteristics_extension_bytes)) {
+ p->bios_characteristics_extension_bytes[0] = 0;
+ /* Enable targeted content distribution. Needed for SVVP */
+ p->bios_characteristics_extension_bytes[1] = 4;
+ }
+
+ set_field_with_default(0, system_bios_major_release, 1);
+ set_field_with_default(0, system_bios_minor_release, 0);
+ set_field_with_default(0, embedded_controller_major_release, 0xff);
+ set_field_with_default(0, embedded_controller_minor_release, 0xff);
+
+ *end = 0;
+ end++;
+
+ return end;
+}
+
+/* Type 1 -- System Information */
+static void *
+smbios_init_type_1(void *start)
+{
+ struct smbios_type_1 *p = (struct smbios_type_1 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_1);
+ size_t size;
+ int str_index = 0;
+
+ p->header.type = 1;
+ p->header.length = sizeof(struct smbios_type_1);
+ p->header.handle = 0x100;
+
+ load_str_field_with_default(1, manufacturer_str, BUILD_APPNAME);
+ load_str_field_with_default(1, product_name_str, BUILD_APPNAME);
+ load_str_field_or_skip(1, version_str);
+ load_str_field_or_skip(1, serial_number_str);
+
+ if (!get_field(1, offsetof(struct smbios_type_1, uuid), &p->uuid))
+ memset(p->uuid, 0, 16);
+
+ set_field_with_default(1, wake_up_type, 0x06); /* power switch */
+
+ load_str_field_or_skip(1, sku_number_str);
+ load_str_field_or_skip(1, family_str);
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+/* Type 3 -- System Enclosure */
+static void *
+smbios_init_type_3(void *start)
+{
+ struct smbios_type_3 *p = (struct smbios_type_3 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_3);
+ size_t size;
+ int str_index = 0;
+
+ p->header.type = 3;
+ p->header.length = sizeof(struct smbios_type_3);
+ p->header.handle = 0x300;
+
+ load_str_field_with_default(3, manufacturer_str, BUILD_APPNAME);
+ set_field_with_default(3, type, 0x01); /* other */
+
+ load_str_field_or_skip(3, version_str);
+ load_str_field_or_skip(3, serial_number_str);
+ load_str_field_or_skip(3, asset_tag_number_str);
+
+ set_field_with_default(3, boot_up_state, 0x03); /* safe */
+ set_field_with_default(3, power_supply_state, 0x03); /* safe */
+ set_field_with_default(3, thermal_state, 0x03); /* safe */
+ set_field_with_default(3, security_status, 0x02); /* unknown */
+
+ set_field_with_default(3, oem_defined, 0);
+ set_field_with_default(3, height, 0);
+ set_field_with_default(3, number_of_power_cords, 0);
+ set_field_with_default(3, contained_element_count, 0);
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+/* Type 4 -- Processor Information */
+static void *
+smbios_init_type_4(void *start, unsigned int cpu_number)
+{
+ struct smbios_type_4 *p = (struct smbios_type_4 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_4);
+ size_t size;
+ int str_index = 0;
+ char name[1024];
+
+ p->header.type = 4;
+ p->header.length = sizeof(struct smbios_type_4);
+ p->header.handle = 0x400 + cpu_number;
+
+ size = get_field(4, offsetof(struct smbios_type_4, socket_designation_str),
+ name);
+ if (size)
+ snprintf(name + size - 1, sizeof(name) - size, "%2x", cpu_number);
+ else
+ snprintf(name, sizeof(name), "CPU%2x", cpu_number);
+
+ memcpy(end, name, strlen(name) + 1);
+ end += strlen(name) + 1;
+ p->socket_designation_str = ++str_index;
+
+ set_field_with_default(4, processor_type, 0x03); /* CPU */
+ set_field_with_default(4, processor_family, 0x01); /* other */
+
+ load_str_field_with_default(4, processor_manufacturer_str, BUILD_APPNAME);
+
+ if (!get_field(4, offsetof(struct smbios_type_4, processor_id)
+ , p->processor_id)) {
+ u32 cpuid_signature, ebx, ecx, cpuid_features;
+ cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features);
+ p->processor_id[0] = cpuid_signature;
+ p->processor_id[1] = cpuid_features;
+ }
+
+ load_str_field_or_skip(4, processor_version_str);
+ set_field_with_default(4, voltage, 0);
+ set_field_with_default(4, external_clock, 0);
+
+ set_field_with_default(4, max_speed, 2000);
+ set_field_with_default(4, current_speed, 2000);
+
+ set_field_with_default(4, status, 0x41); /* socket populated, CPU enabled */
+ set_field_with_default(4, processor_upgrade, 0x01); /* other */
+
+ /* cache information structure not provided */
+ p->l1_cache_handle = 0xffff;
+ p->l2_cache_handle = 0xffff;
+ p->l3_cache_handle = 0xffff;
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+/* Type 16 -- Physical Memory Array */
+static void *
+smbios_init_type_16(void *start, u32 memory_size_mb, int nr_mem_devs)
+{
+ struct smbios_type_16 *p = (struct smbios_type_16*)start;
+
+ p->header.type = 16;
+ p->header.length = sizeof(struct smbios_type_16);
+ p->header.handle = 0x1000;
+
+ set_field_with_default(16, location, 0x01); /* other */
+ set_field_with_default(16, use, 0x03); /* system memory */
+ /* Multi-bit ECC to make Microsoft happy */
+ set_field_with_default(16, error_correction, 0x06);
+ /* 0x80000000 = unknown, accept sizes < 2TB - TODO multiple arrays */
+ p->maximum_capacity = memory_size_mb < 2 << 20 ?
+ memory_size_mb << 10 : 0x80000000;
+ p->memory_error_information_handle = 0xfffe; /* none provided */
+ p->number_of_memory_devices = nr_mem_devs;
+
+ start += sizeof(struct smbios_type_16);
+ *((u16 *)start) = 0;
+
+ return start + 2;
+}
+
+/* Type 17 -- Memory Device */
+static void *
+smbios_init_type_17(void *start, u32 size_mb, int instance)
+{
+ struct smbios_type_17 *p = (struct smbios_type_17 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_17);
+ size_t size;
+ int str_index = 0;
+ char name[1024];
+
+ p->header.type = 17;
+ p->header.length = sizeof(struct smbios_type_17);
+ p->header.handle = 0x1100 + instance;
+
+ p->physical_memory_array_handle = 0x1000;
+ set_field_with_default(17, total_width, 64);
+ set_field_with_default(17, data_width, 64);
+/* TODO: should assert in case something is wrong ASSERT((memory_size_mb & ~0x7fff) == 0); */
+ p->size = size_mb;
+ set_field_with_default(17, form_factor, 0x09); /* DIMM */
+ p->device_set = 0;
+
+ size = get_field(17, offsetof(struct smbios_type_17, device_locator_str),
+ name);
+ if (size)
+ snprintf(name + size - 1, sizeof(name) - size, "%d", instance);
+ else
+ snprintf(name, sizeof(name), "DIMM %d", instance);
+
+ memcpy(end, name, strlen(name) + 1);
+ end += strlen(name) + 1;
+ p->device_locator_str = ++str_index;
+
+ load_str_field_or_skip(17, bank_locator_str);
+ set_field_with_default(17, memory_type, 0x07); /* RAM */
+ set_field_with_default(17, type_detail, 0);
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+/* Type 19 -- Memory Array Mapped Address */
+static void *
+smbios_init_type_19(void *start, u32 start_mb, u32 size_mb, int instance)
+{
+ struct smbios_type_19 *p = (struct smbios_type_19 *)start;
+
+ p->header.type = 19;
+ p->header.length = sizeof(struct smbios_type_19);
+ p->header.handle = 0x1300 + instance;
+
+ p->starting_address = start_mb << 10;
+ p->ending_address = p->starting_address + (size_mb << 10) - 1;
+ p->memory_array_handle = 0x1000;
+ p->partition_width = 1;
+
+ start += sizeof(struct smbios_type_19);
+ *((u16 *)start) = 0;
+
+ return start + 2;
+}
+
+/* Type 20 -- Memory Device Mapped Address */
+static void *
+smbios_init_type_20(void *start, u32 start_mb, u32 size_mb, int instance,
+ int dev_handle, int array_handle)
+{
+ struct smbios_type_20 *p = (struct smbios_type_20 *)start;
+
+ p->header.type = 20;
+ p->header.length = sizeof(struct smbios_type_20);
+ p->header.handle = 0x1400 + instance;
+
+ p->starting_address = start_mb << 10;
+ p->ending_address = p->starting_address + (size_mb << 10) - 1;
+ p->memory_device_handle = 0x1100 + dev_handle;
+ p->memory_array_mapped_address_handle = 0x1300 + array_handle;
+ p->partition_row_position = 1;
+ p->interleave_position = 0;
+ p->interleaved_data_depth = 0;
+
+ start += sizeof(struct smbios_type_20);
+
+ *((u16 *)start) = 0;
+ return start+2;
+}
+
+/* Type 32 -- System Boot Information */
+static void *
+smbios_init_type_32(void *start)
+{
+ struct smbios_type_32 *p = (struct smbios_type_32 *)start;
+
+ p->header.type = 32;
+ p->header.length = sizeof(struct smbios_type_32);
+ p->header.handle = 0x2000;
+ memset(p->reserved, 0, 6);
+ set_field_with_default(32, boot_status, 0); /* no errors detected */
+
+ start += sizeof(struct smbios_type_32);
+ *((u16 *)start) = 0;
+
+ return start+2;
+}
+
+/* Type 127 -- End of Table */
+static void *
+smbios_init_type_127(void *start)
+{
+ struct smbios_type_127 *p = (struct smbios_type_127 *)start;
+
+ p->header.type = 127;
+ p->header.length = sizeof(struct smbios_type_127);
+ p->header.handle = 0x7f00;
+
+ start += sizeof(struct smbios_type_127);
+ *((u16 *)start) = 0;
+
+ return start + 2;
+}
+
+#define TEMPSMBIOSSIZE (32 * 1024)
+
+void
+smbios_legacy_setup(void)
+{
+ if (! CONFIG_SMBIOS)
+ return;
+
+ dprintf(3, "init SMBIOS tables\n");
+
+ char *start = malloc_tmphigh(TEMPSMBIOSSIZE);
+ if (! start) {
+ warn_noalloc();
+ return;
+ }
+ memset(start, 0, TEMPSMBIOSSIZE);
+
+ u32 nr_structs = 0, max_struct_size = 0;
+ char *q, *p = start;
+ char *end = start + TEMPSMBIOSSIZE - sizeof(struct smbios_type_127);
+
+#define add_struct(type, args...) \
+ do { \
+ if (!get_external(type, &p, &nr_structs, &max_struct_size, end)) { \
+ q = smbios_init_type_##type(args); \
+ nr_structs++; \
+ if ((q - p) > max_struct_size) \
+ max_struct_size = q - p; \
+ p = q; \
+ } \
+ } while (0)
+
+ add_struct(0, p);
+ add_struct(1, p);
+ add_struct(3, p);
+
+ int cpu_num;
+ for (cpu_num = 1; cpu_num <= MaxCountCPUs; cpu_num++)
+ add_struct(4, p, cpu_num);
+
+ int ram_mb = (RamSize + RamSizeOver4G) >> 20;
+ int nr_mem_devs = (ram_mb + 0x3fff) >> 14;
+ add_struct(16, p, ram_mb, nr_mem_devs);
+
+ int i, j;
+ for (i = 0; i < nr_mem_devs; i++) {
+ u32 dev_mb = ((i == (nr_mem_devs - 1))
+ ? (((ram_mb - 1) & 0x3fff) + 1)
+ : 16384);
+ add_struct(17, p, dev_mb, i);
+ }
+
+ add_struct(19, p, 0, RamSize >> 20, 0);
+ if (RamSizeOver4G)
+ add_struct(19, p, 4096, RamSizeOver4G >> 20, 1);
+
+ add_struct(20, p, 0, RamSize >> 20, 0, 0, 0);
+ if (RamSizeOver4G) {
+ u32 start_mb = 4096;
+ for (j = 1, i = 0; i < nr_mem_devs; i++, j++) {
+ u32 dev_mb = ((i == (nr_mem_devs - 1))
+ ? (((ram_mb - 1) & 0x3fff) + 1)
+ : 16384);
+ if (i == 0)
+ dev_mb -= RamSize >> 20;
+
+ add_struct(20, p, start_mb, dev_mb, j, i, 1);
+ start_mb += dev_mb;
+ }
+ }
+
+ add_struct(32, p);
+ /* Add any remaining provided entries before the end marker */
+ for (i = 0; i < 256; i++)
+ get_external(i, &p, &nr_structs, &max_struct_size, end);
+ add_struct(127, p);
+
+#undef add_struct
+
+ smbios_entry_point_setup(max_struct_size, p - start, start, nr_structs);
+ free(start);
+}
diff --git a/qemu/roms/seabios/src/fw/smm.c b/qemu/roms/seabios/src/fw/smm.c
new file mode 100644
index 000000000..6cb484e7e
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/smm.c
@@ -0,0 +1,259 @@
+// System Management Mode support (on emulators)
+//
+// Copyright (C) 2008-2014 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "dev-q35.h"
+#include "dev-piix.h"
+#include "hw/pci.h" // pci_config_writel
+#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "hw/pci_regs.h" // PCI_DEVICE_ID
+#include "output.h" // dprintf
+#include "paravirt.h" // PORT_SMI_STATUS
+#include "stacks.h" // HaveSmmCall32
+#include "string.h" // memcpy
+#include "util.h" // smm_setup
+#include "x86.h" // wbinvd
+
+/*
+ * Check SMM state save area format (bits 0-15) and require support
+ * for SMBASE relocation.
+ */
+#define SMM_REV_MASK 0x0002ffff
+
+#define SMM_REV_I32 0x00020000
+#define SMM_REV_I64 0x00020064
+
+struct smm_state {
+ union {
+ struct {
+ u8 pad_000[0xf8];
+ u32 smm_base;
+ u32 smm_rev;
+ u8 pad_100[0xd0];
+ u32 eax, ecx, edx, ebx, esp, ebp, esi, edi, eip, eflags;
+ u8 pad_1f8[0x08];
+ } i32;
+ struct {
+ u8 pad_000[0xfc];
+ u32 smm_rev;
+ u32 smm_base;
+ u8 pad_104[0x6c];
+ u64 rflags, rip, r15, r14, r13, r12, r11, r10, r9, r8;
+ u64 rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax;
+ } i64;
+ };
+};
+
+struct smm_layout {
+ struct smm_state backup1;
+ struct smm_state backup2;
+ u8 stack[0x7c00];
+ u64 codeentry;
+ u8 pad_8008[0x7df8];
+ struct smm_state cpu;
+};
+
+void VISIBLE32FLAT
+handle_smi(u16 cs)
+{
+ if (!CONFIG_USE_SMM)
+ return;
+ u8 cmd = inb(PORT_SMI_CMD);
+ struct smm_layout *smm = MAKE_FLATPTR(cs, 0);
+ dprintf(DEBUG_HDL_smi, "handle_smi cmd=%x smbase=%p\n", cmd, smm);
+
+ if (smm == (void*)BUILD_SMM_INIT_ADDR) {
+ // relocate SMBASE to 0xa0000
+ u32 rev = smm->cpu.i32.smm_rev & SMM_REV_MASK;
+ if (rev == SMM_REV_I32) {
+ smm->cpu.i32.smm_base = BUILD_SMM_ADDR;
+ } else if (rev == SMM_REV_I64) {
+ smm->cpu.i64.smm_base = BUILD_SMM_ADDR;
+ } else {
+ warn_internalerror();
+ return;
+ }
+ // indicate to smm_relocate_and_restore() that the SMM code was executed
+ outb(0x00, PORT_SMI_STATUS);
+
+ if (CONFIG_CALL32_SMM) {
+ // Backup current cpu state for SMM trampolining
+ struct smm_layout *newsmm = (void*)BUILD_SMM_ADDR;
+ memcpy(&newsmm->backup1, &smm->cpu, sizeof(newsmm->backup1));
+ memcpy(&newsmm->backup2, &smm->cpu, sizeof(newsmm->backup2));
+ HaveSmmCall32 = 1;
+ }
+
+ return;
+ }
+
+ if (CONFIG_CALL32_SMM && cmd == CALL32SMM_CMDID) {
+ if (smm->cpu.i32.smm_rev == SMM_REV_I32) {
+ u32 regs[8];
+ memcpy(regs, &smm->cpu.i32.eax, sizeof(regs));
+ if (smm->cpu.i32.ecx == CALL32SMM_ENTERID) {
+ dprintf(9, "smm cpu call pc=%x esp=%x\n", regs[3], regs[4]);
+ memcpy(&smm->backup2, &smm->cpu, sizeof(smm->backup2));
+ memcpy(&smm->cpu, &smm->backup1, sizeof(smm->cpu));
+ memcpy(&smm->cpu.i32.eax, regs, sizeof(regs));
+ smm->cpu.i32.eip = regs[3];
+ } else if (smm->cpu.i32.ecx == CALL32SMM_RETURNID) {
+ dprintf(9, "smm cpu ret %x esp=%x\n", regs[3], regs[4]);
+ memcpy(&smm->cpu, &smm->backup2, sizeof(smm->cpu));
+ memcpy(&smm->cpu.i32.eax, regs, sizeof(regs));
+ smm->cpu.i32.eip = regs[3];
+ }
+ } else if (smm->cpu.i64.smm_rev == SMM_REV_I64) {
+ u64 regs[8];
+ memcpy(regs, &smm->cpu.i64.rdi, sizeof(regs));
+ if ((u32)smm->cpu.i64.rcx == CALL32SMM_ENTERID) {
+ memcpy(&smm->backup2, &smm->cpu, sizeof(smm->backup2));
+ memcpy(&smm->cpu, &smm->backup1, sizeof(smm->cpu));
+ memcpy(&smm->cpu.i64.rdi, regs, sizeof(regs));
+ smm->cpu.i64.rip = (u32)regs[4];
+ } else if ((u32)smm->cpu.i64.rcx == CALL32SMM_RETURNID) {
+ memcpy(&smm->cpu, &smm->backup2, sizeof(smm->cpu));
+ memcpy(&smm->cpu.i64.rdi, regs, sizeof(regs));
+ smm->cpu.i64.rip = (u32)regs[4];
+ }
+ }
+ }
+}
+
+extern void entry_smi(void);
+// movw %cs, %ax; ljmpw $SEG_BIOS, $(entry_smi - BUILD_BIOS_ADDR)
+#define SMI_INSN (0xeac88c | ((u64)SEG_BIOS<<40) \
+ | ((u64)((u32)entry_smi - BUILD_BIOS_ADDR) << 24))
+
+static void
+smm_save_and_copy(void)
+{
+ // save original memory content
+ struct smm_layout *initsmm = (void*)BUILD_SMM_INIT_ADDR;
+ struct smm_layout *smm = (void*)BUILD_SMM_ADDR;
+ memcpy(&smm->cpu, &initsmm->cpu, sizeof(smm->cpu));
+ memcpy(&smm->codeentry, &initsmm->codeentry, sizeof(smm->codeentry));
+
+ // Setup code entry point.
+ initsmm->codeentry = SMI_INSN;
+}
+
+static void
+smm_relocate_and_restore(void)
+{
+ /* init APM status port */
+ outb(0x01, PORT_SMI_STATUS);
+
+ /* raise an SMI interrupt */
+ outb(0x00, PORT_SMI_CMD);
+
+ /* wait until SMM code executed */
+ while (inb(PORT_SMI_STATUS) != 0x00)
+ ;
+
+ /* restore original memory content */
+ struct smm_layout *initsmm = (void*)BUILD_SMM_INIT_ADDR;
+ struct smm_layout *smm = (void*)BUILD_SMM_ADDR;
+ memcpy(&initsmm->cpu, &smm->cpu, sizeof(initsmm->cpu));
+ memcpy(&initsmm->codeentry, &smm->codeentry, sizeof(initsmm->codeentry));
+
+ // Setup code entry point.
+ smm->codeentry = SMI_INSN;
+ wbinvd();
+}
+
+// This code is hardcoded for PIIX4 Power Management device.
+static void piix4_apmc_smm_setup(int isabdf, int i440_bdf)
+{
+ /* check if SMM init is already done */
+ u32 value = pci_config_readl(isabdf, PIIX_DEVACTB);
+ if (value & PIIX_DEVACTB_APMC_EN)
+ return;
+
+ /* enable the SMM memory window */
+ pci_config_writeb(i440_bdf, I440FX_SMRAM, 0x02 | 0x48);
+
+ smm_save_and_copy();
+
+ /* enable SMI generation when writing to the APMC register */
+ pci_config_writel(isabdf, PIIX_DEVACTB, value | PIIX_DEVACTB_APMC_EN);
+
+ /* enable SMI generation */
+ value = inl(acpi_pm_base + PIIX_PMIO_GLBCTL);
+ outl(acpi_pm_base + PIIX_PMIO_GLBCTL, value | PIIX_PMIO_GLBCTL_SMI_EN);
+
+ smm_relocate_and_restore();
+
+ /* close the SMM memory window and enable normal SMM */
+ pci_config_writeb(i440_bdf, I440FX_SMRAM, 0x02 | 0x08);
+}
+
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */
+void ich9_lpc_apmc_smm_setup(int isabdf, int mch_bdf)
+{
+ /* check if SMM init is already done */
+ u32 value = inl(acpi_pm_base + ICH9_PMIO_SMI_EN);
+ if (value & ICH9_PMIO_SMI_EN_APMC_EN)
+ return;
+
+ /* enable the SMM memory window */
+ pci_config_writeb(mch_bdf, Q35_HOST_BRIDGE_SMRAM, 0x02 | 0x48);
+
+ smm_save_and_copy();
+
+ /* enable SMI generation when writing to the APMC register */
+ outl(value | ICH9_PMIO_SMI_EN_APMC_EN | ICH9_PMIO_SMI_EN_GLB_SMI_EN,
+ acpi_pm_base + ICH9_PMIO_SMI_EN);
+
+ /* lock SMI generation */
+ value = pci_config_readw(isabdf, ICH9_LPC_GEN_PMCON_1);
+ pci_config_writel(isabdf, ICH9_LPC_GEN_PMCON_1,
+ value | ICH9_LPC_GEN_PMCON_1_SMI_LOCK);
+
+ smm_relocate_and_restore();
+
+ /* close the SMM memory window and enable normal SMM */
+ pci_config_writeb(mch_bdf, Q35_HOST_BRIDGE_SMRAM, 0x02 | 0x08);
+}
+
+static int SMMISADeviceBDF = -1, SMMPMDeviceBDF = -1;
+
+void
+smm_device_setup(void)
+{
+ if (!CONFIG_USE_SMM)
+ return;
+
+ struct pci_device *isapci, *pmpci;
+ isapci = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3);
+ pmpci = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441);
+ if (isapci && pmpci) {
+ SMMISADeviceBDF = isapci->bdf;
+ SMMPMDeviceBDF = pmpci->bdf;
+ return;
+ }
+ isapci = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC);
+ pmpci = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH);
+ if (isapci && pmpci) {
+ SMMISADeviceBDF = isapci->bdf;
+ SMMPMDeviceBDF = pmpci->bdf;
+ }
+}
+
+void
+smm_setup(void)
+{
+ if (!CONFIG_USE_SMM || SMMISADeviceBDF < 0)
+ return;
+
+ dprintf(3, "init smm\n");
+ u16 device = pci_config_readw(SMMISADeviceBDF, PCI_DEVICE_ID);
+ if (device == PCI_DEVICE_ID_INTEL_82371AB_3)
+ piix4_apmc_smm_setup(SMMISADeviceBDF, SMMPMDeviceBDF);
+ else
+ ich9_lpc_apmc_smm_setup(SMMISADeviceBDF, SMMPMDeviceBDF);
+}
diff --git a/qemu/roms/seabios/src/fw/smp.c b/qemu/roms/seabios/src/fw/smp.c
new file mode 100644
index 000000000..a466ea6e9
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/smp.c
@@ -0,0 +1,153 @@
+// QEMU multi-CPU initialization code
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "hw/rtc.h" // CMOS_BIOS_SMP_COUNT
+#include "output.h" // dprintf
+#include "romfile.h" // romfile_loadint
+#include "stacks.h" // yield
+#include "util.h" // smp_setup
+#include "x86.h" // wrmsr
+
+#define APIC_ICR_LOW ((u8*)BUILD_APIC_ADDR + 0x300)
+#define APIC_SVR ((u8*)BUILD_APIC_ADDR + 0x0F0)
+#define APIC_LINT0 ((u8*)BUILD_APIC_ADDR + 0x350)
+#define APIC_LINT1 ((u8*)BUILD_APIC_ADDR + 0x360)
+
+#define APIC_ENABLED 0x0100
+
+static struct { u32 index; u64 val; } smp_mtrr[32];
+static u32 smp_mtrr_count;
+
+void
+wrmsr_smp(u32 index, u64 val)
+{
+ wrmsr(index, val);
+ if (smp_mtrr_count >= ARRAY_SIZE(smp_mtrr)) {
+ warn_noalloc();
+ return;
+ }
+ smp_mtrr[smp_mtrr_count].index = index;
+ smp_mtrr[smp_mtrr_count].val = val;
+ smp_mtrr_count++;
+}
+
+u32 MaxCountCPUs;
+static u32 CountCPUs;
+// 256 bits for the found APIC IDs
+static u32 FoundAPICIDs[256/32];
+
+int apic_id_is_present(u8 apic_id)
+{
+ return !!(FoundAPICIDs[apic_id/32] & (1ul << (apic_id % 32)));
+}
+
+void VISIBLE32FLAT
+handle_smp(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ // Enable CPU caching
+ setcr0(getcr0() & ~(CR0_CD|CR0_NW));
+
+ // Detect apic_id
+ u32 eax, ebx, ecx, cpuid_features;
+ cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+ u8 apic_id = ebx>>24;
+ dprintf(DEBUG_HDL_smp, "handle_smp: apic_id=%d\n", apic_id);
+
+ // MTRR setup
+ int i;
+ for (i=0; i<smp_mtrr_count; i++)
+ wrmsr(smp_mtrr[i].index, smp_mtrr[i].val);
+
+ // Set bit on FoundAPICIDs
+ FoundAPICIDs[apic_id/32] |= (1 << (apic_id % 32));
+
+ CountCPUs++;
+}
+
+// Atomic lock for shared stack across processors.
+u32 SMPLock __VISIBLE;
+u32 SMPStack __VISIBLE;
+
+// find and initialize the CPUs by launching a SIPI to them
+void
+smp_setup(void)
+{
+ if (!CONFIG_QEMU)
+ return;
+
+ ASSERT32FLAT();
+ u32 eax, ebx, ecx, cpuid_features;
+ cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+ if (eax < 1 || !(cpuid_features & CPUID_APIC)) {
+ // No apic - only the main cpu is present.
+ dprintf(1, "No apic - only the main cpu is present.\n");
+ CountCPUs= 1;
+ MaxCountCPUs = 1;
+ return;
+ }
+
+ // mark the BSP initial APIC ID as found, too:
+ u8 apic_id = ebx>>24;
+ FoundAPICIDs[apic_id/32] |= (1 << (apic_id % 32));
+ CountCPUs = 1;
+
+ // Setup jump trampoline to counter code.
+ u64 old = *(u64*)BUILD_AP_BOOT_ADDR;
+ // ljmpw $SEG_BIOS, $(entry_smp - BUILD_BIOS_ADDR)
+ extern void entry_smp(void);
+ u64 new = (0xea | ((u64)SEG_BIOS<<24)
+ | (((u32)entry_smp - BUILD_BIOS_ADDR) << 8));
+ *(u64*)BUILD_AP_BOOT_ADDR = new;
+
+ // enable local APIC
+ u32 val = readl(APIC_SVR);
+ writel(APIC_SVR, val | APIC_ENABLED);
+
+ /* Set LINT0 as Ext_INT, level triggered */
+ writel(APIC_LINT0, 0x8700);
+
+ /* Set LINT1 as NMI, level triggered */
+ writel(APIC_LINT1, 0x8400);
+
+ // Init the lock.
+ writel(&SMPLock, 1);
+
+ // broadcast SIPI
+ barrier();
+ writel(APIC_ICR_LOW, 0x000C4500);
+ u32 sipi_vector = BUILD_AP_BOOT_ADDR >> 12;
+ writel(APIC_ICR_LOW, 0x000C4600 | sipi_vector);
+
+ // Wait for other CPUs to process the SIPI.
+ u8 cmos_smp_count = rtc_read(CMOS_BIOS_SMP_COUNT) + 1;
+ while (cmos_smp_count != CountCPUs)
+ asm volatile(
+ // Release lock and allow other processors to use the stack.
+ " movl %%esp, %1\n"
+ " movl $0, %0\n"
+ // Reacquire lock and take back ownership of stack.
+ "1:rep ; nop\n"
+ " lock btsl $0, %0\n"
+ " jc 1b\n"
+ : "+m" (SMPLock), "+m" (SMPStack)
+ : : "cc", "memory");
+ yield();
+
+ // Restore memory.
+ *(u64*)BUILD_AP_BOOT_ADDR = old;
+
+ MaxCountCPUs = romfile_loadint("etc/max-cpus", 0);
+ if (!MaxCountCPUs || MaxCountCPUs < CountCPUs)
+ MaxCountCPUs = CountCPUs;
+
+ dprintf(1, "Found %d cpu(s) max supported %d cpu(s)\n", CountCPUs,
+ MaxCountCPUs);
+}
diff --git a/qemu/roms/seabios/src/fw/ssdt-misc.dsl b/qemu/roms/seabios/src/fw/ssdt-misc.dsl
new file mode 100644
index 000000000..acc850e84
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/ssdt-misc.dsl
@@ -0,0 +1,104 @@
+ACPI_EXTRACT_ALL_CODE ssdp_misc_aml
+
+DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 0x1)
+{
+
+/****************************************************************
+ * PCI memory ranges
+ ****************************************************************/
+
+ Scope(\) {
+ ACPI_EXTRACT_NAME_DWORD_CONST acpi_pci32_start
+ Name(P0S, 0x12345678)
+ ACPI_EXTRACT_NAME_DWORD_CONST acpi_pci32_end
+ Name(P0E, 0x12345678)
+ ACPI_EXTRACT_NAME_BYTE_CONST acpi_pci64_valid
+ Name(P1V, 0x12)
+ ACPI_EXTRACT_NAME_BUFFER8 acpi_pci64_start
+ Name(P1S, Buffer() { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 })
+ ACPI_EXTRACT_NAME_BUFFER8 acpi_pci64_end
+ Name(P1E, Buffer() { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 })
+ ACPI_EXTRACT_NAME_BUFFER8 acpi_pci64_length
+ Name(P1L, Buffer() { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 })
+ }
+
+
+/****************************************************************
+ * Suspend
+ ****************************************************************/
+
+ Scope(\) {
+ /*
+ * S3 (suspend-to-ram), S4 (suspend-to-disk) and S5 (power-off) type codes:
+ * must match piix4 emulation.
+ */
+
+ ACPI_EXTRACT_NAME_STRING acpi_s3_name
+ Name(_S3, Package(0x04) {
+ One, /* PM1a_CNT.SLP_TYP */
+ One, /* PM1b_CNT.SLP_TYP */
+ Zero, /* reserved */
+ Zero /* reserved */
+ })
+ ACPI_EXTRACT_NAME_STRING acpi_s4_name
+ ACPI_EXTRACT_PKG_START acpi_s4_pkg
+ Name(_S4, Package(0x04) {
+ 0x2, /* PM1a_CNT.SLP_TYP */
+ 0x2, /* PM1b_CNT.SLP_TYP */
+ Zero, /* reserved */
+ Zero /* reserved */
+ })
+ Name(_S5, Package(0x04) {
+ Zero, /* PM1a_CNT.SLP_TYP */
+ Zero, /* PM1b_CNT.SLP_TYP */
+ Zero, /* reserved */
+ Zero /* reserved */
+ })
+ }
+
+ External(\_SB.PCI0, DeviceObj)
+ External(\_SB.PCI0.ISA, DeviceObj)
+
+ Scope(\_SB.PCI0.ISA) {
+ Device(PEVT) {
+ Name(_HID, "QEMU0001")
+ /* PEST will be patched to be Zero if no such device */
+ ACPI_EXTRACT_NAME_WORD_CONST ssdt_isa_pest
+ Name(PEST, 0xFFFF)
+ OperationRegion(PEOR, SystemIO, PEST, 0x01)
+ Field(PEOR, ByteAcc, NoLock, Preserve) {
+ PEPT, 8,
+ }
+
+ Method(_STA, 0, NotSerialized) {
+ Store(PEST, Local0)
+ If (LEqual(Local0, Zero)) {
+ Return (0x00)
+ } Else {
+ Return (0x0F)
+ }
+ }
+
+ Method(RDPT, 0, NotSerialized) {
+ Store(PEPT, Local0)
+ Return (Local0)
+ }
+
+ Method(WRPT, 1, NotSerialized) {
+ Store(Arg0, PEPT)
+ }
+
+ Name(_CRS, ResourceTemplate() {
+ IO(Decode16, 0x00, 0x00, 0x01, 0x01, IO)
+ })
+
+ CreateWordField(_CRS, IO._MIN, IOMN)
+ CreateWordField(_CRS, IO._MAX, IOMX)
+
+ Method(_INI, 0, NotSerialized) {
+ Store(PEST, IOMN)
+ Store(PEST, IOMX)
+ }
+ }
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/ssdt-pcihp.dsl b/qemu/roms/seabios/src/fw/ssdt-pcihp.dsl
new file mode 100644
index 000000000..cb24c11ce
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/ssdt-pcihp.dsl
@@ -0,0 +1,36 @@
+ACPI_EXTRACT_ALL_CODE ssdp_pcihp_aml
+
+DefinitionBlock ("ssdt-pcihp.aml", "SSDT", 0x01, "BXPC", "BXSSDTPCIHP", 0x1)
+{
+
+/****************************************************************
+ * PCI hotplug
+ ****************************************************************/
+
+ /* Objects supplied by DSDT */
+ External(\_SB.PCI0, DeviceObj)
+ External(\_SB.PCI0.PCEJ, MethodObj)
+
+ Scope(\_SB.PCI0) {
+
+ /* Bulk generated PCI hotplug devices */
+ ACPI_EXTRACT_DEVICE_START ssdt_pcihp_start
+ ACPI_EXTRACT_DEVICE_END ssdt_pcihp_end
+ ACPI_EXTRACT_DEVICE_STRING ssdt_pcihp_name
+
+ // Method _EJ0 can be patched by BIOS to EJ0_
+ // at runtime, if the slot is detected to not support hotplug.
+ // Extract the offset of the address dword and the
+ // _EJ0 name to allow this patching.
+ Device(SAA) {
+ ACPI_EXTRACT_NAME_BYTE_CONST ssdt_pcihp_id
+ Name(_SUN, 0xAA)
+ ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pcihp_adr
+ Name(_ADR, 0xAA0000)
+ ACPI_EXTRACT_METHOD_STRING ssdt_pcihp_ej0
+ Method(_EJ0, 1) {
+ PCEJ(_SUN)
+ }
+ }
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/ssdt-proc.dsl b/qemu/roms/seabios/src/fw/ssdt-proc.dsl
new file mode 100644
index 000000000..407d61ead
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/ssdt-proc.dsl
@@ -0,0 +1,48 @@
+/* This file is the basis for the ssdt table generated in src/acpi.c.
+ * It defines the contents of the per-cpu Processor() object. At
+ * runtime, a dynamically generated SSDT will contain one copy of this
+ * AML snippet for every possible cpu in the system. The objects will
+ * be placed in the \_SB_ namespace.
+ *
+ * In addition to the aml code generated from this file, the
+ * src/acpi.c file creates a NTFY method with an entry for each cpu:
+ * Method(NTFY, 2) {
+ * If (LEqual(Arg0, 0x00)) { Notify(CP00, Arg1) }
+ * If (LEqual(Arg0, 0x01)) { Notify(CP01, Arg1) }
+ * ...
+ * }
+ * and a CPON array with the list of active and inactive cpus:
+ * Name(CPON, Package() { One, One, ..., Zero, Zero, ... })
+ */
+
+ACPI_EXTRACT_ALL_CODE ssdp_proc_aml
+
+DefinitionBlock ("ssdt-proc.aml", "SSDT", 0x01, "BXPC", "BXSSDT", 0x1)
+{
+ ACPI_EXTRACT_PROCESSOR_START ssdt_proc_start
+ ACPI_EXTRACT_PROCESSOR_END ssdt_proc_end
+ ACPI_EXTRACT_PROCESSOR_STRING ssdt_proc_name
+ Processor(CPAA, 0xAA, 0x0000b010, 0x06) {
+ ACPI_EXTRACT_NAME_BYTE_CONST ssdt_proc_id
+ Name(ID, 0xAA)
+/*
+ * The src/acpi.c code requires the above ACP_EXTRACT tags so that it can update
+ * CPAA and 0xAA with the appropriate CPU id (see
+ * SD_OFFSET_CPUHEX/CPUID1/CPUID2). Don't change the above without
+ * also updating the C code.
+ */
+ Name(_HID, "ACPI0007")
+ External(CPMA, MethodObj)
+ External(CPST, MethodObj)
+ External(CPEJ, MethodObj)
+ Method(_MAT, 0) {
+ Return (CPMA(ID))
+ }
+ Method(_STA, 0) {
+ Return (CPST(ID))
+ }
+ Method(_EJ0, 1, NotSerialized) {
+ CPEJ(ID, Arg0)
+ }
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/xen.c b/qemu/roms/seabios/src/fw/xen.c
new file mode 100644
index 000000000..dd8e8afd4
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/xen.c
@@ -0,0 +1,147 @@
+// Xen HVM support
+//
+// Copyright (C) 2011 Citrix Systems.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h"
+#include "hw/serialio.h" // DebugOutputPort
+#include "malloc.h" // memalign_high
+#include "memmap.h" // add_e820
+#include "output.h" // dprintf
+#include "paravirt.h" // PlatformRunningOn
+#include "string.h" // memcpy
+#include "util.h" // copy_acpi_rsdp
+#include "x86.h" // cpuid
+#include "xen.h"
+
+#define INFO_PHYSICAL_ADDRESS 0x00001000
+
+u32 xen_cpuid_base = 0;
+unsigned long xen_hypercall_page = 0;
+
+struct xen_seabios_info {
+ char signature[14]; /* XenHVMSeaBIOS\0 */
+ u8 length; /* Length of this struct */
+ u8 checksum; /* Set such that the sum over bytes 0..length == 0 */
+ /*
+ * Physical address of an array of tables_nr elements.
+ *
+ * Each element is a 32 bit value contianing the physical address
+ * of a BIOS table.
+ */
+ u32 tables;
+ u32 tables_nr;
+ /*
+ * Physical address of the e820 table, contains e820_nr entries.
+ */
+ u32 e820;
+ u32 e820_nr;
+} PACKED;
+
+static void validate_info(struct xen_seabios_info *t)
+{
+ if ( memcmp(t->signature, "XenHVMSeaBIOS", 14) )
+ panic("Bad Xen info signature\n");
+
+ if ( t->length < sizeof(struct xen_seabios_info) )
+ panic("Bad Xen info length\n");
+
+ if (checksum(t, t->length) != 0)
+ panic("Bad Xen info checksum\n");
+}
+
+void xen_preinit(void)
+{
+ u32 base, eax, ebx, ecx, edx;
+ char signature[13];
+
+ if (!CONFIG_XEN)
+ return;
+
+ for (base = 0x40000000; base < 0x40010000; base += 0x100) {
+ cpuid(base, &eax, &ebx, &ecx, &edx);
+ memcpy(signature + 0, &ebx, 4);
+ memcpy(signature + 4, &ecx, 4);
+ memcpy(signature + 8, &edx, 4);
+ signature[12] = 0;
+
+ dprintf(9, "Found hypervisor signature \"%s\" at %x\n",
+ signature, base);
+ if (strcmp(signature, "XenVMMXenVMM") == 0) {
+ /* Set debug_io_port first, so the following messages work. */
+ DebugOutputPort = 0xe9;
+ debug_banner();
+ dprintf(1, "\nFound Xen hypervisor signature at %x\n", base);
+ if ((eax - base) < 2)
+ panic("Insufficient Xen cpuid leaves. eax=%x at base %x\n",
+ eax, base);
+ xen_cpuid_base = base;
+ break;
+ }
+ }
+ if (!xen_cpuid_base) {
+ dprintf(1, "No Xen hypervisor found.\n");
+ return;
+ }
+ PlatformRunningOn = PF_QEMU|PF_XEN;
+}
+
+static int hypercall_xen_version( int cmd, void *arg)
+{
+ return _hypercall2(int, xen_version, cmd, arg);
+}
+
+/* Fill in hypercall transfer pages. */
+void xen_hypercall_setup(void)
+{
+ u32 eax, ebx, ecx, edx;
+ xen_extraversion_t extraversion;
+ unsigned long i;
+
+ if (!runningOnXen())
+ return;
+
+ cpuid(xen_cpuid_base + 2, &eax, &ebx, &ecx, &edx);
+
+ xen_hypercall_page = (unsigned long)memalign_high(PAGE_SIZE, eax*PAGE_SIZE);
+ if (!xen_hypercall_page)
+ panic("unable to allocate Xen hypercall page\n");
+
+ dprintf(1, "Allocated Xen hypercall page at %lx\n", xen_hypercall_page);
+ for ( i = 0; i < eax; i++ )
+ wrmsr(ebx, xen_hypercall_page + (i << 12) + i);
+
+ /* Print version information. */
+ cpuid(xen_cpuid_base + 1, &eax, &ebx, &ecx, &edx);
+ hypercall_xen_version(XENVER_extraversion, extraversion);
+ dprintf(1, "Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
+}
+
+void xen_biostable_setup(void)
+{
+ struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS;
+ void **tables = (void*)info->tables;
+ int i;
+
+ dprintf(1, "xen: copy BIOS tables...\n");
+ for (i=0; i<info->tables_nr; i++)
+ copy_table(tables[i]);
+
+ find_acpi_features();
+}
+
+void xen_ramsize_preinit(void)
+{
+ int i;
+ struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS;
+ struct e820entry *e820 = (struct e820entry *)info->e820;
+ validate_info(info);
+
+ dprintf(1, "xen: copy e820...\n");
+
+ for (i = 0; i < info->e820_nr; i++) {
+ struct e820entry *e = &e820[i];
+ add_e820(e->start, e->size, e->type);
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/xen.h b/qemu/roms/seabios/src/fw/xen.h
new file mode 100644
index 000000000..f00f8407d
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/xen.h
@@ -0,0 +1,125 @@
+#ifndef __XEN_H
+#define __XEN_H
+
+void xen_preinit(void);
+void xen_ramsize_preinit(void);
+void xen_hypercall_setup(void);
+void xen_biostable_setup(void);
+
+extern unsigned long xen_hypercall_page;
+
+#define _hypercall0(type, name) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res) \
+ : "0" (__hentry) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall1(type, name, a1) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1) \
+ : "0" (__hentry), "1" ((long)(a1)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall2(type, name, a1, a2) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall3(type, name, a1, a2, a3) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2, __ign3; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall4(type, name, a1, a2, a3, a4) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2, __ign3, __ign4; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)), \
+ "5" ((long)(a5)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+/******************************************************************************
+ *
+ * The following interface definitions are taken from Xen and have the
+ * following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* xen.h */
+
+#define __HYPERVISOR_xen_version 17
+
+/* version.h */
+
+/* arg == xen_extraversion_t. */
+#define XENVER_extraversion 1
+typedef char xen_extraversion_t[16];
+#define XEN_EXTRAVERSION_LEN (sizeof(xen_extraversion_t))
+
+#endif