Bug Summary

File:/boot/home/haiku/haiku/src/system/boot/platform/bios_ia32/acpi.cpp
Location:line 125, column 12
Description:Access to field 'length' results in a dereference of a null pointer (loaded from variable 'rsdt')

Annotated Source Code

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.
7 *
8 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
9 * Distributed under the terms of the NewOS License.
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//#define TRACE_ACPI
24#ifdef TRACE_ACPI
25# define TRACE(x); dprintf x
26#else
27# define TRACE(x); ;
28#endif
29
30static struct scan_spots_struct acpi_scan_spots[] = {
31 { 0x0, 0x400, 0x400 - 0x0 },
32 { 0xe0000, 0x100000, 0x100000 - 0xe0000 },
33 { 0, 0, 0 }
34};
35
36static acpi_descriptor_header* sAcpiRsdt; // System Description Table
37static acpi_descriptor_header* sAcpiXsdt; // Extended System Description Table
38static int32 sNumEntries = -1;
39
40
41static status_t
42acpi_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 // for ACPI 2.0+ we need to also validate the extended checksum
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
71static status_t
72acpi_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
83static status_t
84acpi_check_rsdt(acpi_rsdp* rsdp)
85{
86 if (acpi_validate_rsdp(rsdp) != B_OK((int)0))
6
Taking false branch
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) {
7
Taking false branch
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 // if we're ACPI v1 or we fail to map the XSDT for some reason,
111 // attempt to use the RSDT instead.
112 if (rsdt == NULL__null) {
8
Taking true branch
113 // map and validate the root system description table
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 // Map the whole table, not just the header
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
154template<typename PointerType>
155acpi_descriptor_header*
156acpi_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 // if using the xsdt, our entries are 64 bits wide.
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 // not interesting for us
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 // Map the whole table, not just the header
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
216acpi_descriptor_header*
217acpi_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
228void
229acpi_init()
230{
231 // Try to find the ACPI RSDP.
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) {
3
Taking true branch
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}