//----------------------------------------------------------------------------// // GNU GPL OS/K // // // // Desc: ACPI, Hardware detection related functions // // // // // // Copyright © 2018-2020 The OS/K Team // // // // This file is part of OS/K. // // // // OS/K is free software: you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // // the Free Software Foundation, either version 3 of the License, or // // any later version. // // // // OS/K is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY//without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU General Public License for more details. // // // // You should have received a copy of the GNU General Public License // // along with OS/K. If not, see . // //----------------------------------------------------------------------------// #include #include #include #include #include char IoACPIVersion = 1; int tableCount = 1; extern MemoryMap_t memoryMap; // ACPI reverse strings static char *SDTChar[N_SDT_TYPES] = { "APIC", "BERT", "CPEP", "DSDT", "ECDT", "EINJ", "ERST", "FACP", "FACS", "HEST", "MSCT", "MPST", "OEMx", "PMTT", "PSDT", "RASF", "RSDT", "SBST", "SLIT", "SRAT", "SSDT", "XSDT", "HPET", "MCFG" }; // ACPI Tables Directory static SDTHeader_t *SDTDirectory[N_SDT_TYPES] = {0}; // // Returns the checksum of the given structure // static char DoChecksum(const void *ptr, const size_t size, size_t intermediateSize, ulong reason) { char checksum = 0; for (ulong i=0; i < (ulong)size; i++) { if (reason && i > (ulong)intermediateSize) break; checksum += (uchar)((char*)ptr)[i]; } return checksum; } // // Returns the address of the RSDP // static inline RSDPDescriptor_t *IoFindRSDP() { char *rsdp = NULL; // Search in EBDA for (rsdp = (char *)0x00080000; // EBDA address (ulong)rsdp < (ulong)0x0009FFFF; // EBDA end rsdp++) { if (!strncmp(rsdp, "RSD PTR", 6)) { return (RSDPDescriptor_t *)rsdp; } } // Search in BDA for (rsdp = (char *)0x000E0000; // BDA address (ulong)rsdp < (ulong)0x000FFFFF; // BDA end rsdp++) { if (!strncmp(rsdp, "RSD PTR", 6)) { return (RSDPDescriptor_t *)rsdp; } } return NULL; } // // RSDP Exploration // static inline void IoInitRSDP(void) { char checksum = 1; RSDPDescriptor_t *rsdp = IoFindRSDP(); if (!rsdp) KeStartPanic("ACPI RSDP not found in memory"); // Checksum calculation checksum = DoChecksum(rsdp, (size_t)sizeof(RSDPDescriptor_t), (size_t)sizeof(struct RSDPLegacy), !rsdp->legacy.revision ); if (checksum) KeStartPanic("Invalid RSDP checksum : %d vs 0", checksum); if (rsdp->legacy.revision == 1 || rsdp->legacy.revision >= 3) KeStartPanic("Invalid ACPI Revision : %d", rsdp->legacy.revision); DebugLog("ACPI Revision %d (OEM %s)\n", (uint)rsdp->legacy.revision, rsdp->legacy.OEMID ); SDTDirectory[SDT_RSDT] = (void *)(ulong)rsdp->legacy.rsdtAddress; if (rsdp->legacy.revision) { SDTDirectory[SDT_XSDT] = (void *)rsdp->xsdtAddress; IoACPIVersion = 2; } } // // R/XSDT Exploration // static inline void IoInitRXSDT(void) { char checksum = 1; SDTHeader_t *rxsdt = SDTDirectory[SDT_RSDT]; if (IoACPIVersion == 2) { rxsdt = SDTDirectory[SDT_XSDT]; } /* // Checksum calculation */ checksum = DoChecksum(rxsdt, (size_t)rxsdt->length, 0, 0 ); if (checksum) KeStartPanic("Invalid RSDT checksum : %d vs 0", checksum); if (IoACPIVersion == 1) { DebugLog("ACPI Root System Table %s (%s) length %d [%p]\n", rxsdt->signature, rxsdt->OEMID, rxsdt->length, rxsdt ); } else { DebugLog("ACPI Extended System Table %s (%s) length %d [%p]\n", rxsdt->signature, rxsdt->OEMID, rxsdt->length, rxsdt ); } } // // Returns the address of the MCFG // static inline SDTHeader_t *IoFindMCFG() { char *mcfg = NULL; for (uint i = 0; i < memoryMap.length; i++) { if (memoryMap.entry[i].type == RESERVED_ZONE) { for (mcfg = (char *)memoryMap.entry[i].addr; (ulong)mcfg < (ulong)(memoryMap.entry[i].addr + memoryMap.entry[i].length); mcfg++) { if (!strncmp(mcfg, "MCFG", 3)) { return (SDTHeader_t *)mcfg; } } } } return NULL; } // // Explore all ACPI Tables // static inline void IoSearchAcpiTables(void) { SDTHeader_t *xrsdt = SDTDirectory[SDT_RSDT]; SDTHeader_t *table = NULL; uint *curInt = NULL; ulong *curLong = NULL; register char checksum; int entries; if (IoACPIVersion == 1) { entries = (xrsdt->length - sizeof(xrsdt)) / 4; } else { xrsdt = SDTDirectory[SDT_XSDT]; entries = (xrsdt->length - sizeof(xrsdt)) / 8; } DebugLog("ACPI detected %d entries\n", entries); curInt = (uint*)&(xrsdt->sdtEntry); curLong = (ulong*)&(xrsdt->sdtEntry); // Parsing R/XSDT for (int i = 0; i < entries; i++) { if (IoACPIVersion == 1) table = (SDTHeader_t *)(ulong)curInt[i]; else table = (SDTHeader_t *)(ulong)curLong[i]; //KernLog("\tACPI RSDT[%d] %p\n", i, table); if (MmIsBusyZone(table)) { checksum = DoChecksum(table, (size_t)table->length, 0, 0); if (!checksum) { for (ulong i=0; i < N_SDT_TYPES; i++) { if (!strncmp(table->signature, SDTChar[i], 3)) { DebugLog("ACPI System Table %s (OEM %s) length %d [%p]\n", SDTChar[i], table->OEMID, table->length, table ); SDTDirectory[i] = table; } } } } } // Parsing FADT FADT_t *fadt = (FADT_t *)IoGetAcpiTable(SDT_FADT); SDTHeader_t *dsdt; if (IoACPIVersion == 1) { dsdt = (SDTHeader_t *)(ulong)fadt->dsdtAddress; } else { dsdt = (SDTHeader_t *)(ulong)fadt->xDsdtAddress; } checksum = DoChecksum(dsdt, (size_t)dsdt->length, 0, 0); if (!checksum) { if (!strncmp(dsdt->signature, SDTChar[SDT_DSDT], 3)) { DebugLog("ACPI System Table %s (OEM %s) length %d [%p]\n", SDTChar[SDT_DSDT], dsdt->OEMID, dsdt->length, dsdt ); SDTDirectory[SDT_DSDT] = dsdt; } } // Finding MCFG SDTHeader_t *mcfg = IoFindMCFG(); if (mcfg) { //DebugLog("MCFG found at %p\n"); checksum = 0; //DoChecksum(mcfg, (size_t)mcfg->length, 0, 0); if (!checksum) { if (!strncmp(mcfg->signature, SDTChar[SDT_MCFG], 3)) { DebugLog("ACPI System Table %s (OEM %s) length %lu [%p]\n", mcfg->signature, mcfg->OEMID, mcfg->length / MB, mcfg ); SDTDirectory[SDT_MCFG] = mcfg; } } } } // -------------------------------------------------------------------------- // // // Initialise the ACPI by finding tables // void IoInitAcpi(void) { // MAP ACPI PAGES for (uint i = 0; i < memoryMap.length; i++) { if (memoryMap.entry[i].type != AVAILABLE_ZONE) { // Map each page that is in the busy zone for (uint j = 0; j < (memoryMap.entry[i].length + ((ulong)memoryMap.entry[i].addr) - ((ulong)memoryMap.entry[i].addr & 0xFFFFFFFFFFFFF000)) / KPAGESIZE; j++) { MmMapPage(memoryMap.entry[i].addr + KPAGESIZE*j, memoryMap.entry[i].addr + KPAGESIZE*j, PRESENT); //KernLog("ACPI %d ID MAP %p\n", i, // memoryMap.entry[i].addr + KPAGESIZE*j); } } } // FIND RSDP IoInitRSDP(); IoInitRXSDT(); IoSearchAcpiTables(); } // -------------------------------------------------------------------------- // // // Returns the addr of the submitted SDT // // Arg must be a member of the enum in acpi.h // SDTHeader_t *IoGetAcpiTable(ulong id) { return SDTDirectory[id]; }