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.
17 #include <KernelExport.h>
19 #include <arch/x86/arch_acpi.h>
24 # define TRACE(x) dprintf x
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},
37 static acpi_descriptor_header
* sAcpiRsdt
; // System Description Table
38 static acpi_descriptor_header
* sAcpiXsdt
; // Extended System Description Table
39 static int32 sNumEntries
= -1;
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
++)
50 if ((checksum
& 0xff) != 0) {
51 TRACE(("acpi: rsdp failed basic checksum\n"));
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
++) {
62 if ((checksum
& 0xff) != 0) {
63 TRACE(("acpi: rsdp failed extended checksum\n"));
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
++)
80 return checksum
== 0 ? B_OK
: B_BAD_DATA
;
85 acpi_check_rsdt(acpi_rsdp
* rsdp
)
87 if (acpi_validate_rsdp(rsdp
) != B_OK
)
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
));
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
);
105 && strncmp(rsdt
->signature
, ACPI_XSDT_SIGNATURE
, 4) != 0) {
106 delete_area(rsdtArea
);
108 TRACE(("acpi: invalid extended system description table\n"));
113 // if we're ACPI v1 or we fail to map the XSDT for some reason,
114 // attempt to use the RSDT instead.
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
);
121 TRACE(("acpi: couldn't map rsdt header\n"));
124 if (strncmp(rsdt
->signature
, ACPI_RSDT_SIGNATURE
, 4) != 0) {
125 delete_area(rsdtArea
);
127 TRACE(("acpi: invalid root system description table\n"));
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
);
141 if (acpi_validate_rsdt(rsdt
) != B_OK
) {
142 TRACE(("acpi: rsdt failed checksum validation\n"));
143 delete_area(rsdtArea
);
150 TRACE(("acpi: found valid %s at %p\n",
151 usingXsdt
? ACPI_XSDT_SIGNATURE
: ACPI_RSDT_SIGNATURE
,
161 template<typename PointerType
>
162 acpi_descriptor_header
*
163 acpi_find_table_generic(const char* signature
, acpi_descriptor_header
* acpiSdt
)
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"));
180 TRACE(("acpi: searching %ld entries for table '%.4s'\n", sNumEntries
,
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
);
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
);
207 TRACE(("acpi: Found '%.4s' @ %p\n", signature
, pointer
));
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
);
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
);
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
));
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
)));
256 for (char *pointer
= start
;
257 (addr_t
)pointer
< (addr_t
)start
+ acpi_scan_spots
[i
].length
;
259 if (strncmp(pointer
, ACPI_RSDP_SIGNATURE
, 8) == 0) {
260 TRACE(("acpi_init: found ACPI RSDP signature at %p\n",
262 rsdp
= (acpi_rsdp
*)pointer
;
266 if (rsdp
!= NULL
&& acpi_check_rsdt(rsdp
) == B_OK
) {
267 delete_area(rsdpArea
);
270 delete_area(rsdpArea
);