1 /* 2 * Copyright 2011, Rene Gollent, rene@gollent.com. 3 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. 4 * Copyright 2007, Michael Lotz, mmlr@mlotz.ch 5 * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. 6 * Distributed under the terms of the MIT License. 7 * 8 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 9 * Distributed under the terms of the NewOS License. 10 */ 11 12 13 #include "acpi.h" 14 #include "mmu.h" 15 16 #include <string.h> 17 18 #include <KernelExport.h> 19 20 #include <arch/x86/arch_acpi.h> 21 22 23 //#define TRACE_ACPI 24 #ifdef TRACE_ACPI 25 # define TRACE(x) dprintf x 26 #else 27 # define TRACE(x) ; 28 #endif 29 #define ERROR(x...) dprintf(x) 30 31 static struct scan_spots_struct acpi_scan_spots[] = { 32 { 0x0, 0x400, 0x400 - 0x0 }, 33 { 0xe0000, 0x100000, 0x100000 - 0xe0000 }, 34 { 0, 0, 0 } 35 }; 36 37 static acpi_descriptor_header* sAcpiRsdt; // System Description Table 38 static acpi_descriptor_header* sAcpiXsdt; // Extended System Description Table 39 static int32 sNumEntries = -1; 40 41 42 static status_t 43 acpi_validate_rsdp(acpi_rsdp* rsdp) 44 { 45 const char* data = (const char*)rsdp; 46 unsigned char checksum = 0; 47 for (uint32 i = 0; i < sizeof(acpi_rsdp_legacy); i++) 48 checksum += data[i]; 49 50 if ((checksum & 0xff) != 0) { 51 TRACE(("acpi: rsdp failed basic checksum\n")); 52 return B_BAD_DATA; 53 } 54 55 // for ACPI 2.0+ we need to also validate the extended checksum 56 if (rsdp->revision > 0) { 57 for (uint32 i = sizeof(acpi_rsdp_legacy); 58 i < sizeof(acpi_rsdp_extended); i++) { 59 checksum += data[i]; 60 } 61 62 if ((checksum & 0xff) != 0) { 63 TRACE(("acpi: rsdp failed extended checksum\n")); 64 return B_BAD_DATA; 65 } 66 } 67 68 return B_OK; 69 } 70 71 72 static status_t 73 acpi_validate_rsdt(acpi_descriptor_header* rsdt) 74 { 75 const char* data = (const char*)rsdt; 76 unsigned char checksum = 0; 77 for (uint32 i = 0; i < rsdt->length; i++) 78 checksum += data[i]; 79 80 return checksum == 0 ? B_OK : B_BAD_DATA; 81 } 82 83 84 static status_t 85 acpi_check_rsdt(acpi_rsdp* rsdp) 86 { 87 if (acpi_validate_rsdp(rsdp) != B_OK) 88 return B_BAD_DATA; 89 90 bool usingXsdt = false; 91 92 TRACE(("acpi: found rsdp at %p oem id: %.6s, rev %d\n", 93 rsdp, rsdp->oem_id, rsdp->revision)); 94 TRACE(("acpi: rsdp points to rsdt at 0x%lx\n", rsdp->rsdt_address)); 95 96 uint32 length = 0; 97 acpi_descriptor_header* rsdt = NULL; 98 if (rsdp->revision > 0) { 99 length = rsdp->xsdt_length; 100 rsdt = (acpi_descriptor_header*)mmu_map_physical_memory( 101 (uint32)rsdp->xsdt_address, rsdp->xsdt_length, kDefaultPageFlags); 102 if (rsdt != NULL 103 && strncmp(rsdt->signature, ACPI_XSDT_SIGNATURE, 4) != 0) { 104 mmu_free(rsdt, rsdp->xsdt_length); 105 rsdt = NULL; 106 TRACE(("acpi: invalid extended system description table\n")); 107 } else 108 usingXsdt = true; 109 } 110 111 // if we're ACPI v1 or we fail to map the XSDT for some reason, 112 // attempt to use the RSDT instead. 113 if (rsdt == NULL) { 114 // map and validate the root system description table 115 rsdt = (acpi_descriptor_header*)mmu_map_physical_memory( 116 rsdp->rsdt_address, sizeof(acpi_descriptor_header), 117 kDefaultPageFlags); 118 if (rsdt == NULL) { 119 TRACE(("acpi: couldn't map rsdt header\n")); 120 return B_ERROR; 121 } 122 if (strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 0) { 123 mmu_free(rsdt, sizeof(acpi_descriptor_header)); 124 rsdt = NULL; 125 TRACE(("acpi: invalid root system description table\n")); 126 return B_ERROR; 127 } 128 129 length = rsdt->length; 130 // Map the whole table, not just the header 131 TRACE(("acpi: rsdt length: %lu\n", length)); 132 mmu_free(rsdt, sizeof(acpi_descriptor_header)); 133 rsdt = (acpi_descriptor_header*)mmu_map_physical_memory( 134 rsdp->rsdt_address, length, kDefaultPageFlags); 135 } 136 137 if (rsdt != NULL) { 138 if (acpi_validate_rsdt(rsdt) != B_OK) { 139 ERROR("acpi: %.4s failed checksum validation\n", rsdt->signature); 140 } 141 if (usingXsdt) 142 sAcpiXsdt = rsdt; 143 else 144 sAcpiRsdt = rsdt; 145 TRACE(("acpi: found %.4s at %p\n", rsdt->signature, rsdt)); 146 } else 147 return B_ERROR; 148 149 return B_OK; 150 } 151 152 153 template<typename PointerType> 154 acpi_descriptor_header* 155 acpi_find_table_generic(const char* signature, acpi_descriptor_header* acpiSdt) 156 { 157 if (acpiSdt == NULL) 158 return NULL; 159 160 if (sNumEntries == -1) { 161 // if using the xsdt, our entries are 64 bits wide. 162 sNumEntries = (acpiSdt->length 163 - sizeof(acpi_descriptor_header)) 164 / sizeof(PointerType); 165 } 166 167 if (sNumEntries <= 0) { 168 TRACE(("acpi: root system description table is empty\n")); 169 return NULL; 170 } 171 172 TRACE(("acpi: searching %ld entries for table '%.4s'\n", sNumEntries, 173 signature)); 174 175 PointerType* pointer = (PointerType*)((uint8*)acpiSdt 176 + sizeof(acpi_descriptor_header)); 177 178 acpi_descriptor_header* header = NULL; 179 for (int32 j = 0; j < sNumEntries; j++, pointer++) { 180 header = (acpi_descriptor_header*) 181 mmu_map_physical_memory((uint32)*pointer, 182 sizeof(acpi_descriptor_header), kDefaultPageFlags); 183 184 if (header == NULL 185 || strncmp(header->signature, signature, 4) != 0) { 186 // not interesting for us 187 TRACE(("acpi: Looking for '%.4s'. Skipping '%.4s'\n", 188 signature, header != NULL ? header->signature : "null")); 189 190 if (header != NULL) { 191 mmu_free(header, sizeof(acpi_descriptor_header)); 192 header = NULL; 193 } 194 195 continue; 196 } 197 198 TRACE(("acpi: Found '%.4s' @ %p\n", signature, pointer)); 199 break; 200 } 201 202 203 if (header == NULL) 204 return NULL; 205 206 // Map the whole table, not just the header 207 uint32 length = header->length; 208 mmu_free(header, sizeof(acpi_descriptor_header)); 209 210 return (acpi_descriptor_header*)mmu_map_physical_memory( 211 (uint32)*pointer, length, kDefaultPageFlags); 212 } 213 214 215 acpi_descriptor_header* 216 acpi_find_table(const char* signature) 217 { 218 if (sAcpiRsdt != NULL) 219 return acpi_find_table_generic<uint32>(signature, sAcpiRsdt); 220 else if (sAcpiXsdt != NULL) 221 return acpi_find_table_generic<uint64>(signature, sAcpiXsdt); 222 223 return NULL; 224 } 225 226 227 void 228 acpi_init() 229 { 230 // Try to find the ACPI RSDP. 231 for (int32 i = 0; acpi_scan_spots[i].length > 0; i++) { 232 acpi_rsdp* rsdp = NULL; 233 234 TRACE(("acpi_init: entry base 0x%lx, limit 0x%lx\n", 235 acpi_scan_spots[i].start, acpi_scan_spots[i].stop)); 236 237 for (char* pointer = (char*)acpi_scan_spots[i].start; 238 (uint32)pointer < acpi_scan_spots[i].stop; pointer += 16) { 239 if (strncmp(pointer, ACPI_RSDP_SIGNATURE, 8) == 0) { 240 TRACE(("acpi_init: found ACPI RSDP signature at %p\n", 241 pointer)); 242 rsdp = (acpi_rsdp*)pointer; 243 } 244 } 245 246 if (rsdp != NULL && acpi_check_rsdt(rsdp) == B_OK) 247 break; 248 } 249 } 250