Hi,
This patch series makes the PCI I/O windows runtime-configurable via qemu firmware config interface. Main advantage is that we can size and shuffle around the PCI i/O windows according to the amount of memory the virtual machine has. We don't need a hole for 64bit PCI bars, we can just map them above the main memory. The hole for 32bit PCI bars can be enlarged for guests with less than 3.5 GB of memory.
Oh, and the pci device initialization fix is there too ;)
cheers, Gerd
Gerd Hoffmann (5): pci: init all devices acpi: add qemu fwcfg driver acpi: update pci io windows according to fw_cfg info pciinit: make pci ressources configurable update src/acpi-dsdt.hex
src/acpi-dsdt.dsl | 81 ++++++++++- src/acpi-dsdt.hex | 420 +++++++++++++++++++++++++++++++++++++++++++++++++++-- src/paravirt.c | 8 + src/paravirt.h | 2 + src/pciinit.c | 32 +++- 5 files changed, 522 insertions(+), 21 deletions(-)
seabios used to initialize root bus devices only, with this patch devices behind pci bridges are initialized too. This allows to boot from virtio devices behind pci bridges.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/pciinit.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/src/pciinit.c b/src/pciinit.c index 25b04ac..6a7a0d2 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -213,9 +213,6 @@ static void pci_bios_init_devices(void) { struct pci_device *pci; foreachpci(pci) { - if (pci_bdf_to_bus(pci->bdf) != 0) - // Only init devices on host bus. - break; pci_bios_init_device(pci); }
On Fri, May 04, 2012 at 10:21:23AM +0200, Gerd Hoffmann wrote:
seabios used to initialize root bus devices only, with this patch devices behind pci bridges are initialized too. This allows to boot from virtio devices behind pci bridges.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com
src/pciinit.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/src/pciinit.c b/src/pciinit.c index 25b04ac..6a7a0d2 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -213,9 +213,6 @@ static void pci_bios_init_devices(void) { struct pci_device *pci; foreachpci(pci) {
if (pci_bdf_to_bus(pci->bdf) != 0)
// Only init devices on host bus.
break;
I think this will then assign an incorrect PCI_INTERRUPT_LINE value to non root bus devices.
-Kevin
On 05/04/12 15:15, Kevin O'Connor wrote:
On Fri, May 04, 2012 at 10:21:23AM +0200, Gerd Hoffmann wrote:
seabios used to initialize root bus devices only, with this patch devices behind pci bridges are initialized too. This allows to boot from virtio devices behind pci bridges.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com
src/pciinit.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/src/pciinit.c b/src/pciinit.c index 25b04ac..6a7a0d2 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -213,9 +213,6 @@ static void pci_bios_init_devices(void) { struct pci_device *pci; foreachpci(pci) {
if (pci_bdf_to_bus(pci->bdf) != 0)
// Only init devices on host bus.
break;
I think this will then assign an incorrect PCI_INTERRUPT_LINE value to non root bus devices.
Attached patch should fix it if I read the specs correctly. Untested though, review appreciated.
cheers, Gerd
On Fri, May 04, 2012 at 05:35:10PM +0200, Gerd Hoffmann wrote:
On 05/04/12 15:15, Kevin O'Connor wrote:
On Fri, May 04, 2012 at 10:21:23AM +0200, Gerd Hoffmann wrote:
seabios used to initialize root bus devices only, with this patch devices behind pci bridges are initialized too. This allows to boot from virtio devices behind pci bridges.
[...]
I think this will then assign an incorrect PCI_INTERRUPT_LINE value to non root bus devices.
Attached patch should fix it if I read the specs correctly. Untested though, review appreciated.
It looks good to me from a read of the spec as well. I'm not sure how to test it.
-Kevin
On Fri, May 04, 2012 at 05:35:10PM +0200, Gerd Hoffmann wrote:
On 05/04/12 15:15, Kevin O'Connor wrote:
On Fri, May 04, 2012 at 10:21:23AM +0200, Gerd Hoffmann wrote:
seabios used to initialize root bus devices only, with this patch devices behind pci bridges are initialized too. This allows to boot from virtio devices behind pci bridges.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com
src/pciinit.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/src/pciinit.c b/src/pciinit.c index 25b04ac..6a7a0d2 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -213,9 +213,6 @@ static void pci_bios_init_devices(void) { struct pci_device *pci; foreachpci(pci) {
if (pci_bdf_to_bus(pci->bdf) != 0)
// Only init devices on host bus.
break;
I think this will then assign an incorrect PCI_INTERRUPT_LINE value to non root bus devices.
Attached patch should fix it if I read the specs correctly.
I committed this patch.
-Kevin
Add a acpi driver for the qemu firmware config interface.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/acpi-dsdt.dsl | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 43 insertions(+), 0 deletions(-)
diff --git a/src/acpi-dsdt.dsl b/src/acpi-dsdt.dsl index 4a18617..d71b783 100644 --- a/src/acpi-dsdt.dsl +++ b/src/acpi-dsdt.dsl @@ -445,6 +445,49 @@ DefinitionBlock ( Return (BUF0) } } + + /* qemu firmware config interface */ + Device (FWC) + { + Name (_HID, EisaId ("FWC0510")) + OperationRegion (FWCD, SystemIO, 0x0510, 0x02) + Field (FWCD, WordAcc, NoLock, Preserve) + { + FWCS, 16, /* select */ + } + Field (FWCD, ByteAcc, NoLock, Preserve) + { + FWCW, 8, /* write */ + FWCR, 8, /* read */ + } + Name (_CRS, ResourceTemplate () + { + IO (Decode16, 0x0510, 0x0510, 0x01, 0x02) + }) + + /* fetch fw_cfg entry, args: entry nr, length */ + Method (FWCB, 2) { + Name (RETB, Buffer(Arg1) { }) + Store (Arg0, FWCS) + Store (Zero, Local0) + While (LLess(Local0, Arg1)) { + Store (FWCR, Index(RETB, Local0)) + Increment(Local0) + } + Return (RETB) + } + + /* fetch signature & verify */ + Method (_STA, 0, NotSerialized) + { + Store(ToString(FWCB(0, 4)), Local0) + If (LEqual (Local0, "QEMU")) { + Return (0x0f) + } Else { + Return (0x00) + } + } + } }
This patch makes the pci ressources runtime configurable. The patch fetches the pci window information from the qemu firmware config interface and in case valid data is found there the ressource entries are updated accordingly.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/acpi-dsdt.dsl | 38 +++++++++++++++++++++++++++++++++++--- 1 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/src/acpi-dsdt.dsl b/src/acpi-dsdt.dsl index d71b783..4e6c2ad 100644 --- a/src/acpi-dsdt.dsl +++ b/src/acpi-dsdt.dsl @@ -132,7 +132,7 @@ DefinitionBlock ( B0EJ, 32, }
- Name (_CRS, ResourceTemplate () + Name (CRES, ResourceTemplate () { WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, 0x0000, // Address Space Granularity @@ -174,15 +174,47 @@ DefinitionBlock ( 0xFEBFFFFF, // Address Range Maximum 0x00000000, // Address Translation Offset 0x1EC00000, // Address Length - ,, , AddressRangeMemory, TypeStatic) + ,, PW32, AddressRangeMemory, TypeStatic) 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 - ,, , AddressRangeMemory, TypeStatic) + ,, PW64, AddressRangeMemory, TypeStatic) }) + Method (_INI, 0) + { + Store (_SB.PCI0.ISA.FWC.FWCB(0x1a, 64), Local0) + CreateQWordField (Local0, 0, QW0) + CreateQWordField (Local0, 8, QW1) + CreateQWordField (Local0, 16, QW2) + CreateQWordField (Local0, 24, QW3) + + /* 32bit pci io window */ + If (LAnd (LNotEqual(QW0, 0), LNotEqual(QW1, 0))) { + CreateDWordField (CRES,_SB.PCI0.PW32._MIN, PS32) + CreateDWordField (CRES,_SB.PCI0.PW32._MAX, PE32) + CreateDWordField (CRES,_SB.PCI0.PW32._LEN, PL32) + Store (QW0, PS32) + Store (QW1, PE32) + Subtract (QW1, QW0, PL32) + } + + /* 64bit pci io window */ + If (LAnd (LNotEqual(QW2, 0), LNotEqual(QW3, 0))) { + CreateQWordField (CRES,_SB.PCI0.PW64._MIN, PS64) + CreateQWordField (CRES,_SB.PCI0.PW64._MAX, PE64) + CreateQWordField (CRES,_SB.PCI0.PW64._LEN, PL64) + Store (QW2, PS64) + Store (QW3, PE64) + Subtract (QW3, QW2, PL64) + } + } + Method (_CRS, 0) + { + Return (CRES) + } } }
Try to get the pci window information from the qemu firmware config interface and use them if available, otherwise fall back to the compile time defaults.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/paravirt.c | 8 ++++++++ src/paravirt.h | 2 ++ src/pciinit.c | 29 ++++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/src/paravirt.c b/src/paravirt.c index 9cf77de..61ed086 100644 --- a/src/paravirt.c +++ b/src/paravirt.c @@ -305,6 +305,14 @@ u16 qemu_cfg_get_max_cpus(void) return cnt; }
+void qemu_cfg_get_pci_windows(u64 *pcimem) +{ + if (!qemu_cfg_present) + return; + + qemu_cfg_read_entry(pcimem, QEMU_CFG_PCI_WINDOWS, 64); +} + static QemuCfgFile LastFile;
static u32 diff --git a/src/paravirt.h b/src/paravirt.h index f39e226..6dc8ede 100644 --- a/src/paravirt.h +++ b/src/paravirt.h @@ -35,6 +35,7 @@ static inline int kvm_para_available(void) #define QEMU_CFG_BOOT_MENU 0x0e #define QEMU_CFG_MAX_CPUS 0x0f #define QEMU_CFG_FILE_DIR 0x19 +#define QEMU_CFG_PCI_WINDOWS 0x1a #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) @@ -57,6 +58,7 @@ int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs, int qemu_cfg_get_numa_nodes(void); void qemu_cfg_get_numa_data(u64 *data, int n); u16 qemu_cfg_get_max_cpus(void); +void qemu_cfg_get_pci_windows(u64 *pcimem);
typedef struct QemuCfgFile { u32 size; /* file size */ diff --git a/src/pciinit.c b/src/pciinit.c index 6a7a0d2..52c5b69 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -11,6 +11,7 @@ #include "pci_ids.h" // PCI_VENDOR_ID_INTEL #include "pci_regs.h" // PCI_COMMAND #include "xen.h" // usingXen +#include "paravirt.h" // qemu_cfg_get_pci_windows
#define PCI_DEVICE_MEM_MIN 0x1000 #define PCI_BRIDGE_IO_MIN 0x1000 @@ -29,6 +30,12 @@ static const char *region_type_name[] = { [ PCI_REGION_TYPE_PREFMEM ] = "prefmem", };
+static u64 pcimem[4]; +static u64 pcimem_start = BUILD_PCIMEM_START; +static u64 pcimem_end = BUILD_PCIMEM_END; +static u64 pcimem64_start = BUILD_PCIMEM64_START; +static u64 pcimem64_end = BUILD_PCIMEM64_END; + struct pci_region_entry { struct pci_device *dev; int bar; @@ -511,13 +518,13 @@ static int pci_bios_init_root_regions(struct pci_bus *bus) } u64 sum = pci_region_sum(r_end); u64 align = pci_region_align(r_end); - r_end->base = ALIGN_DOWN((BUILD_PCIMEM_END - sum), align); + 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 < BUILD_PCIMEM_START) || - (r_start->base > BUILD_PCIMEM_END)) + if ((r_start->base < pcimem_start) || + (r_start->base > pcimem_end)) // Memory range requested is larger than available. return -1; return 0; @@ -595,11 +602,11 @@ static void pci_bios_map_devices(struct pci_bus *busses) if (pci_bios_init_root_regions(busses)) panic("PCI: out of 32bit address space\n");
- r64_mem.base = BUILD_PCIMEM64_START; + r64_mem.base = pcimem64_start; u64 sum = pci_region_sum(&r64_mem); u64 align = pci_region_align(&r64_pref); r64_pref.base = ALIGN(r64_mem.base + sum, align); - if (r64_pref.base + pci_region_sum(&r64_pref) > BUILD_PCIMEM64_END) + if (r64_pref.base + pci_region_sum(&r64_pref) > pcimem64_end) panic("PCI: out of 64bit address space\n"); pci_region_map_entries(busses, &r64_mem); pci_region_map_entries(busses, &r64_pref); @@ -629,6 +636,18 @@ pci_setup(void)
dprintf(3, "pci setup\n");
+ qemu_cfg_get_pci_windows(pcimem); + if (pcimem[0] && pcimem[1]) { + pcimem_start = pcimem[0]; + pcimem_end = pcimem[1] + 1; + dprintf(1, "32bit pci window: %llx - %llx\n", pcimem_start, pcimem_end); + } + if (pcimem[2] && pcimem[3]) { + pcimem64_start = pcimem[2]; + pcimem64_end = pcimem[3] + 1; + dprintf(1, "64bit pci window: %llx - %llx\n", pcimem64_start, pcimem64_end); + } + dprintf(1, "=== PCI bus & bridge init ===\n"); if (pci_probe_host() != 0) { return;
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/acpi-dsdt.hex | 420 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 410 insertions(+), 10 deletions(-)
diff --git a/src/acpi-dsdt.hex b/src/acpi-dsdt.hex index 07f0e18..16b3e37 100644 --- a/src/acpi-dsdt.hex +++ b/src/acpi-dsdt.hex @@ -3,12 +3,12 @@ static unsigned char AmlCode[] = { 0x53, 0x44, 0x54, -0x4f, -0x11, +0xdf, +0x12, 0x0, 0x0, 0x1, -0xca, +0x9, 0x42, 0x58, 0x50, @@ -110,16 +110,16 @@ static unsigned char AmlCode[] = { 0x47, 0x42, 0x10, -0x42, -0x84, +0x4e, +0x92, 0x5f, 0x53, 0x42, 0x5f, 0x5b, 0x82, -0x4a, -0x83, +0x46, +0x92, 0x50, 0x43, 0x49, @@ -2059,9 +2059,9 @@ static unsigned char AmlCode[] = { 0x4a, 0x20, 0x8, -0x5f, 0x43, 0x52, +0x45, 0x53, 0x11, 0x40, @@ -2224,6 +2224,242 @@ static unsigned char AmlCode[] = { 0x0, 0x79, 0x0, +0x14, +0x4f, +0xd, +0x5f, +0x49, +0x4e, +0x49, +0x0, +0x70, +0x5e, +0x2f, +0x3, +0x49, +0x53, +0x41, +0x5f, +0x46, +0x57, +0x43, +0x5f, +0x46, +0x57, +0x43, +0x42, +0xa, +0x1a, +0xa, +0x40, +0x60, +0x8f, +0x60, +0x0, +0x51, +0x57, +0x30, +0x5f, +0x8f, +0x60, +0xa, +0x8, +0x51, +0x57, +0x31, +0x5f, +0x8f, +0x60, +0xa, +0x10, +0x51, +0x57, +0x32, +0x5f, +0x8f, +0x60, +0xa, +0x18, +0x51, +0x57, +0x33, +0x5f, +0xa0, +0x41, +0x5, +0x90, +0x92, +0x93, +0x51, +0x57, +0x30, +0x5f, +0x0, +0x92, +0x93, +0x51, +0x57, +0x31, +0x5f, +0x0, +0x8a, +0x43, +0x52, +0x45, +0x53, +0xa, +0x5c, +0x50, +0x53, +0x33, +0x32, +0x8a, +0x43, +0x52, +0x45, +0x53, +0xa, +0x60, +0x50, +0x45, +0x33, +0x32, +0x8a, +0x43, +0x52, +0x45, +0x53, +0xa, +0x68, +0x50, +0x4c, +0x33, +0x32, +0x70, +0x51, +0x57, +0x30, +0x5f, +0x50, +0x53, +0x33, +0x32, +0x70, +0x51, +0x57, +0x31, +0x5f, +0x50, +0x45, +0x33, +0x32, +0x74, +0x51, +0x57, +0x31, +0x5f, +0x51, +0x57, +0x30, +0x5f, +0x50, +0x4c, +0x33, +0x32, +0xa0, +0x41, +0x5, +0x90, +0x92, +0x93, +0x51, +0x57, +0x32, +0x5f, +0x0, +0x92, +0x93, +0x51, +0x57, +0x33, +0x5f, +0x0, +0x8f, +0x43, +0x52, +0x45, +0x53, +0xa, +0x7a, +0x50, +0x53, +0x36, +0x34, +0x8f, +0x43, +0x52, +0x45, +0x53, +0xa, +0x82, +0x50, +0x45, +0x36, +0x34, +0x8f, +0x43, +0x52, +0x45, +0x53, +0xa, +0x92, +0x50, +0x4c, +0x36, +0x34, +0x70, +0x51, +0x57, +0x32, +0x5f, +0x50, +0x53, +0x36, +0x34, +0x70, +0x51, +0x57, +0x33, +0x5f, +0x50, +0x45, +0x36, +0x34, +0x74, +0x51, +0x57, +0x33, +0x5f, +0x51, +0x57, +0x32, +0x5f, +0x50, +0x4c, +0x36, +0x34, +0x14, +0xb, +0x5f, +0x43, +0x52, +0x53, +0x0, +0xa4, +0x43, +0x52, +0x45, +0x53, 0x10, 0x4b, 0x9, @@ -2517,8 +2753,8 @@ static unsigned char AmlCode[] = { 0xa, 0x4, 0x10, -0x47, -0x22, +0x4b, +0x2c, 0x2f, 0x3, 0x5f, @@ -3068,6 +3304,170 @@ static unsigned char AmlCode[] = { 0x55, 0x46, 0x30, +0x5b, +0x82, +0x42, +0xa, +0x46, +0x57, +0x43, +0x5f, +0x8, +0x5f, +0x48, +0x49, +0x44, +0xc, +0x1a, +0xe3, +0x5, +0x10, +0x5b, +0x80, +0x46, +0x57, +0x43, +0x44, +0x1, +0xb, +0x10, +0x5, +0xa, +0x2, +0x5b, +0x81, +0xb, +0x46, +0x57, +0x43, +0x44, +0x2, +0x46, +0x57, +0x43, +0x53, +0x10, +0x5b, +0x81, +0x10, +0x46, +0x57, +0x43, +0x44, +0x1, +0x46, +0x57, +0x43, +0x57, +0x8, +0x46, +0x57, +0x43, +0x52, +0x8, +0x8, +0x5f, +0x43, +0x52, +0x53, +0x11, +0xd, +0xa, +0xa, +0x47, +0x1, +0x10, +0x5, +0x10, +0x5, +0x1, +0x2, +0x79, +0x0, +0x14, +0x2f, +0x46, +0x57, +0x43, +0x42, +0x2, +0x8, +0x52, +0x45, +0x54, +0x42, +0x11, +0x2, +0x69, +0x70, +0x68, +0x46, +0x57, +0x43, +0x53, +0x70, +0x0, +0x60, +0xa2, +0x12, +0x95, +0x60, +0x69, +0x70, +0x46, +0x57, +0x43, +0x52, +0x88, +0x52, +0x45, +0x54, +0x42, +0x60, +0x0, +0x75, +0x60, +0xa4, +0x52, +0x45, +0x54, +0x42, +0x14, +0x23, +0x5f, +0x53, +0x54, +0x41, +0x0, +0x70, +0x9c, +0x46, +0x57, +0x43, +0x42, +0x0, +0xa, +0x4, +0xff, +0x0, +0x60, +0xa0, +0xc, +0x93, +0x60, +0xd, +0x51, +0x45, +0x4d, +0x55, +0x0, +0xa4, +0xa, +0xf, +0xa1, +0x3, +0xa4, +0x0, 0x10, 0x4d, 0x5,
On 05/04/12 10:21, Gerd Hoffmann wrote:
Signed-off-by: Gerd Hoffmann kraxel@redhat.com
Topic just came up on irc (#qemu): Any reason to keep the iasl generated files in the git repository? I think pretty much every linux distro has iasl packaged these days, so it shouldn't be a major hassle to depend on it for seabios builds ...
cheers, Gerd
On 04.05.2012 13:04, Gerd Hoffmann wrote:
On 05/04/12 10:21, Gerd Hoffmann wrote:
Signed-off-by: Gerd Hoffmann kraxel@redhat.com
Topic just came up on irc (#qemu): Any reason to keep the iasl generated files in the git repository? I think pretty much every linux distro has iasl packaged these days, so it shouldn't be a major hassle to depend on it for seabios builds ...
There's no need to _depend_ on iasl for building from a tarball. Just add generation of acpi-dsdt.hex in the `make dist' target, or in autogen.sh, or even both - and ship the resulting file in the tarball. This way, the only place where iasl will be needed is when building from git, or when you changed acpi sources (I assume dependencies for acpi-dsdt.hex are specified correctly).
Thanks,
/mjt
On Fri, May 04, 2012 at 10:21:22AM +0200, Gerd Hoffmann wrote:
Hi,
This patch series makes the PCI I/O windows runtime-configurable via qemu firmware config interface. Main advantage is that we can size and shuffle around the PCI i/O windows according to the amount of memory the virtual machine has. We don't need a hole for 64bit PCI bars, we can just map them above the main memory. The hole for 32bit PCI bars can be enlarged for guests with less than 3.5 GB of memory.
Why pass in a PCI IO range through fw_cfg if SeaBIOS can figure out an acceptable range from the amount of memory in the machine?
-Kevin
On 05/04/12 15:18, Kevin O'Connor wrote:
On Fri, May 04, 2012 at 10:21:22AM +0200, Gerd Hoffmann wrote:
Hi,
This patch series makes the PCI I/O windows runtime-configurable via qemu firmware config interface. Main advantage is that we can size and shuffle around the PCI i/O windows according to the amount of memory the virtual machine has. We don't need a hole for 64bit PCI bars, we can just map them above the main memory. The hole for 32bit PCI bars can be enlarged for guests with less than 3.5 GB of memory.
Why pass in a PCI IO range through fw_cfg if SeaBIOS can figure out an acceptable range from the amount of memory in the machine?
Suggestions on how to update the pci host bridge windows in the dsdt then?
cheers, Gerd
On Fri, May 04, 2012 at 04:01:56PM +0200, Gerd Hoffmann wrote:
On 05/04/12 15:18, Kevin O'Connor wrote:
On Fri, May 04, 2012 at 10:21:22AM +0200, Gerd Hoffmann wrote:
Hi,
This patch series makes the PCI I/O windows runtime-configurable via qemu firmware config interface. Main advantage is that we can size and shuffle around the PCI i/O windows according to the amount of memory the virtual machine has. We don't need a hole for 64bit PCI bars, we can just map them above the main memory. The hole for 32bit PCI bars can be enlarged for guests with less than 3.5 GB of memory.
Why pass in a PCI IO range through fw_cfg if SeaBIOS can figure out an acceptable range from the amount of memory in the machine?
Suggestions on how to update the pci host bridge windows in the dsdt then?
Perhaps malloc_high() a struct with the info you need and then create an OperationRegion() in the dynamically generated SSDT with the address of the struct.
-Kevin
On Fri, May 04, 2012 at 10:46:00AM -0400, Kevin O'Connor wrote:
On Fri, May 04, 2012 at 04:01:56PM +0200, Gerd Hoffmann wrote:
On 05/04/12 15:18, Kevin O'Connor wrote:
On Fri, May 04, 2012 at 10:21:22AM +0200, Gerd Hoffmann wrote:
Hi,
This patch series makes the PCI I/O windows runtime-configurable via qemu firmware config interface. Main advantage is that we can size and shuffle around the PCI i/O windows according to the amount of memory the virtual machine has. We don't need a hole for 64bit PCI bars, we can just map them above the main memory. The hole for 32bit PCI bars can be enlarged for guests with less than 3.5 GB of memory.
Why pass in a PCI IO range through fw_cfg if SeaBIOS can figure out an acceptable range from the amount of memory in the machine?
Suggestions on how to update the pci host bridge windows in the dsdt then?
Perhaps malloc_high() a struct with the info you need and then create an OperationRegion() in the dynamically generated SSDT with the address of the struct.
I played with this a little and came up with the below as an example.
-Kevin
diff --git a/src/acpi-dsdt.dsl b/src/acpi-dsdt.dsl index 4a18617..960f9fb 100644 --- a/src/acpi-dsdt.dsl +++ b/src/acpi-dsdt.dsl @@ -132,7 +132,7 @@ DefinitionBlock ( B0EJ, 32, }
- Name (_CRS, ResourceTemplate () + Name (CRES, ResourceTemplate () { WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, 0x0000, // Address Space Granularity @@ -183,6 +183,18 @@ DefinitionBlock ( 0x8000000000, // Address Length ,, , AddressRangeMemory, TypeStatic) }) + Method (_CRS, 0) + { + External (_SB.BDAT) + Field(_SB.BDAT, DWordAcc, NoLock, Preserve) { + VAL1, 32, + VAL2, 32, + } + DBUG("Got") + DBUG(VAL1) + DBUG(VAL2) + Return (CRES) + } } }
diff --git a/src/acpi.c b/src/acpi.c index 30888b9..3e0d4da 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -415,7 +415,8 @@ build_ssdt(void) int length = ((1+3+4) + (acpi_cpus * SD_SIZEOF) + (1+2+5+(12*acpi_cpus)) - + (6+2+1+(1*acpi_cpus))); + + (6+2+1+(1*acpi_cpus)) + + 17); u8 *ssdt = malloc_high(sizeof(struct acpi_table_header) + length); if (! ssdt) { warn_noalloc(); @@ -477,6 +478,26 @@ build_ssdt(void) for (i=0; i<acpi_cpus; i++) *(ssdt_ptr++) = (i < CountCPUs) ? 0x01 : 0x00;
+ // XXX + u32 *myval = malloc_high(sizeof(*myval) * 2); + myval[0] = 0x1234abcd; + myval[1] = 0xdcba8976; + + // build "OperationRegion(BDAT, SystemMemory, 0x12345678, 0x87654321)" + *(ssdt_ptr++) = 0x5B; // ExtOpPrefix + *(ssdt_ptr++) = 0x80; // OpRegionOp + *(ssdt_ptr++) = 'B'; + *(ssdt_ptr++) = 'D'; + *(ssdt_ptr++) = 'A'; + *(ssdt_ptr++) = 'T'; + *(ssdt_ptr++) = 0x00; // SystemMemory + *(ssdt_ptr++) = 0x0C; // DWordPrefix + *(u32*)ssdt_ptr = (u32)myval; + ssdt_ptr += 4; + *(ssdt_ptr++) = 0x0C; // DWordPrefix + *(u32*)ssdt_ptr = sizeof(*myval)*2; + ssdt_ptr += 4; + build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
//hexdump(ssdt, ssdt_ptr - ssdt);
On Fri, May 04, 2012 at 11:37:25AM -0400, Kevin O'Connor wrote:
On Fri, May 04, 2012 at 10:46:00AM -0400, Kevin O'Connor wrote:
On Fri, May 04, 2012 at 04:01:56PM +0200, Gerd Hoffmann wrote:
On 05/04/12 15:18, Kevin O'Connor wrote:
On Fri, May 04, 2012 at 10:21:22AM +0200, Gerd Hoffmann wrote:
Hi,
This patch series makes the PCI I/O windows runtime-configurable via qemu firmware config interface. Main advantage is that we can size and shuffle around the PCI i/O windows according to the amount of memory the virtual machine has. We don't need a hole for 64bit PCI bars, we can just map them above the main memory. The hole for 32bit PCI bars can be enlarged for guests with less than 3.5 GB of memory.
Why pass in a PCI IO range through fw_cfg if SeaBIOS can figure out an acceptable range from the amount of memory in the machine?
Suggestions on how to update the pci host bridge windows in the dsdt then?
Perhaps malloc_high() a struct with the info you need and then create an OperationRegion() in the dynamically generated SSDT with the address of the struct.
I played with this a little and came up with the below as an example.
IMO that is much better than reading fw_cfg from AML. fw_cfg wasn't meant to be touched while OS is running. Another option is to patch the DSDT directly. We have the infrastructure for that in place.
-Kevin
diff --git a/src/acpi-dsdt.dsl b/src/acpi-dsdt.dsl index 4a18617..960f9fb 100644 --- a/src/acpi-dsdt.dsl +++ b/src/acpi-dsdt.dsl @@ -132,7 +132,7 @@ DefinitionBlock ( B0EJ, 32, }
Name (_CRS, ResourceTemplate ()
Name (CRES, ResourceTemplate () { WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, 0x0000, // Address Space Granularity
@@ -183,6 +183,18 @@ DefinitionBlock ( 0x8000000000, // Address Length ,, , AddressRangeMemory, TypeStatic) })
Method (_CRS, 0)
{
External (\_SB.BDAT)
Field(\_SB.BDAT, DWordAcc, NoLock, Preserve) {
VAL1, 32,
VAL2, 32,
}
DBUG("Got")
DBUG(VAL1)
DBUG(VAL2)
Return (CRES)
}} }
diff --git a/src/acpi.c b/src/acpi.c index 30888b9..3e0d4da 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -415,7 +415,8 @@ build_ssdt(void) int length = ((1+3+4) + (acpi_cpus * SD_SIZEOF) + (1+2+5+(12*acpi_cpus))
+ (6+2+1+(1*acpi_cpus)));
+ (6+2+1+(1*acpi_cpus))
u8 *ssdt = malloc_high(sizeof(struct acpi_table_header) + length); if (! ssdt) { warn_noalloc();+ 17);
@@ -477,6 +478,26 @@ build_ssdt(void) for (i=0; i<acpi_cpus; i++) *(ssdt_ptr++) = (i < CountCPUs) ? 0x01 : 0x00;
// XXX
u32 *myval = malloc_high(sizeof(*myval) * 2);
myval[0] = 0x1234abcd;
myval[1] = 0xdcba8976;
// build "OperationRegion(BDAT, SystemMemory, 0x12345678, 0x87654321)"
*(ssdt_ptr++) = 0x5B; // ExtOpPrefix
*(ssdt_ptr++) = 0x80; // OpRegionOp
*(ssdt_ptr++) = 'B';
*(ssdt_ptr++) = 'D';
*(ssdt_ptr++) = 'A';
*(ssdt_ptr++) = 'T';
*(ssdt_ptr++) = 0x00; // SystemMemory
*(ssdt_ptr++) = 0x0C; // DWordPrefix
*(u32*)ssdt_ptr = (u32)myval;
ssdt_ptr += 4;
*(ssdt_ptr++) = 0x0C; // DWordPrefix
*(u32*)ssdt_ptr = sizeof(*myval)*2;
ssdt_ptr += 4;
build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
//hexdump(ssdt, ssdt_ptr - ssdt);
-- Gleb.
Hi, Tried these patches today on Win2008 x64 guest with 64bit devices. I've got BSOD on boot. I guess windows don't like changes in _CRS.
On 04/05/12 20:21, Gerd Hoffmann wrote:
Hi,
This patch series makes the PCI I/O windows runtime-configurable via qemu firmware config interface. Main advantage is that we can size and shuffle around the PCI i/O windows according to the amount of memory the virtual machine has. We don't need a hole for 64bit PCI bars, we can just map them above the main memory. The hole for 32bit PCI bars can be enlarged for guests with less than 3.5 GB of memory.
Oh, and the pci device initialization fix is there too ;)
cheers, Gerd
Gerd Hoffmann (5): pci: init all devices acpi: add qemu fwcfg driver acpi: update pci io windows according to fw_cfg info pciinit: make pci ressources configurable update src/acpi-dsdt.hex
src/acpi-dsdt.dsl | 81 ++++++++++- src/acpi-dsdt.hex | 420 +++++++++++++++++++++++++++++++++++++++++++++++++++-- src/paravirt.c | 8 + src/paravirt.h | 2 + src/pciinit.c | 32 +++- 5 files changed, 522 insertions(+), 21 deletions(-)
SeaBIOS mailing list SeaBIOS@seabios.org http://www.seabios.org/mailman/listinfo/seabios
On Mon, May 07, 2012 at 01:58:18PM +1200, Alexey Korolev wrote:
Hi, Tried these patches today on Win2008 x64 guest with 64bit devices. I've got BSOD on boot. I guess windows don't like changes in _CRS.
Hrmm, I went to test this, and found that the "Fix 64bit PCI issues on Windows" patch causes winxp to BSOD. So, it looks like that patch will have to be reverted. We'll need to dynamically generate the _CRS somehow.
The DSDT is a real pain.
-Kevin