1 /* 2 * Copyright 2020 Haiku, Inc. All rights reserved. 3 * Copyright 2014, Jessica Hamilton, jessica.l.hamilton@gmail.com. 4 * Copyright 2011, Rene Gollent, rene@gollent.com. 5 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. 6 * Copyright 2007, Michael Lotz, mmlr@mlotz.ch 7 * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. 8 * Distributed under the terms of the MIT License. 9 * 10 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 11 * Distributed under the terms of the NewOS License. 12 */ 13 14 15 #include <string.h> 16 17 #include <KernelExport.h> 18 #include <SupportDefs.h> 19 20 #include <arch_acpi.h> 21 #include <boot/stage2.h> 22 #include <boot/platform.h> 23 #include <boot/stdio.h> 24 25 #include "efi_platform.h" 26 #include "acpi.h" 27 #include "mmu.h" 28 29 30 #define TRACE_ACPI 31 #ifdef TRACE_ACPI 32 # define TRACE(x) dprintf x 33 #else 34 # define TRACE(x) ; 35 #endif 36 37 38 static acpi_descriptor_header* sAcpiRsdt; // System Description Table 39 static acpi_descriptor_header* sAcpiXsdt; // Extended System Description Table 40 static int32 sNumEntries = -1; 41 42 43 static status_t 44 acpi_validate_rsdp(acpi_rsdp* rsdp) 45 { 46 const char* data = (const char*)rsdp; 47 unsigned char checksum = 0; 48 for (uint32 i = 0; i < sizeof(acpi_rsdp_legacy); i++) 49 checksum += data[i]; 50 51 if ((checksum & 0xff) != 0) { 52 TRACE(("acpi: rsdp failed basic checksum\n")); 53 return B_BAD_DATA; 54 } 55 56 // for ACPI 2.0+ we need to also validate the extended checksum 57 if (rsdp->revision > 0) { 58 for (uint32 i = sizeof(acpi_rsdp_legacy); 59 i < sizeof(acpi_rsdp_extended); i++) { 60 checksum += data[i]; 61 } 62 63 if ((checksum & 0xff) != 0) { 64 TRACE(("acpi: rsdp failed extended checksum\n")); 65 return B_BAD_DATA; 66 } 67 } 68 69 return B_OK; 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%" B_PRIx32 "\n", rsdp->rsdt_address)); 96 97 acpi_descriptor_header* rsdt = NULL; 98 if (rsdp->revision > 0) { 99 rsdt = (acpi_descriptor_header*)(addr_t)rsdp->xsdt_address; 100 if (rsdt != NULL 101 && strncmp(rsdt->signature, ACPI_XSDT_SIGNATURE, 4) != 0) { 102 rsdt = NULL; 103 TRACE(("acpi: invalid extended system description table\n")); 104 } else 105 usingXsdt = true; 106 } 107 108 // if we're ACPI v1 or we fail to map the XSDT for some reason, 109 // attempt to use the RSDT instead. 110 if (rsdt == NULL) { 111 // validate the root system description table 112 rsdt = (acpi_descriptor_header*)(addr_t)rsdp->rsdt_address; 113 if (rsdt == NULL) { 114 TRACE(("acpi: couldn't map rsdt header\n")); 115 return B_ERROR; 116 } 117 if (strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 0) { 118 rsdt = NULL; 119 TRACE(("acpi: invalid root system description table\n")); 120 return B_ERROR; 121 } 122 123 TRACE(("acpi: rsdt length: %" B_PRIu32 "\n", rsdt->length)); 124 } 125 126 if (rsdt != NULL) { 127 if (acpi_validate_rsdt(rsdt) != B_OK) { 128 TRACE(("acpi: rsdt failed checksum validation\n")); 129 return B_ERROR; 130 } else { 131 if (usingXsdt) 132 sAcpiXsdt = rsdt; 133 else 134 sAcpiRsdt = rsdt; 135 TRACE(("acpi: found valid %s at %p\n", 136 usingXsdt ? ACPI_XSDT_SIGNATURE : ACPI_RSDT_SIGNATURE, 137 rsdt)); 138 } 139 } else 140 return B_ERROR; 141 142 return B_OK; 143 } 144 145 template<typename PointerType> 146 acpi_descriptor_header* 147 acpi_find_table_generic(const char* signature, acpi_descriptor_header* acpiSdt) 148 { 149 if (acpiSdt == NULL) 150 return NULL; 151 152 if (sNumEntries == -1) { 153 // if using the xsdt, our entries are 64 bits wide. 154 sNumEntries = (acpiSdt->length - sizeof(acpi_descriptor_header)) 155 / sizeof(PointerType); 156 } 157 158 if (sNumEntries <= 0) { 159 TRACE(("acpi: root system description table is empty\n")); 160 return NULL; 161 } 162 163 TRACE(("acpi: searching %" B_PRId32 " entries for table '%.4s'\n", sNumEntries, 164 signature)); 165 166 PointerType* pointer = (PointerType*)((uint8*)acpiSdt 167 + sizeof(acpi_descriptor_header)); 168 169 acpi_descriptor_header* header = NULL; 170 for (int32 j = 0; j < sNumEntries; j++, pointer++) { 171 header = (acpi_descriptor_header*)(addr_t)*pointer; 172 if (header != NULL && strncmp(header->signature, signature, 4) == 0) { 173 TRACE(("acpi: Found '%.4s' @ %p\n", signature, pointer)); 174 return header; 175 } 176 177 TRACE(("acpi: Looking for '%.4s'. Skipping '%.4s'\n", 178 signature, header != NULL ? header->signature : "null")); 179 header = NULL; 180 continue; 181 } 182 183 return NULL; 184 } 185 186 187 acpi_descriptor_header* 188 acpi_find_table(const char* signature) 189 { 190 if (sAcpiRsdt != NULL) 191 return acpi_find_table_generic<uint32>(signature, sAcpiRsdt); 192 else if (sAcpiXsdt != NULL) 193 return acpi_find_table_generic<uint64>(signature, sAcpiXsdt); 194 195 return NULL; 196 } 197 198 199 void __attribute__((weak)) 200 arch_handle_acpi() 201 { 202 } 203 204 205 void 206 acpi_init() 207 { 208 efi_guid acpi = ACPI_20_TABLE_GUID; 209 efi_configuration_table *table = kSystemTable->ConfigurationTable; 210 size_t entries = kSystemTable->NumberOfTableEntries; 211 212 // Try to find the ACPI RSDP. 213 for (uint32 i = 0; i < entries; i++) { 214 if (!table[i].VendorGuid.equals(acpi)) 215 continue; 216 217 acpi_rsdp *rsdp = (acpi_rsdp *)(table[i].VendorTable); 218 if (strncmp((char *)rsdp, ACPI_RSDP_SIGNATURE, 8) == 0) 219 TRACE(("acpi_init: found ACPI RSDP signature at %p\n", rsdp)); 220 221 if (rsdp != NULL && acpi_check_rsdt(rsdp) == B_OK) { 222 gKernelArgs.arch_args.acpi_root = rsdp; 223 arch_handle_acpi(); 224 break; 225 } 226 } 227 } 228