Using kevins ssdt approach.
Also trying to address the winxp issue by only adding the 64bit window to the _crs in case we actually have mapped pci bars high. That bit doesn't work though, the "LEqual(QW2, 0x00)" expression seems to never evaluate to true for some reason. Ideas anyone?
--- src/acpi-dsdt.dsl | 47 ++++++++++++++++++++++++++++++++++++++++++++--- src/acpi.c | 25 ++++++++++++++++++++++++- src/pci.h | 2 ++ src/pciinit.c | 22 +++++++++++++++++----- 4 files changed, 87 insertions(+), 9 deletions(-)
diff --git a/src/acpi-dsdt.dsl b/src/acpi-dsdt.dsl index 227e4a3..17d6d87 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,56 @@ DefinitionBlock ( 0xFEBFFFFF, // Address Range Maximum 0x00000000, // Address Translation Offset 0x1EC00000, // Address Length - ,, , AddressRangeMemory, TypeStatic) + ,, 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 - ,, , AddressRangeMemory, TypeStatic) + ,, PW64, AddressRangeMemory, TypeStatic) }) + Method (_CRS, 0) + { + External (_SB.BDAT) + Field(_SB.BDAT, QWordAcc, NoLock, Preserve) { + QW0, 64, + QW1, 64, + QW2, 64, + QW3, 64, + } + + /* 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 (QW0, PS32) + Store (QW1, PE32) + Subtract (QW1, QW0, PL32) + + If (LEqual(QW2, 0x00)) { + DBUG("PCI0 _CRS: 32bit only") + Return (CRES) + } Else { + DBUG("PCI0 _CRS: add 64bit window") + DBUG(QW2) + DBUG(QW3) + + /* fixup and add 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 (QW2, PS64) + Store (QW3, PE64) + Subtract (QW3, QW2, PL64) + + ConcatenateResTemplate (CRES, CR64, Local0) + Return (Local0) + } + } } }
diff --git a/src/acpi.c b/src/acpi.c index 30888b9..930924c 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,28 @@ build_ssdt(void) for (i=0; i<acpi_cpus; i++) *(ssdt_ptr++) = (i < CountCPUs) ? 0x01 : 0x00;
+ // store pci io windows + u64 *pcimem = malloc_high(sizeof(*pcimem) * 4); + pcimem[0] = pcimem_start; + pcimem[1] = pcimem_end - 1; + pcimem[2] = pcimem64_start; + pcimem[3] = pcimem64_end - 1; + + // 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)pcimem; + ssdt_ptr += 4; + *(ssdt_ptr++) = 0x0C; // DWordPrefix + *(u32*)ssdt_ptr = sizeof(*pcimem)*4; + ssdt_ptr += 4; + build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
//hexdump(ssdt, ssdt_ptr - ssdt); diff --git a/src/pci.h b/src/pci.h index 6be838c..ebf934c 100644 --- a/src/pci.h +++ b/src/pci.h @@ -56,6 +56,8 @@ struct pci_device { // Local information on device. int have_driver; }; +extern u64 pcimem_start, pcimem_end; +extern u64 pcimem64_start, pcimem64_end; extern struct pci_device *PCIDevices; extern int MaxPCIBus; int pci_probe_host(void); diff --git a/src/pciinit.c b/src/pciinit.c index 8374603..b85d45e 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -29,6 +29,11 @@ static const char *region_type_name[] = { [ 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; + struct pci_region_entry { struct pci_device *dev; int bar; @@ -517,13 +522,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; @@ -601,14 +606,17 @@ 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); + } else { + // no bars mapped high -> drop 64bit window + pcimem64_start = 0; } // Map regions on each device. int bus; @@ -634,6 +642,10 @@ pci_setup(void) }
dprintf(3, "pci setup\n"); + u64 pcimem64_size = (1LL << 36); // 64 MB + pcimem_start = RamSize; + pcimem64_start = (RamSizeOver4G + pcimem64_size) & ~(pcimem64_size-1); + pcimem64_end = pcimem64_start + pcimem64_size;
dprintf(1, "=== PCI bus & bridge init ===\n"); if (pci_probe_host() != 0) {