1 /* 2 * Copyright 2014, Jessica Hamilton, jessica.l.hamilton@gmail.com. 3 * Copyright 2011, Rene Gollent, rene@gollent.com. 4 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. 5 * Copyright 2007, Michael Lotz, mmlr@mlotz.ch 6 * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. 7 * Distributed under the terms of the MIT License. 8 * 9 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 10 * Distributed under the terms of the NewOS License. 11 */ 12 13 14 #include <string.h> 15 16 #include <KernelExport.h> 17 #include <SupportDefs.h> 18 19 #include <arch/x86/arch_acpi.h> 20 #include <boot/stage2.h> 21 #include <boot/platform.h> 22 #include <boot/stdio.h> 23 24 #include "efi_platform.h" 25 #include "acpi.h" 26 #include "mmu.h" 27 28 29 #define TRACE_ACPI 30 #ifdef TRACE_ACPI 31 # define TRACE(x) dprintf x 32 #else 33 # define TRACE(x) ; 34 #endif 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 73 static status_t 74 acpi_validate_rsdt(acpi_descriptor_header* rsdt) 75 { 76 const char* data = (const char*)rsdt; 77 unsigned char checksum = 0; 78 for (uint32 i = 0; i < rsdt->length; i++) 79 checksum += data[i]; 80 81 return checksum == 0 ? B_OK : B_BAD_DATA; 82 } 83 84 85 static status_t 86 acpi_check_rsdt(acpi_rsdp* rsdp) 87 { 88 if (acpi_validate_rsdp(rsdp) != B_OK) 89 return B_BAD_DATA; 90 91 bool usingXsdt = false; 92 93 TRACE(("acpi: found rsdp at %p oem id: %.6s, rev %d\n", 94 rsdp, rsdp->oem_id, rsdp->revision)); 95 TRACE(("acpi: rsdp points to rsdt at 0x%x\n", rsdp->rsdt_address)); 96 97 uint32 length = 0; 98 acpi_descriptor_header* rsdt = NULL; 99 if (rsdp->revision > 0) { 100 length = rsdp->xsdt_length; 101 rsdt = (acpi_descriptor_header*)mmu_map_physical_memory( 102 (uint32)rsdp->xsdt_address, rsdp->xsdt_length, kDefaultPageFlags); 103 if (rsdt != NULL 104 && strncmp(rsdt->signature, ACPI_XSDT_SIGNATURE, 4) != 0) { 105 mmu_free(rsdt, rsdp->xsdt_length); 106 rsdt = NULL; 107 TRACE(("acpi: invalid extended system description table\n")); 108 } else 109 usingXsdt = true; 110 } 111 112 // if we're ACPI v1 or we fail to map the XSDT for some reason, 113 // attempt to use the RSDT instead. 114 if (rsdt == NULL) { 115 // map and validate the root system description table 116 rsdt = (acpi_descriptor_header*)mmu_map_physical_memory( 117 rsdp->rsdt_address, sizeof(acpi_descriptor_header), 118 kDefaultPageFlags); 119 if (rsdt == NULL) { 120 TRACE(("acpi: couldn't map rsdt header\n")); 121 return B_ERROR; 122 } 123 if (strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 0) { 124 mmu_free(rsdt, sizeof(acpi_descriptor_header)); 125 rsdt = NULL; 126 TRACE(("acpi: invalid root system description table\n")); 127 return B_ERROR; 128 } 129 130 length = rsdt->length; 131 // Map the whole table, not just the header 132 TRACE(("acpi: rsdt length: %u\n", length)); 133 mmu_free(rsdt, sizeof(acpi_descriptor_header)); 134 rsdt = (acpi_descriptor_header*)mmu_map_physical_memory( 135 rsdp->rsdt_address, length, kDefaultPageFlags); 136 } 137 138 if (rsdt != NULL) { 139 if (acpi_validate_rsdt(rsdt) != B_OK) { 140 TRACE(("acpi: rsdt failed checksum validation\n")); 141 mmu_free(rsdt, length); 142 return B_ERROR; 143 } else { 144 if (usingXsdt) 145 sAcpiXsdt = rsdt; 146 else 147 sAcpiRsdt = rsdt; 148 TRACE(("acpi: found valid %s at %p\n", 149 usingXsdt ? ACPI_XSDT_SIGNATURE : ACPI_RSDT_SIGNATURE, 150 rsdt)); 151 } 152 } else 153 return B_ERROR; 154 155 return B_OK; 156 } 157 158 template<typename PointerType> 159 acpi_descriptor_header* 160 acpi_find_table_generic(const char* signature, acpi_descriptor_header* acpiSdt) 161 { 162 if (acpiSdt == NULL) 163 return NULL; 164 165 if (sNumEntries == -1) { 166 // if using the xsdt, our entries are 64 bits wide. 167 sNumEntries = (acpiSdt->length 168 - sizeof(acpi_descriptor_header)) 169 / sizeof(PointerType); 170 } 171 172 if (sNumEntries <= 0) { 173 TRACE(("acpi: root system description table is empty\n")); 174 return NULL; 175 } 176 177 TRACE(("acpi: searching %d entries for table '%.4s'\n", sNumEntries, 178 signature)); 179 180 PointerType* pointer = (PointerType*)((uint8*)acpiSdt 181 + sizeof(acpi_descriptor_header)); 182 183 acpi_descriptor_header* header = NULL; 184 for (int32 j = 0; j < sNumEntries; j++, pointer++) { 185 header = (acpi_descriptor_header*) 186 mmu_map_physical_memory((uint32)*pointer, 187 sizeof(acpi_descriptor_header), kDefaultPageFlags); 188 189 if (header == NULL 190 || strncmp(header->signature, signature, 4) != 0) { 191 // not interesting for us 192 TRACE(("acpi: Looking for '%.4s'. Skipping '%.4s'\n", 193 signature, header != NULL ? header->signature : "null")); 194 195 if (header != NULL) { 196 mmu_free(header, sizeof(acpi_descriptor_header)); 197 header = NULL; 198 } 199 200 continue; 201 } 202 203 TRACE(("acpi: Found '%.4s' @ %p\n", signature, pointer)); 204 break; 205 } 206 207 208 if (header == NULL) 209 return NULL; 210 211 // Map the whole table, not just the header 212 uint32 length = header->length; 213 mmu_free(header, sizeof(acpi_descriptor_header)); 214 215 return (acpi_descriptor_header*)mmu_map_physical_memory( 216 (uint32)*pointer, length, kDefaultPageFlags); 217 } 218 219 220 acpi_descriptor_header* 221 acpi_find_table(const char* signature) 222 { 223 if (sAcpiRsdt != NULL) 224 return acpi_find_table_generic<uint32>(signature, sAcpiRsdt); 225 else if (sAcpiXsdt != NULL) 226 return acpi_find_table_generic<uint64>(signature, sAcpiXsdt); 227 228 return NULL; 229 } 230 231 232 void 233 acpi_init() 234 { 235 EFI_GUID acpi = ACPI_20_TABLE_GUID; 236 EFI_CONFIGURATION_TABLE *table = kSystemTable->ConfigurationTable; 237 UINTN entries = kSystemTable->NumberOfTableEntries; 238 239 // Try to find the ACPI RSDP. 240 for (uint32 i = 0; i < entries; i++) { 241 acpi_rsdp *rsdp = NULL; 242 243 EFI_GUID vendor = table[i].VendorGuid; 244 245 if (vendor.Data1 == acpi.Data1 246 && vendor.Data2 == acpi.Data2 247 && vendor.Data3 == acpi.Data3 248 && strncmp((char *)vendor.Data4, (char *)acpi.Data4, 8) == 0) { 249 rsdp = (acpi_rsdp *)(table[i].VendorTable); 250 if (strncmp((char *)rsdp, ACPI_RSDP_SIGNATURE, 8) == 0) 251 TRACE(("acpi_init: found ACPI RSDP signature at %p\n", rsdp)); 252 253 if (rsdp != NULL && acpi_check_rsdt(rsdp) == B_OK) { 254 gKernelArgs.arch_args.acpi_root = rsdp; 255 break; 256 } 257 } 258 } 259 } 260