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