//----------------------------------------------------------------------------// // 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 SDTHeader *AcpiSDT = NULL; SDTHeader *AcpiFADT = NULL; 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" }; // ACPI Tables Directory static SDTHeader *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 *IoFindRSDP() { char *rsdp = NULL; // Search in EBDA for (rsdp = (char *)0x00080000; // EBDA address (ulong)rsdp < (ulong)0x0009FFFF; // EBDA end rsdp++) { if (rsdp[0] == 'R' && rsdp[1] == 'S' && rsdp[2] == 'D' && rsdp[3] == ' ' && rsdp[4] == 'P' && rsdp[5] == 'T' && rsdp[6] == 'R' && rsdp[7] == ' ' ) { return (RSDPDescriptor *)rsdp; } } // Search in BDA for (rsdp = (char *)0x000E0000; // BDA address (ulong)rsdp < (ulong)0x000FFFFF; // BDA end rsdp++) { if (rsdp[0] == 'R' && rsdp[1] == 'S' && rsdp[2] == 'D' && rsdp[3] == ' ' && rsdp[4] == 'P' && rsdp[5] == 'T' && rsdp[6] == 'R' && rsdp[7] == ' ' ) { return (RSDPDescriptor *)rsdp; } } return NULL; } // // RSDP Exploration // static inline void IoInitRSDP(void) { char checksum = 1; RSDPDescriptor *rsdp = IoFindRSDP(); if (!rsdp) KeStartPanic("ACPI RSDP not found in memory"); // Checksum calculation checksum = DoChecksum(rsdp, (size_t)sizeof(RSDPDescriptor), (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 ); AcpiSDT = (void *)(ulong)rsdp->legacy.rsdtAddress; if (rsdp->legacy.revision) { AcpiSDT = (void *)rsdp->xsdtAddress; IoACPIVersion = 2; } } // // R/XSDT Exploration // static inline void IoInitRXSDT(void) { char checksum = 1; SDTHeader *rxsdt = AcpiSDT; /* // 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 ); } } // // Explore all ACPI Tables // static inline void IoSearchAcpiTables(void) { SDTHeader *xrsdt = AcpiSDT; SDTHeader *table = NULL; uint *curInt = NULL; ulong *curLong = NULL; register char checksum; int entries; if (IoACPIVersion == 1) { entries = (xrsdt->length - sizeof(xrsdt)) / 4; } else { entries = (xrsdt->length - sizeof(xrsdt)) / 8; } DebugLog("ACPI detected %d entries\n", entries); curInt = (uint*)&(xrsdt->sdtTablePtr); curLong = (ulong*)&(xrsdt->sdtTablePtr); for (int i = 0; i < entries; i++) { if (IoACPIVersion == 1) table = (SDTHeader *)(ulong)curInt[i]; else table = (SDTHeader *)(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; } } } } } } // -------------------------------------------------------------------------- // // // Initialise the ACPI by finding tables // void IoInitAcpi(void) { // MAP ACPI PAGES // Search the zone where the start address is for (uint i = 0; i < memoryMap.length; i++) { // if the address is in an available zone, we can return the length 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 *IoGetAcpiTable(ulong id) { return SDTDirectory[id]; }