| 1 | /*␊ |
| 2 | Copyright (c) 2010, Intel Corporation␊ |
| 3 | All rights reserved.␊ |
| 4 | ␊ |
| 5 | Redistribution and use in source and binary forms, with or without␊ |
| 6 | modification, are permitted provided that the following conditions are met:␊ |
| 7 | ␊ |
| 8 | * Redistributions of source code must retain the above copyright notice,␊ |
| 9 | this list of conditions and the following disclaimer.␊ |
| 10 | * Redistributions in binary form must reproduce the above copyright notice,␊ |
| 11 | this list of conditions and the following disclaimer in the documentation␊ |
| 12 | and/or other materials provided with the distribution.␊ |
| 13 | * Neither the name of Intel Corporation nor the names of its contributors␊ |
| 14 | may be used to endorse or promote products derived from this software␊ |
| 15 | without specific prior written permission.␊ |
| 16 | ␊ |
| 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND␊ |
| 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED␊ |
| 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE␊ |
| 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR␊ |
| 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES␊ |
| 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;␊ |
| 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON␊ |
| 24 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT␊ |
| 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS␊ |
| 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.␊ |
| 27 | */␊ |
| 28 | #include "libsaio.h"␊ |
| 29 | #include "bootstruct.h"␊ |
| 30 | #include "datatype.h"␊ |
| 31 | #include "intel_acpi.h"␊ |
| 32 | #include "ppm.h"␊ |
| 33 | #include "acpi_tools.h"␊ |
| 34 | ␊ |
| 35 | static U32 GetRsdtPointer(void *mem_addr, U32 mem_size, ACPI_TABLES * acpi_tables);␊ |
| 36 | static U32 GetXsdtPointer(ACPI_TABLES * acpi_tables);␊ |
| 37 | static ACPI_TABLE_HEADER *GetTablePtr(ACPI_TABLE_RSDT * rsdt, U32 signature);␊ |
| 38 | static ACPI_TABLE_HEADER *GetTablePtr64(ACPI_TABLE_XSDT * xsdt, U32 signature);␊ |
| 39 | ␊ |
| 40 | //-------------------------------------------------------------------------------␊ |
| 41 | //␊ |
| 42 | // Procedure: FindAcpiTables - Collects addresses for RSDP, RSDT, FADT, & DSDT.␊ |
| 43 | //␊ |
| 44 | // Description: Finds the differentiated system description table pointer␊ |
| 45 | // by scanning and checking ACPI tables. This function will␊ |
| 46 | // get and store the following ACPI Table Pointers:␊ |
| 47 | // 1) RSD Pointer in RsdPointer Variable␊ |
| 48 | // 2) RSDT Pointer in RsdtPointer Variable␉␉␉(RSDP->RSDT)␊ |
| 49 | // 3) XSDT Pointer in XsdtPointer Variable␉␉␉(RSDP->XSDT)␊ |
| 50 | // 4) FACP Pointer in FacpPointer Variable␉␉␉(RSDP->RSDT->FACP)␊ |
| 51 | // 5) FACP(64) Pointer in FacpPointer64 Variable␉␉(RSDP->XSDT->FACP)␊ |
| 52 | // 6) DSDT Pointer in DsdtPointer Variable␉␉␉(RSDP->RSDT->FACP->DSDT)␊ |
| 53 | // 7) DSDT(64) Pointer in DsdtPointer64 Variable␉␉(RSDP->XSDT->FACP->XDSDT)␊ |
| 54 | // 8) FACS Pointer in FacsPointer Variable␉␉␉(RSDP->RSDT->FACP->FACS)␊ |
| 55 | // 9) FACS(64) Pointer in FacsPointer64 Variable␉␉(RSDP->XSDT->FACP->XFACS)␊ |
| 56 | // A) MADT Pointer in FacsPointer Variable␉␉␉(RSDP->RSDT->APIC)␊ |
| 57 | // B) MADT(64) Pointer in MadtPointer64 Variable␉␉(RSDP->XSDT->APIC)␊ |
| 58 | //␊ |
| 59 | //-------------------------------------------------------------------------------␊ |
| 60 | U32 FindAcpiTables(ACPI_TABLES * acpi_tables)␊ |
| 61 | {␊ |
| 62 | U32 success = 0ul;␊ |
| 63 | ␊ |
| 64 | // Perform init of ACPI table pointers␊ |
| 65 | {␊ |
| 66 | void *null = 0ul;␊ |
| 67 | acpi_tables->DsdtPointer = null;␊ |
| 68 | acpi_tables->DsdtPointer64 = null;␊ |
| 69 | acpi_tables->FacpPointer = null;␊ |
| 70 | acpi_tables->FacsPointer = null;␊ |
| 71 | acpi_tables->FacsPointer64 = null;␊ |
| 72 | acpi_tables->RsdPointer = null;␊ |
| 73 | acpi_tables->RsdtPointer = null;␊ |
| 74 | acpi_tables->MadtPointer = null;␊ |
| 75 | ␉␉acpi_tables->MadtPointer64 = null;␊ |
| 76 | acpi_tables->XsdtPointer = null;␊ |
| 77 | acpi_tables->FacpPointer64 = null;␊ |
| 78 | }␊ |
| 79 | ␊ |
| 80 | // Find the RSDT pointer by scanning EBDA/E000/F000 segments.␊ |
| 81 | ␊ |
| 82 | // Init memory address as EBDA and scan 1KB region␊ |
| 83 | success = GetRsdtPointer((void *)(((U32) * (U16 *) 0x40E) << 4), 0x400, acpi_tables);␊ |
| 84 | ␊ |
| 85 | // Init memory address as E000 segment and scan 64KB region␊ |
| 86 | if (!success)␊ |
| 87 | success = GetRsdtPointer((void *)0x0E0000, 0x10000, acpi_tables);␊ |
| 88 | ␊ |
| 89 | // Init memory address as F000 segment and scan 64KB region␊ |
| 90 | if (!success)␊ |
| 91 | success = GetRsdtPointer((void *)0x0F0000, 0x10000, acpi_tables);␊ |
| 92 | ␉␊ |
| 93 | if (!success)␊ |
| 94 | return (0ul);␊ |
| 95 | ␊ |
| 96 | GetXsdtPointer(acpi_tables);␊ |
| 97 | ␊ |
| 98 | // Find FACP table pointer which is one of table pointers in the RDST␊ |
| 99 | acpi_tables->FacpPointer = (ACPI_TABLE_FADT *)␊ |
| 100 | GetTablePtr(acpi_tables->RsdtPointer, NAMESEG("FACP"));␊ |
| 101 | if (acpi_tables->FacpPointer == 0ul)␊ |
| 102 | return (0ul);␊ |
| 103 | ␊ |
| 104 | // Find FACP(64) table pointer which is one of table pointers in the XDST␊ |
| 105 | acpi_tables->FacpPointer64 = (ACPI_TABLE_FADT *)␊ |
| 106 | GetTablePtr64(acpi_tables->XsdtPointer, NAMESEG("FACP"));␊ |
| 107 | ␊ |
| 108 | // Find the DSDT which is included in the FACP table␊ |
| 109 | acpi_tables->DsdtPointer = (ACPI_TABLE_DSDT *) acpi_tables->FacpPointer->Dsdt;␊ |
| 110 | if ((*(U32 *) (acpi_tables->DsdtPointer->Header.Signature) != NAMESEG("DSDT")) ||␊ |
| 111 | (GetChecksum(acpi_tables->DsdtPointer, acpi_tables->DsdtPointer->Header.Length) != 0))␊ |
| 112 | return (0ul);␊ |
| 113 | ␊ |
| 114 | ␉{␊ |
| 115 | ␉␉// Find the XDSDT which is included in the FACP(64) table␊ |
| 116 | ␉␉ACPI_TABLE_DSDT *DsdtPointer64 = (ACPI_TABLE_DSDT *)((U32)acpi_tables->FacpPointer64->XDsdt);␊ |
| 117 | ␉␉if ((*(U32*) (DsdtPointer64->Header.Signature) == NAMESEG("DSDT")) &&␊ |
| 118 | ␉␉␉(GetChecksum(DsdtPointer64, DsdtPointer64->Header.Length) == 0))␊ |
| 119 | ␉␉␉acpi_tables->DsdtPointer64 = (ACPI_TABLE_DSDT *) DsdtPointer64;␊ |
| 120 | ␉} ␊ |
| 121 | ␊ |
| 122 | // Find the FACS which is included in the FACP table␊ |
| 123 | acpi_tables->FacsPointer = (ACPI_TABLE_FACS *) acpi_tables->FacpPointer->Facs;␊ |
| 124 | if (*(U32 *) (acpi_tables->FacsPointer->Signature) != NAMESEG("FACS"))␊ |
| 125 | return (0ul);␊ |
| 126 | ␊ |
| 127 | ␉{␊ |
| 128 | ␉␉// Find the XFACS which is included in the FACP(64) table␊ |
| 129 | ␉␉ACPI_TABLE_FACS *FacsPointer64 = (ACPI_TABLE_FACS *)((U32)acpi_tables->FacpPointer64->XFacs);␊ |
| 130 | ␉␉if (*(U32*) (FacsPointer64->Signature) == NAMESEG("FACS"))␊ |
| 131 | ␉␉␉acpi_tables->FacsPointer64 = (ACPI_TABLE_FACS *) FacsPointer64;␊ |
| 132 | ␉} ␊ |
| 133 | ␉␊ |
| 134 | // Find the MADT table which is one of the table pointers in the RSDT␊ |
| 135 | acpi_tables->MadtPointer = (ACPI_TABLE_MADT *) GetTablePtr(acpi_tables->RsdtPointer, NAMESEG("APIC"));␊ |
| 136 | if (acpi_tables->MadtPointer == 0ul)␊ |
| 137 | return (0ul);␊ |
| 138 | ␉␊ |
| 139 | ␉// Find the MADT(64) table which is one of the table pointers in the XSDT␊ |
| 140 | acpi_tables->MadtPointer64 = (ACPI_TABLE_MADT *) GetTablePtr64(acpi_tables->XsdtPointer, NAMESEG("APIC"));␊ |
| 141 | ␉␊ |
| 142 | return (1ul);␊ |
| 143 | }␊ |
| 144 | ␊ |
| 145 | //-----------------------------------------------------------------------------␊ |
| 146 | U32 get_num_tables(ACPI_TABLE_RSDT * rsdt)␊ |
| 147 | {␊ |
| 148 | // Compute number of table pointers included in RSDT␊ |
| 149 | return ((rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER))␊ |
| 150 | / sizeof(ACPI_TABLE_HEADER *));␊ |
| 151 | }␊ |
| 152 | ␊ |
| 153 | //-----------------------------------------------------------------------------␊ |
| 154 | U32 get_num_tables64(ACPI_TABLE_XSDT * xsdt)␊ |
| 155 | {␊ |
| 156 | {␊ |
| 157 | void *null = 0ul;␊ |
| 158 | if (xsdt == null)␊ |
| 159 | return 0ul;␊ |
| 160 | }␊ |
| 161 | ␊ |
| 162 | // Compute number of table pointers included in XSDT␊ |
| 163 | return ((xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER))␊ |
| 164 | / sizeof(U64));␊ |
| 165 | }␊ |
| 166 | ␊ |
| 167 | //-------------------------------------------------------------------------------␊ |
| 168 | //␊ |
| 169 | // Procedure: GetTablePtr - Find ACPI table in RSDT with input signature.␊ |
| 170 | //␊ |
| 171 | //-------------------------------------------------------------------------------␊ |
| 172 | static ACPI_TABLE_HEADER *GetTablePtr(ACPI_TABLE_RSDT * rsdt, U32 signature)␊ |
| 173 | {␊ |
| 174 | U32 index;␊ |
| 175 | U32 num_tables;␊ |
| 176 | ACPI_TABLE_HEADER **table_array = (ACPI_TABLE_HEADER **) rsdt->TableOffsetEntry;␊ |
| 177 | ␊ |
| 178 | // Compute number of table pointers included in RSDT␊ |
| 179 | num_tables = get_num_tables(rsdt);␊ |
| 180 | ␊ |
| 181 | for (index = 0; index < num_tables; index++) {␊ |
| 182 | if ((*(U32 *) (table_array[index]->Signature) == signature) &&␊ |
| 183 | (GetChecksum(table_array[index], table_array[index]->Length) == 0)) {␊ |
| 184 | return (table_array[index]);␊ |
| 185 | }␊ |
| 186 | }␊ |
| 187 | return (0);␊ |
| 188 | }␊ |
| 189 | ␊ |
| 190 | //-------------------------------------------------------------------------------␊ |
| 191 | //␊ |
| 192 | // Procedure: GetTablePtr64 - Find ACPI table in XSDT with input signature.␊ |
| 193 | //␊ |
| 194 | //-------------------------------------------------------------------------------␊ |
| 195 | static ACPI_TABLE_HEADER *GetTablePtr64(ACPI_TABLE_XSDT * xsdt, U32 signature)␊ |
| 196 | {␊ |
| 197 | U32 index;␊ |
| 198 | U32 num_tables;␊ |
| 199 | ␉␊ |
| 200 | ␉int method;␊ |
| 201 | ␉␊ |
| 202 | ␉// Compute number of table pointers included in XSDT␊ |
| 203 | num_tables = get_num_tables64(xsdt);␊ |
| 204 | ␉␊ |
| 205 | ␉getIntForKey(kAcpiMethod, &method, DEFAULT_BOOT_CONFIG);␊ |
| 206 | ␉switch (method) {␊ |
| 207 | ␉␉case 0x2000:␊ |
| 208 | ␉␉{␊ |
| 209 | ␉␉␉for (index = 0; index < num_tables; index++) {␊ |
| 210 | ␉␉␉␉U64 ptr = xsdt->TableOffsetEntry[index];␊ |
| 211 | ␉␉␉␉␊ |
| 212 | ␉␉␉␉if ((*(U32 *) ((ACPI_TABLE_HEADER *) (unsigned long)ptr)->Signature == signature) &&␊ |
| 213 | ␉␉␉␉␉(GetChecksum(((ACPI_TABLE_HEADER *) (unsigned long)ptr), ((ACPI_TABLE_HEADER *) (unsigned long)ptr)->Length) == 0)) {␊ |
| 214 | ␉␉␉␉␉return (((ACPI_TABLE_HEADER *) (unsigned long)ptr));␊ |
| 215 | ␉␉␉␉} ␊ |
| 216 | ␉␉␉}␊ |
| 217 | ␉␉␉break;␊ |
| 218 | ␉␉}␊ |
| 219 | ␉␉case 0x1000:␉␉␉␊ |
| 220 | ␉␉default:␊ |
| 221 | ␉␉{␊ |
| 222 | ␉␉␉ACPI_TABLE_HEADER *table = (ACPI_TABLE_HEADER *) xsdt->TableOffsetEntry;␉␉␊ |
| 223 | ␉␉␉␊ |
| 224 | ␉␉␉for (index = 0; index < num_tables; index++) {␊ |
| 225 | ␉␉␉␉if (((U32) (table->Signature) == signature) &&␊ |
| 226 | ␉␉␉␉␉(GetChecksum(table, table->Length) == 0)) {␊ |
| 227 | ␉␉␉␉␉return (table);␊ |
| 228 | ␉␉␉␉}␊ |
| 229 | ␉␉␉␉// Move array pointer to next 64-bit pointer␊ |
| 230 | ␉␉␉␉table = (ACPI_TABLE_HEADER *) ((U32) table + sizeof(U64));␊ |
| 231 | ␉␉␉}␊ |
| 232 | ␉␉␉break;␊ |
| 233 | ␉␉}␊ |
| 234 | ␉}␉␉␊ |
| 235 | ␊ |
| 236 | return (0);␊ |
| 237 | }␊ |
| 238 | ␊ |
| 239 | //-------------------------------------------------------------------------------␊ |
| 240 | //␊ |
| 241 | // Procedure: GetChecksum - Performs byte checksum␊ |
| 242 | //␊ |
| 243 | //-------------------------------------------------------------------------------␊ |
| 244 | U8 GetChecksum(void *mem_addr, U32 mem_size)␊ |
| 245 | {␊ |
| 246 | U8 *current = mem_addr;␊ |
| 247 | U8 *end = current + mem_size;␊ |
| 248 | U8 checksum = 0;␊ |
| 249 | ␊ |
| 250 | for (; current < end; current++)␊ |
| 251 | checksum = checksum + *current;␊ |
| 252 | ␊ |
| 253 | return (checksum);␊ |
| 254 | }␊ |
| 255 | ␊ |
| 256 | /*==========================================================================␊ |
| 257 | * Function to map 32 bit physical address to 64 bit virtual address␊ |
| 258 | */␊ |
| 259 | ␊ |
| 260 | ␊ |
| 261 | //-------------------------------------------------------------------------------␊ |
| 262 | //␊ |
| 263 | // Procedure: GetRsdtPointer - Scans given segment for RSDT pointer␊ |
| 264 | //␊ |
| 265 | // Description: Scans for root system description table pointer signature␊ |
| 266 | // ('RSD PTR ') , verifies checksum, and returns pointer to␊ |
| 267 | // RSDT table if found.␊ |
| 268 | //␊ |
| 269 | //-------------------------------------------------------------------------------␊ |
| 270 | static U32 GetRsdtPointer(void *mem_addr, U32 mem_size, ACPI_TABLES * acpi_tables)␊ |
| 271 | {␊ |
| 272 | U8 *current = mem_addr;␊ |
| 273 | U8 *end = current + mem_size;␊ |
| 274 | ␊ |
| 275 | // Quick sanity check for a valid start address␊ |
| 276 | if (current == 0ul)␊ |
| 277 | return (0ul);␊ |
| 278 | ␊ |
| 279 | for (; current < end; current += 16) {␊ |
| 280 | if (*(volatile U64 *)current == NAMESEG64("RSD PTR ")) {␊ |
| 281 | if (GetChecksum(current, ACPI_RSDP_REV0_SIZE) == 0) {␊ |
| 282 | // RSD pointer structure checksum okay, lookup the RSDT pointer. ␊ |
| 283 | acpi_tables->RsdPointer = (ACPI_TABLE_RSDP *)current;␊ |
| 284 | acpi_tables->RsdtPointer = (ACPI_TABLE_RSDT *) acpi_tables->RsdPointer->RsdtPhysicalAddress;␊ |
| 285 | if ((acpi_tables->RsdPointer != (void*)0ul) && (acpi_tables->RsdtPointer != (void*)0ul))␊ |
| 286 | return (1ul);␊ |
| 287 | else␊ |
| 288 | return (0ul);␊ |
| 289 | }␊ |
| 290 | }␊ |
| 291 | }␊ |
| 292 | ␊ |
| 293 | return (0);␊ |
| 294 | }␊ |
| 295 | ␊ |
| 296 | //-------------------------------------------------------------------------------␊ |
| 297 | //␊ |
| 298 | // Procedure: GetXsdtPointer␊ |
| 299 | //␊ |
| 300 | //-------------------------------------------------------------------------------␊ |
| 301 | static U32 GetXsdtPointer(ACPI_TABLES * acpi_tables)␊ |
| 302 | {␊ |
| 303 | if ((GetChecksum(acpi_tables->RsdPointer, sizeof(ACPI_TABLE_RSDP)) == 0) &&␊ |
| 304 | (acpi_tables->RsdPointer->Revision == 2) &&␊ |
| 305 | (acpi_tables->RsdPointer->Length == sizeof(ACPI_TABLE_RSDP))) {␊ |
| 306 | // RSD pointer structure checksum okay, lookup the XSDT pointer.␊ |
| 307 | acpi_tables->XsdtPointer = (ACPI_TABLE_XSDT *) (U32) acpi_tables->RsdPointer->XsdtPhysicalAddress;␊ |
| 308 | return (1ul);␊ |
| 309 | }␊ |
| 310 | ␊ |
| 311 | return (0ul);␊ |
| 312 | }␊ |
| 313 | |