1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
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 | |
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; |
37 | static acpi_descriptor_header* sAcpiXsdt; |
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((-2147483647 - 1) + 16); |
52 | } |
53 | |
54 | |
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((-2147483647 - 1) + 16); |
64 | } |
65 | } |
66 | |
67 | return B_OK((int)0); |
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((int)0) : B_BAD_DATA((-2147483647 - 1) + 16); |
80 | } |
81 | |
82 | |
83 | static status_t |
84 | acpi_check_rsdt(acpi_rsdp* rsdp) |
85 | { |
86 | if (acpi_validate_rsdp(rsdp) != B_OK((int)0)) |
| |
87 | return B_BAD_DATA((-2147483647 - 1) + 16); |
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__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__null |
102 | && strncmp(rsdt->signature, ACPI_XSDT_SIGNATURE"XSDT", 4) != 0) { |
103 | mmu_free(rsdt, rsdp->xsdt_length); |
104 | rsdt = NULL__null; |
105 | TRACE(("acpi: invalid extended system description table\n"));; |
106 | } else |
107 | usingXsdt = true; |
108 | } |
109 | |
110 | |
111 | |
112 | if (rsdt == NULL__null) { |
| |
113 | |
114 | rsdt = (acpi_descriptor_header*)mmu_map_physical_memory( |
| 9 | | Value assigned to 'rsdt' | |
|
115 | rsdp->rsdt_address, sizeof(acpi_descriptor_header), |
116 | kDefaultPageFlags); |
117 | if (rsdt != NULL__null |
| 10 | | Assuming pointer value is null | |
|
118 | && strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE"RSDT", 4) != 0) { |
119 | mmu_free(rsdt, sizeof(acpi_descriptor_header)); |
120 | rsdt = NULL__null; |
121 | TRACE(("acpi: invalid root system description table\n"));; |
122 | return B_ERROR(-1); |
123 | } |
124 | |
125 | length = rsdt->length; |
| 11 | | Access to field 'length' results in a dereference of a null pointer (loaded from variable 'rsdt') |
|
126 | |
127 | TRACE(("acpi: rsdt length: %lu\n", length));; |
128 | mmu_free(rsdt, sizeof(acpi_descriptor_header)); |
129 | rsdt = (acpi_descriptor_header*)mmu_map_physical_memory( |
130 | rsdp->rsdt_address, length, kDefaultPageFlags); |
131 | } |
132 | |
133 | if (rsdt != NULL__null) { |
134 | if (acpi_validate_rsdt(rsdt) != B_OK((int)0)) { |
135 | TRACE(("acpi: rsdt failed checksum validation\n"));; |
136 | mmu_free(rsdt, length); |
137 | return B_ERROR(-1); |
138 | } else { |
139 | if (usingXsdt) |
140 | sAcpiXsdt = rsdt; |
141 | else |
142 | sAcpiRsdt = rsdt; |
143 | TRACE(("acpi: found valid %s at %p\n",; |
144 | usingXsdt ? ACPI_XSDT_SIGNATURE : ACPI_RSDT_SIGNATURE,; |
145 | rsdt));; |
146 | } |
147 | } else |
148 | return B_ERROR(-1); |
149 | |
150 | return B_OK((int)0); |
151 | } |
152 | |
153 | |
154 | template<typename PointerType> |
155 | acpi_descriptor_header* |
156 | acpi_find_table_generic(const char* signature, acpi_descriptor_header* acpiSdt) |
157 | { |
158 | if (acpiSdt == NULL__null) |
159 | return NULL__null; |
160 | |
161 | if (sNumEntries == -1) { |
162 | |
163 | sNumEntries = (acpiSdt->length |
164 | - sizeof(acpi_descriptor_header)) |
165 | / sizeof(PointerType); |
166 | } |
167 | |
168 | if (sNumEntries <= 0) { |
169 | TRACE(("acpi: root system description table is empty\n"));; |
170 | return NULL__null; |
171 | } |
172 | |
173 | TRACE(("acpi: searching %ld entries for table '%.4s'\n", sNumEntries,; |
174 | signature));; |
175 | |
176 | PointerType* pointer = (PointerType*)((uint8*)acpiSdt |
177 | + sizeof(acpi_descriptor_header)); |
178 | |
179 | acpi_descriptor_header* header = NULL__null; |
180 | for (int32 j = 0; j < sNumEntries; j++, pointer++) { |
181 | header = (acpi_descriptor_header*) |
182 | mmu_map_physical_memory((uint32)*pointer, |
183 | sizeof(acpi_descriptor_header), kDefaultPageFlags); |
184 | |
185 | if (header == NULL__null |
186 | || strncmp(header->signature, signature, 4) != 0) { |
187 | |
188 | TRACE(("acpi: Looking for '%.4s'. Skipping '%.4s'\n",; |
189 | signature, header != NULL ? header->signature : "null"));; |
190 | |
191 | if (header != NULL__null) { |
192 | mmu_free(header, sizeof(acpi_descriptor_header)); |
193 | header = NULL__null; |
194 | } |
195 | |
196 | continue; |
197 | } |
198 | |
199 | TRACE(("acpi: Found '%.4s' @ %p\n", signature, pointer));; |
200 | break; |
201 | } |
202 | |
203 | |
204 | if (header == NULL__null) |
205 | return NULL__null; |
206 | |
207 | |
208 | uint32 length = header->length; |
209 | mmu_free(header, sizeof(acpi_descriptor_header)); |
210 | |
211 | return (acpi_descriptor_header*)mmu_map_physical_memory( |
212 | (uint32)*pointer, length, kDefaultPageFlags); |
213 | } |
214 | |
215 | |
216 | acpi_descriptor_header* |
217 | acpi_find_table(const char* signature) |
218 | { |
219 | if (sAcpiRsdt != NULL__null) |
220 | return acpi_find_table_generic<uint32>(signature, sAcpiRsdt); |
221 | else if (sAcpiXsdt != NULL__null) |
222 | return acpi_find_table_generic<uint64>(signature, sAcpiXsdt); |
223 | |
224 | return NULL__null; |
225 | } |
226 | |
227 | |
228 | void |
229 | acpi_init() |
230 | { |
231 | |
232 | for (int32 i = 0; acpi_scan_spots[i].length > 0; i++) { |
| 1 | Loop condition is true. Entering loop body | |
|
233 | acpi_rsdp* rsdp = NULL__null; |
234 | |
235 | TRACE(("acpi_init: entry base 0x%lx, limit 0x%lx\n",; |
236 | acpi_scan_spots[i].start, acpi_scan_spots[i].stop));; |
237 | |
238 | for (char* pointer = (char*)acpi_scan_spots[i].start; |
| 2 | | Loop condition is true. Entering loop body | |
|
| 4 | | Loop condition is false. Execution continues on line 247 | |
|
239 | (uint32)pointer < acpi_scan_spots[i].stop; pointer += 16) { |
240 | if (strncmp(pointer, ACPI_RSDP_SIGNATURE"RSD PTR ", 8) == 0) { |
| |
241 | TRACE(("acpi_init: found ACPI RSDP signature at %p\n",; |
242 | pointer));; |
243 | rsdp = (acpi_rsdp*)pointer; |
244 | } |
245 | } |
246 | |
247 | if (rsdp != NULL__null && acpi_check_rsdt(rsdp) == B_OK((int)0)) |
| 5 | | Calling 'acpi_check_rsdt' | |
|
248 | break; |
249 | } |
250 | } |