ACPI
1. RSDP
Root System Description Pointer es una estructura de datos usada en la API de ACPI
1.1. Estructura
Para ACPI 1.0:
struct RSDPDescriptor { char Signature[8]; //String sin terminación null que ha de ser "RSDP PTR " (con el espacio) uint8_t Checksum; // Tomamos todos los bytes de la estructura, sumamos este y comprobamos si al castearlo a byte da 0 char OEMID[6]; // "An OEM-supplied string that identifies the OEM" uint8_t Revision; // La versión, backwards compatible uint32_t RsdtAddress; // Dirección *FISICA* de la tabla RSDT } __attribute__ ((packed));
Para ACPI 2.0+:
struct RSDPDescriptor20 { RSDPDescriptor firstPart; uint32_t Length; //La longitud de la tabla desde offset 0 hasta el final uint64_t XsdtAddress; // Dirección *FISICA* de la tabla XSDT, si tenemos ACPI 2.0 usamos esta en vez de RSDT aún en IA-32 (lo casteamos a uint32_t y ya) uint8_t ExtendedChecksum; // Iguak que el otro checksum uint8_t reserved[3]; // Para nada, no deben ser escritos } __attribute__ ((packed));
Como vemos extiende la estructura de ACPI 1.0 para mantener compatibilidad.
1.2. Cómo se encuentra
En UEFI en la EFI_SYSTEM_TABLE
, si tenemos BIOS en el primer kilobyte de memoria de la “Extended BIOS Data Area” (blablabla).
Su nombre es “RSDP PTR ”, hay que tenerlo en cuenta para encontrarla, es importante el último espacio del nombre (no es una errata).
2. RSDT
Estructura que contiene punteros a otras “SDT” (System Description Tables)
Solo la usaremos si estamos en ACPI < 2.0, si no usamos `XSDT`, de todas formas:
On 80x86 it’s likely that the RSDT and the XSDT both point to the same tables below 4 GB for compatibility reasons
2.1. Estructura
El RSDT es la SDT principal, pero hay varias.
Las SDT se dividen en dos partes, la cabecera que es común a todos los SDT y otra que es de datos, diferente para cada tipo de tabla.
La estructura de la cabecera:
struct ACPISDTHeader { char Signature[4]; // Todas las tablas 4bytes menos la RSDP (la root, principal) uint32_t Length; //tamaño total de la tabla *incluyendo la cabecera* uint8_t Revision; uint8_t Checksum; //todos los bytes de la tabla (incluyendo cabecera) sumados módulo 0x100 ha de ser 0 (alineado) char OEMID[6]; char OEMTableID[8]; uint32_t OEMRevision; uint32_t CreatorID; uint32_t CreatorRevision; };
Lo que es la tabla es así, dependiendo si hemos usado RSDT o XSDT:
struct RSDT { struct ACPISDTHeader h; uint32_t PointerToOtherSDT[(h.Length - sizeof(h)) / 4]; };
struct XSDT { struct ACPISDTHeader h; uint64_t PointerToOtherSDT[(h.Length - sizeof(h)) / 8]; };
El 4 y el 8 mágico creo que son sizeof(uint32_t)
y sizeof(uint64_t)
por 32bit y 64bit de direcciones.
2.2. Uso
Teniendo la RSDT
asumamos que queremos buscar la SDT
“FADT”, como la “FADT” es una SDT
tendrá una ACPISDTHeader
con signature “FACP”:
void *findFACP(void *RootSDT) { RSDT *rsdt = (RSDT *) RootSDT; int entries = (rsdt->h.Length - sizeof(rsdt->h)) / 4; for (int i = 0; i < entries; i++) { ACPISDTHeader *h = (ACPISDTHeader *) rsdt->PointerToOtherSDT[i]; if (!strncmp(h->Signature, "FACP", 4)) return (void *) h; } // No FACP found return NULL; }
3. MCFG (PCIe)
The enhanced configuration mechanism makes use of memory mapped address space range/s to access PCI configuration space. Put simply, the memory address determines the segment group, bus, device, function and register being accessed. On x86 and x64 platforms, the address of each memory area is determined by the ACPI ’MCFG’ table.