vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / bus_managers / pci / arch / x86 / pci_acpi.cpp
blob9123952041c89f4f7e68e27fdb3697d081610e7f
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.
8 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
9 * Distributed under the terms of the NewOS License.
13 #include "pci_acpi.h"
15 #include <string.h>
17 #include <KernelExport.h>
19 #include <arch/x86/arch_acpi.h>
22 //#define TRACE_ACPI
23 #ifdef TRACE_ACPI
24 # define TRACE(x) dprintf x
25 #else
26 # define TRACE(x) ;
27 #endif
29 static struct scan_spots_struct acpi_scan_spots[] = {
30 { 0x0, 0x1000, 0x1000 },
31 { 0x9f000, 0x10000, 0x1000 },
32 { 0xe0000, 0x110000, 0x20000 },
33 { 0xfd000, 0xfe000, 0x1000},
34 { 0, 0, 0 }
37 static acpi_descriptor_header* sAcpiRsdt; // System Description Table
38 static acpi_descriptor_header* sAcpiXsdt; // Extended System Description Table
39 static int32 sNumEntries = -1;
42 static status_t
43 acpi_validate_rsdp(acpi_rsdp* rsdp)
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];
50 if ((checksum & 0xff) != 0) {
51 TRACE(("acpi: rsdp failed basic checksum\n"));
52 return B_BAD_DATA;
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];
62 if ((checksum & 0xff) != 0) {
63 TRACE(("acpi: rsdp failed extended checksum\n"));
64 return B_BAD_DATA;
68 return B_OK;
72 static status_t
73 acpi_validate_rsdt(acpi_descriptor_header* rsdt)
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];
80 return checksum == 0 ? B_OK : B_BAD_DATA;
84 static status_t
85 acpi_check_rsdt(acpi_rsdp* rsdp)
87 if (acpi_validate_rsdp(rsdp) != B_OK)
88 return B_BAD_DATA;
90 bool usingXsdt = false;
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));
96 uint32 length = 0;
97 acpi_descriptor_header* rsdt = NULL;
98 area_id rsdtArea = -1;
99 if (rsdp->revision > 0) {
100 length = rsdp->xsdt_length;
101 rsdtArea = map_physical_memory("rsdt acpi",
102 (uint32)rsdp->xsdt_address, rsdp->xsdt_length, B_ANY_KERNEL_ADDRESS,
103 B_KERNEL_READ_AREA, (void **)&rsdt);
104 if (rsdt != NULL
105 && strncmp(rsdt->signature, ACPI_XSDT_SIGNATURE, 4) != 0) {
106 delete_area(rsdtArea);
107 rsdt = NULL;
108 TRACE(("acpi: invalid extended system description table\n"));
109 } else
110 usingXsdt = true;
113 // if we're ACPI v1 or we fail to map the XSDT for some reason,
114 // attempt to use the RSDT instead.
115 if (rsdt == NULL) {
116 // map and validate the root system description table
117 rsdtArea = map_physical_memory("rsdt acpi",
118 rsdp->rsdt_address, sizeof(acpi_descriptor_header),
119 B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void **)&rsdt);
120 if (rsdt == NULL) {
121 TRACE(("acpi: couldn't map rsdt header\n"));
122 return B_ERROR;
124 if (strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 0) {
125 delete_area(rsdtArea);
126 rsdt = NULL;
127 TRACE(("acpi: invalid root system description table\n"));
128 return B_ERROR;
131 length = rsdt->length;
132 // Map the whole table, not just the header
133 TRACE(("acpi: rsdt length: %lu\n", length));
134 delete_area(rsdtArea);
135 rsdtArea = map_physical_memory("rsdt acpi",
136 rsdp->rsdt_address, length, B_ANY_KERNEL_ADDRESS,
137 B_KERNEL_READ_AREA, (void **)&rsdt);
140 if (rsdt != NULL) {
141 if (acpi_validate_rsdt(rsdt) != B_OK) {
142 TRACE(("acpi: rsdt failed checksum validation\n"));
143 delete_area(rsdtArea);
144 return B_ERROR;
145 } else {
146 if (usingXsdt)
147 sAcpiXsdt = rsdt;
148 else
149 sAcpiRsdt = rsdt;
150 TRACE(("acpi: found valid %s at %p\n",
151 usingXsdt ? ACPI_XSDT_SIGNATURE : ACPI_RSDT_SIGNATURE,
152 rsdt));
154 } else
155 return B_ERROR;
157 return B_OK;
161 template<typename PointerType>
162 acpi_descriptor_header*
163 acpi_find_table_generic(const char* signature, acpi_descriptor_header* acpiSdt)
165 if (acpiSdt == NULL)
166 return NULL;
168 if (sNumEntries == -1) {
169 // if using the xsdt, our entries are 64 bits wide.
170 sNumEntries = (acpiSdt->length
171 - sizeof(acpi_descriptor_header))
172 / sizeof(PointerType);
175 if (sNumEntries <= 0) {
176 TRACE(("acpi: root system description table is empty\n"));
177 return NULL;
180 TRACE(("acpi: searching %ld entries for table '%.4s'\n", sNumEntries,
181 signature));
183 PointerType* pointer = (PointerType*)((uint8*)acpiSdt
184 + sizeof(acpi_descriptor_header));
186 acpi_descriptor_header* header = NULL;
187 area_id headerArea = -1;
188 for (int32 j = 0; j < sNumEntries; j++, pointer++) {
189 headerArea = map_physical_memory("acpi header", (uint32)*pointer,
190 sizeof(acpi_descriptor_header), B_ANY_KERNEL_ADDRESS,
191 B_KERNEL_READ_AREA, (void **)&header);
193 if (header == NULL
194 || strncmp(header->signature, signature, 4) != 0) {
195 // not interesting for us
196 TRACE(("acpi: Looking for '%.4s'. Skipping '%.4s'\n",
197 signature, header != NULL ? header->signature : "null"));
199 if (header != NULL) {
200 delete_area(headerArea);
201 header = NULL;
204 continue;
207 TRACE(("acpi: Found '%.4s' @ %p\n", signature, pointer));
208 break;
212 if (header == NULL)
213 return NULL;
215 // Map the whole table, not just the header
216 uint32 length = header->length;
217 delete_area(headerArea);
219 headerArea = map_physical_memory("acpi table",
220 (uint32)*pointer, length, B_ANY_KERNEL_ADDRESS,
221 B_KERNEL_READ_AREA, (void **)&header);
222 return header;
226 void*
227 acpi_find_table(const char* signature)
229 if (sAcpiRsdt != NULL)
230 return acpi_find_table_generic<uint32>(signature, sAcpiRsdt);
231 else if (sAcpiXsdt != NULL)
232 return acpi_find_table_generic<uint64>(signature, sAcpiXsdt);
234 return NULL;
238 void
239 acpi_init()
241 // Try to find the ACPI RSDP.
242 for (int32 i = 0; acpi_scan_spots[i].length > 0; i++) {
243 acpi_rsdp* rsdp = NULL;
245 TRACE(("acpi_init: entry base 0x%lx, limit 0x%lx\n",
246 acpi_scan_spots[i].start, acpi_scan_spots[i].stop));
248 char* start = NULL;
249 area_id rsdpArea = map_physical_memory("acpi rsdp",
250 acpi_scan_spots[i].start, acpi_scan_spots[i].length,
251 B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void **)&start);
252 if (rsdpArea < B_OK) {
253 TRACE(("acpi_init: couldn't map %s\n", strerror(rsdpArea)));
254 break;
256 for (char *pointer = start;
257 (addr_t)pointer < (addr_t)start + acpi_scan_spots[i].length;
258 pointer += 16) {
259 if (strncmp(pointer, ACPI_RSDP_SIGNATURE, 8) == 0) {
260 TRACE(("acpi_init: found ACPI RSDP signature at %p\n",
261 pointer));
262 rsdp = (acpi_rsdp*)pointer;
266 if (rsdp != NULL && acpi_check_rsdt(rsdp) == B_OK) {
267 delete_area(rsdpArea);
268 break;
270 delete_area(rsdpArea);