cpu.resource(pc-i386) Get this compile again, with acpica.library
[AROS.git] / arch / all-pc / acpi / acpi_init.c
blob7e98a4ab08d2f294bec1011220da19b216bde9a4
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <aros/debug.h>
7 #include <aros/kernel.h>
8 #include <aros/symbolsets.h>
9 #include <resources/acpi.h>
10 #include <resources/efi.h>
11 #include <proto/acpi.h>
12 #include <proto/arossupport.h>
13 #include <proto/efi.h>
14 #include <proto/exec.h>
15 #include <proto/kernel.h>
17 #include <string.h>
19 #include "acpi_intern.h"
21 static void *core_ACPIRootSystemDescriptionPointerScan(IPTR scan_start, IPTR scan_length)
23 unsigned long scan_offset;
24 unsigned char *scan_ptr;
26 /* Scan for the Root System Description Pointer signature
27 on 16-byte boundaries of the physical memory region */
28 for (scan_offset = 0; scan_offset < scan_length; scan_offset += 16)
30 scan_ptr = (unsigned char *)scan_start + scan_offset;
32 if (!memcmp(scan_ptr, "RSD PTR ", 8))
34 /* We have the signature, let's check the checksum*/
35 struct ACPI_TABLE_TYPE_RSDP *rsdp = (struct ACPI_TABLE_TYPE_RSDP *)scan_ptr;
37 if (!acpi_CheckSum(scan_ptr, (rsdp->revision < 2) ? 20 : rsdp->length))
39 /* RSDP located, return its address */
40 return scan_ptr;
42 D(bug("[ACPI] Wrong RDSP checksum at 0x%p\n", scan_ptr));
46 return NULL;
49 static const uuid_t acpi_20_guid = ACPI_20_TABLE_GUID;
50 static const uuid_t acpi_10_guid = ACPI_TABLE_GUID;
52 /* Attempt to locate the ACPI Root System Description Pointer */
53 static void *core_ACPIRootSystemDescriptionPointerLocate(struct EFIBase *EFIBase)
55 struct ACPI_TABLE_TYPE_RSDP *RSDP_PhysAddr;
57 D(bug("[ACPI] efi.resource 0x%p\n", EFIBase));
58 if (EFIBase)
60 /* If we have EFI firmware, the best way to obtain RSDP is to ask it. */
61 RSDP_PhysAddr = EFI_FindConfigTable(&acpi_20_guid);
62 if (RSDP_PhysAddr)
64 D(bug("[ACPI] Got RSDP 2.0 from EFI @ 0x%p\n", RSDP_PhysAddr));
66 if (!memcmp(RSDP_PhysAddr, "RSD PTR ", 8) && !acpi_CheckSum(RSDP_PhysAddr, RSDP_PhysAddr->length))
67 return RSDP_PhysAddr;
69 D(bug("[ACPI] Broken RSDP\n"));
72 RSDP_PhysAddr = EFI_FindConfigTable(&acpi_10_guid);
73 if (RSDP_PhysAddr)
75 D(bug("[ACPI] Got RSDP 1.0 from EFI @ 0x%p\n", RSDP_PhysAddr));
77 if (!memcmp(RSDP_PhysAddr, "RSD PTR ", 8) && !acpi_CheckSum(RSDP_PhysAddr, 20))
78 return RSDP_PhysAddr;
80 D(bug("[ACPI] Broken RSDP\n"));
84 * If there's no RSDP in EFI tables, we'll search for it, just in case.
85 * However, to tell the truth, we are unlikely to find it. For example
86 * on MacMini RSDP is located neither in EBDA nor in ROM space.
87 * Specification Rev 4.0a explicitly says that on UEFI systems RSDP
88 * pointer should be obtained from within EFI system table.
92 /*
93 * Search the first Kilobyte of the Extended BIOS Data Area.
94 * On x86-64 zero page is protected, on i386 it will someday be too.
95 * This code relies on the fact that InitCode(RTF_SINGLETASK) is called with
96 * supervisor privileges. With them you can at least read these locations.
98 RSDP_PhysAddr = core_ACPIRootSystemDescriptionPointerScan(0x00000000, 0x00000400);
100 if (RSDP_PhysAddr != NULL)
102 D(bug("[ACPI] RSDP found in EBDA @ %p\n", RSDP_PhysAddr));
103 return RSDP_PhysAddr;
106 /* Search in BIOS ROM address space */
107 if ((RSDP_PhysAddr = core_ACPIRootSystemDescriptionPointerScan(0x000E0000, 0x00020000)) != NULL)
109 D(bug("[ACPI] RSDP found in BIOS ROM space @ %p\n", RSDP_PhysAddr));
110 return RSDP_PhysAddr;
113 return NULL;
116 /**********************************************************/
117 static int acpi_ParseSDT(struct ACPIBase *ACPIBase)
119 struct ACPI_TABLE_TYPE_RSDP *RSDP = ACPIBase->ACPIB_RSDP_Addr;
120 struct ACPI_TABLE_TYPE_RSDT *RSDT = (APTR)(IPTR)RSDP->rsdt_address;
121 struct ACPI_TABLE_TYPE_XSDT *XSDT = (RSDP->revision >= 2) ? (APTR)(IPTR)RSDP->xsdt_address : NULL;
122 unsigned int i;
124 D(bug("[ACPI] acpi_ParseSDT: ACPI v2 XSDT @ %p, ACPI v1 RSDT @ %p\n", XSDT, RSDT));
126 if (!acpi_CheckTable(&XSDT->header, ACPI_MAKE_ID('X', 'S', 'D', 'T')))
128 ACPIBase->ACPIB_SDT_Addr = &XSDT->header;
130 ACPIBase->ACPIB_SDT_Count = (XSDT->header.length - sizeof(struct ACPI_TABLE_DEF_HEADER)) >> 3;
131 D(bug("[ACPI] acpi_ParseSDT: XSDT size: %u entries\n", ACPIBase->ACPIB_SDT_Count));
133 if (ACPIBase->ACPIB_SDT_Count == 0)
135 /* ???? */
136 return 1;
139 /* Plus 1 in order to reserve one pointer for DSDT */
140 ACPIBase->ACPIB_SDT_Entry = AllocMem((ACPIBase->ACPIB_SDT_Count + 1) * sizeof(APTR), MEMF_ANY);
141 if (!ACPIBase->ACPIB_SDT_Entry)
143 D(bug("[ACPI] Failed to allocate memory for XSDT entries!\n"));
144 return 0;
147 D(bug("[ACPI] acpi_ParseSDT: Copying Tables Start\n"));
148 for (i = 0; i < ACPIBase->ACPIB_SDT_Count; i++)
150 ACPIBase->ACPIB_SDT_Entry[i] = (APTR)(IPTR)XSDT->entry[i];
151 D(bug("[ACPI] acpi_ParseSDT: Table %u Entry @ %p\n", i, ACPIBase->ACPIB_SDT_Entry[i]));
154 D(bug("[ACPI] acpi_ParseSDT: Copying Tables done!\n"));
155 return 1;
158 D(bug("[ACPI] Broken (or no) XSDT, trying RSDT...\n"));
160 /* If there is no (or damager) XSDT, then check RSDT */
161 if (!acpi_CheckTable(&RSDT->header, ACPI_MAKE_ID('R', 'S', 'D', 'T')))
163 ACPIBase->ACPIB_SDT_Addr = &RSDT->header;
165 ACPIBase->ACPIB_SDT_Count = (RSDT->header.length - sizeof(struct ACPI_TABLE_DEF_HEADER)) >> 2;
166 D(bug("[ACPI] acpi_ParseSDT: RSDT size: %u entries\n", ACPIBase->ACPIB_SDT_Count));
168 if (ACPIBase->ACPIB_SDT_Count == 0)
170 /* ???? */
171 return 1;
174 /* Plus 1 in order to reserve one pointer for DSDT */
175 ACPIBase->ACPIB_SDT_Entry = AllocMem((ACPIBase->ACPIB_SDT_Count + 1) * sizeof(APTR), MEMF_ANY);
176 if (!ACPIBase->ACPIB_SDT_Entry)
178 D(bug("[ACPI] Failed to allocate memory for RSDT entries!\n"));
179 return 0;
182 D(bug("[ACPI] acpi_ParseSDT: Copying Tables Start\n"));
183 for (i = 0; i < ACPIBase->ACPIB_SDT_Count; i++)
185 ACPIBase->ACPIB_SDT_Entry[i] = (APTR)(IPTR)RSDT->entry[i];
186 D(bug("[ACPI] acpi_ParseSDT: Table %u Entry @ %p\n", i, ACPIBase->ACPIB_SDT_Entry[i]));
189 D(bug("[ACPI] acpi_ParseSDT: Copying Tables done!\n"));
190 return 1;
193 D(bug("[ACPI] Broken (or no) RSDT\n"));
195 return 0;
198 static int acpi_CheckSDT(struct ACPIBase *ACPIBase)
200 struct ACPI_TABLE_TYPE_FADT *FADT = NULL;
201 struct ACPI_TABLE_DEF_HEADER *header;
202 unsigned int c = 0;
203 unsigned int i;
205 D(bug("[ACPI] Checking SDT Tables..\n"));
207 for (i = 0; i < ACPIBase->ACPIB_SDT_Count; i++)
209 header = ACPIBase->ACPIB_SDT_Entry[i];
211 if (header == NULL)
213 D(bug("[ACPI] NULL pointer for table %u\n", i));
214 continue;
217 D(bug("[ACPI] Table %d Header @ %p, sig='%4.4s'\n", i, header, &header->signature));
219 if (acpi_CheckSum(header, header->length))
221 D(bug("[ACPI] WARNING - SDT %d Checksum invalid\n", i));
222 /* Throw away broken table */
223 continue;
226 /* Pack our array, to simplify access to it */
227 ACPIBase->ACPIB_SDT_Entry[c++] = header;
229 if (header->signature == ACPI_MAKE_ID('F', 'A', 'C', 'P'))
230 FADT = (struct ACPI_TABLE_TYPE_FADT *)header;
233 D(bug("[ACPI] Tables checked, %u of %u good\n", ACPIBase->ACPIB_SDT_Count, c));
235 if (FADT)
237 /* Map the DSDT header via the pointer in the FADT */
238 header = (APTR)(IPTR)FADT->dsdt_addr;
239 D(bug("[ACPI] Got DSDT at 0x%p\n", header));
241 if (!acpi_CheckTable(header, ACPI_MAKE_ID('D', 'S', 'D', 'T')))
243 D(bug("[ACPI] DSDT checked, good\n"));
244 /* We have reserved this pointer above, when allocated SDT array */
245 ACPIBase->ACPIB_SDT_Entry[c++] = header;
249 /* Fix up tables count */
250 ACPIBase->ACPIB_SDT_Count = c;
251 return c;
254 AROS_INTH1(static ResetHandler, struct ACPIBase *, ACPIBase)
256 AROS_INTFUNC_INIT
258 UBYTE action = ACPIBase->ACPIB_ResetHandler.is_Node.ln_Type;
259 struct ACPI_TABLE_TYPE_FADT *fadt =
260 ACPI_FindSDT(ACPI_MAKE_ID('F','A','C','P'));
262 D(bug("[ACPI.ShutdownA] FADT 0x%p\n", fadt));
264 switch (action)
266 case SD_ACTION_COLDREBOOT:
268 /* Use reset register */
269 D(bug("[ACPI.ShutdownA] Reset register 0x%p, value 0x%02X\n",
270 (IPTR)fadt->reset_reg.address, fadt->reset_value));
271 ACPI_WriteReg(&fadt->reset_reg, fadt->reset_value);
273 /* We really should not return from that */
274 break;
277 return FALSE;
279 AROS_INTFUNC_EXIT
282 static int acpi_Init(struct ACPIBase *ACPIBase)
284 APTR KernelBase;
285 struct EFIBase *EFIBase;
288 * We are part of package. To make user's life simpler, we allow to disable ourselves
289 * without repacking.
291 KernelBase = OpenResource("kernel.resource");
292 if (KernelBase)
294 struct TagItem *cmdline = LibFindTagItem(KRN_CmdLine, KrnGetBootInfo());
296 if (cmdline)
298 if (strcasestr((char *)cmdline->ti_Data, "noacpi"))
300 D(bug("[ACPI] Disabled from command line\n"));
301 return FALSE;
306 EFIBase = OpenResource("efi.resource");
308 ACPIBase->ACPIB_RSDP_Addr = core_ACPIRootSystemDescriptionPointerLocate(EFIBase);
309 if (!ACPIBase->ACPIB_RSDP_Addr)
311 D(bug("[ACPI] No RSDP found, giving up...\n"));
312 return FALSE;
316 * Cache OEM and revision for simpler access.
317 * Using memcpy() here allows the compiler to optimize 6 bytes copy.
319 memcpy(ACPIBase->ACPI_OEM_ID, ACPIBase->ACPIB_RSDP_Addr->oem_id, sizeof(ACPIBase->ACPI_OEM_ID));
320 ACPIBase->ACPI_Revision = ACPIBase->ACPIB_RSDP_Addr->revision;
322 /* Parse SDT, canonicalize addresses of tables pointed to by it */
323 if (!acpi_ParseSDT(ACPIBase))
325 D(bug("[ACPI] No valid System Description Table (SDT) specified in RSDP!\n"));
326 return FALSE;
329 /* Validate SDT tables */
330 if (!acpi_CheckSDT(ACPIBase))
332 D(bug("[ACPI] None of SDT entries are valid\n"));
333 return FALSE;
336 #ifdef ENABLE_BLACKLIST
338 * Blacklist mainly affects DSDT. Other tables still contain useful information.
339 * Currently blacklist is disabled because we do not interpret ASL at all.
340 * Perhaps it should go back in some other place, but not here.
342 if (acpi_IsBlacklisted(ACPIBase))
344 D(bug("[ACPI] Blacklisted\n"));
345 return FALSE;
347 #endif
349 /* Install ACPI reset handler. It has a lower priority than the EFI
350 * reset handler (for example), so will only be used if better
351 * mechanisms fail */
352 ACPIBase->ACPIB_ResetHandler.is_Node.ln_Pri = -60;
353 ACPIBase->ACPIB_ResetHandler.is_Code = (VOID_FUNC)ResetHandler;
354 ACPIBase->ACPIB_ResetHandler.is_Data = ACPIBase;
355 AddResetCallback(&ACPIBase->ACPIB_ResetHandler);
357 return TRUE;
360 ADD2INITLIB(acpi_Init, 0);