1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "pci_acpi.h" |
14 | |
15 | #include <string.h> |
16 | |
17 | #include <KernelExport.h> |
18 | |
19 | #include <arch/x86/arch_acpi.h> |
20 | |
21 | |
22 | |
23 | #ifdef TRACE_ACPI |
24 | # define TRACE(x); dprintf x |
25 | #else |
26 | # define TRACE(x); ; |
27 | #endif |
28 | |
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 } |
35 | }; |
36 | |
37 | static acpi_descriptor_header* sAcpiRsdt; |
38 | static acpi_descriptor_header* sAcpiXsdt; |
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((-2147483647 - 1) + 16); |
53 | } |
54 | |
55 | |
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((-2147483647 - 1) + 16); |
65 | } |
66 | } |
67 | |
68 | return B_OK((int)0); |
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((int)0) : B_BAD_DATA((-2147483647 - 1) + 16); |
81 | } |
82 | |
83 | |
84 | static status_t |
85 | acpi_check_rsdt(acpi_rsdp* rsdp) |
86 | { |
87 | if (acpi_validate_rsdp(rsdp) != B_OK((int)0)) |
| |
88 | return B_BAD_DATA((-2147483647 - 1) + 16); |
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__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_ADDRESS4, |
103 | B_KERNEL_READ_AREA16, (void **)&rsdt); |
104 | if (rsdt != NULL__null |
105 | && strncmp(rsdt->signature, ACPI_XSDT_SIGNATURE"XSDT", 4) != 0) { |
106 | delete_area(rsdtArea); |
107 | rsdt = NULL__null; |
108 | TRACE(("acpi: invalid extended system description table\n"));; |
109 | } else |
110 | usingXsdt = true; |
111 | } |
112 | |
113 | |
114 | |
115 | if (rsdt == NULL__null) { |
| |
116 | |
117 | rsdtArea = map_physical_memory("rsdt acpi", |
| 11 | | Value assigned to 'rsdt' | |
|
118 | rsdp->rsdt_address, sizeof(acpi_descriptor_header), |
119 | B_ANY_KERNEL_ADDRESS4, B_KERNEL_READ_AREA16, (void **)&rsdt); |
120 | if (rsdt != NULL__null |
| 12 | | Assuming pointer value is null | |
|
121 | && strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE"RSDT", 4) != 0) { |
122 | delete_area(rsdtArea); |
123 | rsdt = NULL__null; |
124 | TRACE(("acpi: invalid root system description table\n"));; |
125 | return B_ERROR(-1); |
126 | } |
127 | |
128 | length = rsdt->length; |
| 13 | | Access to field 'length' results in a dereference of a null pointer (loaded from variable 'rsdt') |
|
129 | |
130 | TRACE(("acpi: rsdt length: %lu\n", length));; |
131 | delete_area(rsdtArea); |
132 | rsdtArea = map_physical_memory("rsdt acpi", |
133 | rsdp->rsdt_address, length, B_ANY_KERNEL_ADDRESS4, |
134 | B_KERNEL_READ_AREA16, (void **)&rsdt); |
135 | } |
136 | |
137 | if (rsdt != NULL__null) { |
138 | if (acpi_validate_rsdt(rsdt) != B_OK((int)0)) { |
139 | TRACE(("acpi: rsdt failed checksum validation\n"));; |
140 | delete_area(rsdtArea); |
141 | return B_ERROR(-1); |
142 | } else { |
143 | if (usingXsdt) |
144 | sAcpiXsdt = rsdt; |
145 | else |
146 | sAcpiRsdt = rsdt; |
147 | TRACE(("acpi: found valid %s at %p\n",; |
148 | usingXsdt ? ACPI_XSDT_SIGNATURE : ACPI_RSDT_SIGNATURE,; |
149 | rsdt));; |
150 | } |
151 | } else |
152 | return B_ERROR(-1); |
153 | |
154 | return B_OK((int)0); |
155 | } |
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__null) |
163 | return NULL__null; |
164 | |
165 | if (sNumEntries == -1) { |
166 | |
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__null; |
175 | } |
176 | |
177 | TRACE(("acpi: searching %ld 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__null; |
184 | area_id headerArea = -1; |
185 | for (int32 j = 0; j < sNumEntries; j++, pointer++) { |
186 | headerArea = map_physical_memory("acpi header", (uint32)*pointer, |
187 | sizeof(acpi_descriptor_header), B_ANY_KERNEL_ADDRESS4, |
188 | B_KERNEL_READ_AREA16, (void **)&header); |
189 | |
190 | if (header == NULL__null |
191 | || strncmp(header->signature, signature, 4) != 0) { |
192 | |
193 | TRACE(("acpi: Looking for '%.4s'. Skipping '%.4s'\n",; |
194 | signature, header != NULL ? header->signature : "null"));; |
195 | |
196 | if (header != NULL__null) { |
197 | delete_area(headerArea); |
198 | header = NULL__null; |
199 | } |
200 | |
201 | continue; |
202 | } |
203 | |
204 | TRACE(("acpi: Found '%.4s' @ %p\n", signature, pointer));; |
205 | break; |
206 | } |
207 | |
208 | |
209 | if (header == NULL__null) |
210 | return NULL__null; |
211 | |
212 | |
213 | uint32 length = header->length; |
214 | delete_area(headerArea); |
215 | |
216 | headerArea = map_physical_memory("acpi table", |
217 | (uint32)*pointer, length, B_ANY_KERNEL_ADDRESS4, |
218 | B_KERNEL_READ_AREA16, (void **)&header); |
219 | return header; |
220 | } |
221 | |
222 | |
223 | void* |
224 | acpi_find_table(const char* signature) |
225 | { |
226 | if (sAcpiRsdt != NULL__null) |
227 | return acpi_find_table_generic<uint32>(signature, sAcpiRsdt); |
228 | else if (sAcpiXsdt != NULL__null) |
229 | return acpi_find_table_generic<uint64>(signature, sAcpiXsdt); |
230 | |
231 | return NULL__null; |
232 | } |
233 | |
234 | |
235 | void |
236 | acpi_init() |
237 | { |
238 | |
239 | for (int32 i = 0; acpi_scan_spots[i].length > 0; i++) { |
| 1 | Loop condition is true. Entering loop body | |
|
240 | acpi_rsdp* rsdp = NULL__null; |
241 | |
242 | TRACE(("acpi_init: entry base 0x%lx, limit 0x%lx\n",; |
243 | acpi_scan_spots[i].start, acpi_scan_spots[i].stop));; |
244 | |
245 | char* start = NULL__null; |
246 | area_id rsdpArea = map_physical_memory("acpi rsdp", |
247 | acpi_scan_spots[i].start, acpi_scan_spots[i].length, |
248 | B_ANY_KERNEL_ADDRESS4, B_KERNEL_READ_AREA16, (void **)&start); |
249 | if (rsdpArea < B_OK((int)0)) { |
| 2 | | Assuming 'rsdpArea' is >= 0 | |
|
| |
250 | TRACE(("acpi_init: couldn't map %s\n", strerror(rsdpArea)));; |
251 | break; |
252 | } |
253 | for (char *pointer = start; |
| 4 | | Loop condition is true. Entering loop body | |
|
| 6 | | Loop condition is false. Execution continues on line 263 | |
|
254 | (addr_t)pointer < (addr_t)start + acpi_scan_spots[i].length; |
255 | pointer += 16) { |
256 | if (strncmp(pointer, ACPI_RSDP_SIGNATURE"RSD PTR ", 8) == 0) { |
| |
257 | TRACE(("acpi_init: found ACPI RSDP signature at %p\n",; |
258 | pointer));; |
259 | rsdp = (acpi_rsdp*)pointer; |
260 | } |
261 | } |
262 | |
263 | if (rsdp != NULL__null && acpi_check_rsdt(rsdp) == B_OK((int)0)) { |
| 7 | | Calling 'acpi_check_rsdt' | |
|
264 | delete_area(rsdpArea); |
265 | break; |
266 | } |
267 | delete_area(rsdpArea); |
268 | } |
269 | |
270 | } |