intel_extreme: find VBT in OpRegion version 2.0 and from 2.1

we check the OpRegion version and use the rvda pointer when available.
from 2.1 the pointer is relative.

Change-Id: I64d8aea65368aa3c5597f63a2b96b6a430e04315
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5109
Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
Jérôme Duval 2022-03-16 13:29:57 +01:00
parent 8fed6717a7
commit d5137e7776

View File

@ -159,86 +159,167 @@ dumprom(void *rom, uint32 size, intel_info &info)
PROM-programmed timings info when compensation mode is off on your machine.
*/
// outdated: https://01.org/sites/default/files/documentation/skl_opregion_rev0p5.pdf
#define ASLS 0xfc // ASL Storage.
#define OPREGION_SIGNATURE "IntelGraphicsMem"
#define OPREGION_ASLE_OFFSET 0x300
#define OPREGION_VBT_OFFSET 0x400
#define MBOX_ACPI (1 << 0)
#define MBOX_SWSCI (1 << 1)
#define MBOX_ASLE (1 << 2)
#define MBOX_ASLE_EXT (1 << 3)
struct opregion_header {
uint8 signature[16];
uint32 size;
uint8 reserved;
uint8 revision_version;
uint8 minor_version;
uint8 major_version;
uint8 sver[32];
uint8 vver[16];
uint8 gver[16];
uint32 mboxes;
uint32 driver_model;
uint32 platform_configuration;
uint8 gop_version[32];
uint8 rsvd[124];
} __attribute__((packed));
struct opregion_asle {
uint32 ardy;
uint32 aslc;
uint32 tche;
uint32 alsi;
uint32 bclp;
uint32 pfit;
uint32 cblv;
uint16 bclm[20];
uint32 cpfm;
uint32 epfm;
uint8 plut[74];
uint32 pfmb;
uint32 cddv;
uint32 pcft;
uint32 srot;
uint32 iuer;
uint64 fdss;
uint32 fdsp;
uint32 stat;
uint64 rvda;
uint32 rvds;
uint8 rsvd[58];
} __attribute__((packed));
static bool
get_bios(int* vbtOffset)
{
STATIC_ASSERT(sizeof(opregion_header) == 0x100);
STATIC_ASSERT(sizeof(opregion_asle) == 0x100);
intel_info &info = *gDeviceInfo[0];
// first try to fetch Intel OpRegion which should be polulated by the BIOS at start
uint64_t kVBIOSAddress = 0;
uint32 kVBIOSSize = 8 * 1024;
// first try to fetch Intel OpRegion which should be populated by the BIOS at start
uint32 kVBIOSSize;
// get OpRegion - see Intel ACPI IGD info in acpi_igd_opregion_spec_0.pdf
kVBIOSAddress = get_pci_config(info.pci, ASLS, 4);
if (!kVBIOSAddress) {
TRACE((DEVICE_NAME ": ACPI OpRegion not supported!\n"));
} else {
TRACE((DEVICE_NAME ": Graphic OpRegion physical addr: 0x%" B_PRIx64
"; size: 0x%" B_PRIx32 "\n", kVBIOSAddress, kVBIOSSize));
vbios.area = map_physical_memory("ASLS mapping", kVBIOSAddress,
kVBIOSSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void **)&vbios.memory);
if (vbios.area >= 0) {
TRACE((DEVICE_NAME ": mapping ASLS: 0x%" B_PRIx64 " -> %p\n",
kVBIOSAddress, vbios.memory));
// check if we got the ASLS and signature
if (memcmp(vbios.memory, OPREGION_SIGNATURE, 16)) {
TRACE((DEVICE_NAME ": OpRegion signature mismatch\n"));
for (uint32 romMethod = 0; romMethod < 2; romMethod++) {
switch(romMethod) {
case 0:
{
// get OpRegion - see Intel ACPI IGD info in acpi_igd_opregion_spec_0.pdf
uint64 kVBIOSAddress = get_pci_config(info.pci, ASLS, 4);
if (kVBIOSAddress == 0) {
TRACE((DEVICE_NAME ": ACPI OpRegion not supported!\n"));
continue;
}
kVBIOSSize = 8 * 1024;
TRACE((DEVICE_NAME ": Graphic OpRegion physical addr: 0x%" B_PRIx64
"; size: 0x%" B_PRIx32 "\n", kVBIOSAddress, kVBIOSSize));
vbios.area = map_physical_memory("ASLS mapping", kVBIOSAddress,
kVBIOSSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void **)&vbios.memory);
if (vbios.area < 0)
continue;
TRACE((DEVICE_NAME ": mapping OpRegion: 0x%" B_PRIx64 " -> %p\n",
kVBIOSAddress, vbios.memory));
// check if we got the OpRegion and signature
if (memcmp(vbios.memory, OPREGION_SIGNATURE, 16) != 0) {
TRACE((DEVICE_NAME ": OpRegion signature mismatch\n"));
delete_area(vbios.area);
vbios.area = -1;
continue;
}
opregion_header* header = (opregion_header*)vbios.memory;
opregion_asle* asle = (opregion_asle*)(vbios.memory + OPREGION_ASLE_OFFSET);
if (header->major_version < 2 || (header->mboxes & MBOX_ASLE) == 0
|| asle->rvda == 0 || asle->rvds == 0) {
vbios.memory += OPREGION_VBT_OFFSET;
kVBIOSSize -= OPREGION_VBT_OFFSET;
break;
}
uint64 rvda = asle->rvda;
kVBIOSSize = asle->rvds;
if (header->major_version > 3 || header->minor_version >= 1) {
rvda += kVBIOSAddress;
}
TRACE((DEVICE_NAME ": RVDA physical addr: 0x%" B_PRIx64
"; size: 0x%" B_PRIx32 "\n", rvda, kVBIOSSize));
delete_area(vbios.area);
vbios.area = -1;
// force using ISA legacy map as fall-back
kVBIOSAddress = 0;
vbios.area = map_physical_memory("RVDA mapping", rvda,
kVBIOSSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void **)&vbios.memory);
if (vbios.area < 0)
continue;
break;
}
case 1:
{
uint64 kVBIOSAddress = 0xc0000;
kVBIOSSize = 64 * 1024;
/* !!!DANGER!!!: mapping of BIOS using legacy location as a fallback,
hence, if panel mode will be set using info from VBT this way, it will
be taken from primary card's VBIOS */
vbios.area = map_physical_memory("VBIOS mapping", kVBIOSAddress,
kVBIOSSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void**)&vbios.memory);
if (vbios.area < 0)
continue;
TRACE((DEVICE_NAME ": mapping VBIOS: 0x%" B_PRIx64 " -> %p\n",
kVBIOSAddress, vbios.memory));
break;
}
} else {
// mapping failed: force using ISA legacy map as fall-back
kVBIOSAddress = 0;
}
}
if (!kVBIOSAddress) {
kVBIOSAddress = 0xc0000;
kVBIOSSize = 64 * 1024;
/* !!!DANGER!!!: mapping of BIOS using legacy location as a fallback,
hence, if panel mode will be set using info from VBT this way, it will
be taken from primary card's VBIOS */
vbios.area = map_physical_memory("VBIOS mapping", kVBIOSAddress,
kVBIOSSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void**)&vbios.memory);
// dump ROM to file if selected in settings file
if (read_settings_dumpRom())
dumprom(vbios.memory, kVBIOSSize, info);
if (vbios.area < 0)
return false;
// scan BIOS for VBT signature
*vbtOffset = kVBIOSSize;
for (uint32 i = 0; i + 4 < kVBIOSSize; i += 4) {
if (memcmp(vbios.memory + i, "$VBT", 4) == 0) {
*vbtOffset = i;
break;
}
}
TRACE((DEVICE_NAME ": mapping VBIOS: 0x%" B_PRIx64 " -> %p\n",
kVBIOSAddress, vbios.memory));
}
// dump ROM to file if selected in settings file
if (read_settings_dumpRom())
dumprom(vbios.memory, kVBIOSSize, info);
// scan BIOS for VBT signature
*vbtOffset = kVBIOSSize;
for (uint32 i = 0; i + 4 < kVBIOSSize; i += 4) {
if (memcmp(vbios.memory + i, "$VBT", 4) == 0) {
*vbtOffset = i;
if ((*vbtOffset + (uint32)sizeof(vbt_header)) >= kVBIOSSize) {
TRACE((DEVICE_NAME": bad VBT offset : 0x%x\n", *vbtOffset));
delete_area(vbios.area);
continue;
}
struct vbt_header* vbt = (struct vbt_header*)(vbios.memory + *vbtOffset);
if (memcmp(vbt->signature, "$VBT", 4) != 0) {
TRACE((DEVICE_NAME": bad VBT signature: %20s\n", vbt->signature));
delete_area(vbios.area);
continue;
}
return true;
}
if ((*vbtOffset + (uint32)sizeof(vbt_header)) >= kVBIOSSize) {
TRACE((DEVICE_NAME": bad VBT offset : 0x%x\n", *vbtOffset));
delete_area(vbios.area);
return false;
}
struct vbt_header* vbt = (struct vbt_header*)(vbios.memory + *vbtOffset);
if (memcmp(vbt->signature, "$VBT", 4) != 0) {
TRACE((DEVICE_NAME": bad VBT signature: %20s\n", vbt->signature));
delete_area(vbios.area);
return false;
}
return true;
return false;
}