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) {
--
1.7.1