xref: /haiku/src/system/boot/platform/bios_ia32/acpi.cpp (revision e8cd7007416a323259791ac09c013dcce2956976)
1 /*
2  * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
3  * Copyright 2007, Michael Lotz, mmlr@mlotz.ch
4  * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de.
5  * Distributed under the terms of the MIT License.
6  *
7  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
8  * Distributed under the terms of the NewOS License.
9 */
10 
11 
12 #include "acpi.h"
13 #include "mmu.h"
14 
15 #include <string.h>
16 
17 #include <KernelExport.h>
18 
19 #include <arch/x86/arch_acpi.h>
20 
21 
22 //#define TRACE_ACPI
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, 0x400, 0x400 - 0x0 },
31 	{ 0xe0000, 0x100000, 0x100000 - 0xe0000 },
32 	{ 0, 0, 0 }
33 };
34 
35 static acpi_descriptor_header* sAcpiRsdt; // System Description Table
36 static int32 sNumEntries = -1;
37 
38 
39 static status_t
40 acpi_check_rsdt(acpi_rsdp* rsdp)
41 {
42 	TRACE(("acpi: found rsdp at %p oem id: %.6s\n", rsdp, rsdp->oem_id));
43 	TRACE(("acpi: rsdp points to rsdt at 0x%lx\n", rsdp->rsdt_address));
44 
45 	// map and validate the root system description table
46 	acpi_descriptor_header* rsdt
47 		= (acpi_descriptor_header*)mmu_map_physical_memory(
48 		rsdp->rsdt_address, sizeof(acpi_descriptor_header),
49 		kDefaultPageFlags);
50 	if (rsdt == NULL
51 		|| strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 0) {
52 		if (rsdt != NULL)
53 			mmu_free(rsdt, sizeof(acpi_descriptor_header));
54 		TRACE(("acpi: invalid root system description table\n"));
55 		return B_ERROR;
56 	}
57 
58 	sAcpiRsdt = rsdt;
59 	return B_OK;
60 }
61 
62 
63 acpi_descriptor_header*
64 acpi_find_table(const char* signature)
65 {
66 	if (sAcpiRsdt == NULL)
67 		return NULL;
68 
69 	if (sNumEntries == -1) {
70 		sNumEntries = (sAcpiRsdt->length
71 			- sizeof(acpi_descriptor_header)) / 4;
72 	}
73 
74 	if (sNumEntries <= 0) {
75 		TRACE(("acpi: root system description table is empty\n"));
76 		return NULL;
77 	}
78 
79 	TRACE(("acpi: searching %ld entries for table '%.4s'\n", sNumEntries,
80 		signature));
81 
82 	uint32* pointer = (uint32*)((uint8*)sAcpiRsdt
83 		+ sizeof(acpi_descriptor_header));
84 
85 	for (int32 j = 0; j < sNumEntries; j++, pointer++) {
86 		acpi_descriptor_header* header = (acpi_descriptor_header*)
87 			mmu_map_physical_memory(*pointer,
88 				sizeof(acpi_descriptor_header), kDefaultPageFlags);
89 		if (header == NULL
90 			|| strncmp(header->signature, signature, 4) != 0) {
91 			// not interesting for us
92 			TRACE(("acpi: Looking for '%.4s'. Skipping '%.4s'\n",
93 				signature, header != NULL ? header->signature : "null"));
94 
95 			if (header != NULL)
96 				mmu_free(header, sizeof(acpi_descriptor_header));
97 
98 			continue;
99 		}
100 
101 		TRACE(("acpi: Found '%.4s' @ %p\n", signature, pointer));
102 		return header;
103 	}
104 
105 	// If we didn't find the table, return NULL.
106 	return NULL;
107 }
108 
109 
110 void
111 acpi_init()
112 {
113 	// Try to find the ACPI RSDP.
114 	for (int32 i = 0; acpi_scan_spots[i].length > 0; i++) {
115 		acpi_rsdp* rsdp = NULL;
116 
117 		TRACE(("acpi_init: entry base 0x%lx, limit 0x%lx\n",
118 			acpi_scan_spots[i].start, acpi_scan_spots[i].stop));
119 
120 		for (char* pointer = (char*)acpi_scan_spots[i].start;
121 		     (uint32)pointer < acpi_scan_spots[i].stop; pointer += 16) {
122 			if (strncmp(pointer, ACPI_RSDP_SIGNATURE, 8) == 0) {
123 				TRACE(("acpi_init: found ACPI RSDP signature at %p\n",
124 					pointer));
125 				rsdp = (acpi_rsdp*)pointer;
126 			}
127 		}
128 
129 		if (rsdp != NULL && acpi_check_rsdt(rsdp) == B_OK)
130 			break;
131 	}
132 }
133