2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
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>
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 */
42 D(bug("[ACPI] Wrong RDSP checksum at 0x%p\n", scan_ptr
));
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
));
60 /* If we have EFI firmware, the best way to obtain RSDP is to ask it. */
61 RSDP_PhysAddr
= EFI_FindConfigTable(&acpi_20_guid
);
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
))
69 D(bug("[ACPI] Broken RSDP\n"));
72 RSDP_PhysAddr
= EFI_FindConfigTable(&acpi_10_guid
);
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))
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.
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
;
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
;
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)
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"));
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"));
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)
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"));
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"));
193 D(bug("[ACPI] Broken (or no) RSDT\n"));
198 static int acpi_CheckSDT(struct ACPIBase
*ACPIBase
)
200 struct ACPI_TABLE_TYPE_FADT
*FADT
= NULL
;
201 struct ACPI_TABLE_DEF_HEADER
*header
;
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
];
213 D(bug("[ACPI] NULL pointer for table %u\n", i
));
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 */
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
));
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
;
254 AROS_INTH1(static ResetHandler
, struct ACPIBase
*, ACPIBase
)
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
));
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 */
282 static int acpi_Init(struct ACPIBase
*ACPIBase
)
285 struct EFIBase
*EFIBase
;
288 * We are part of package. To make user's life simpler, we allow to disable ourselves
291 KernelBase
= OpenResource("kernel.resource");
294 struct TagItem
*cmdline
= LibFindTagItem(KRN_CmdLine
, KrnGetBootInfo());
298 if (strcasestr((char *)cmdline
->ti_Data
, "noacpi"))
300 D(bug("[ACPI] Disabled from command line\n"));
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"));
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"));
329 /* Validate SDT tables */
330 if (!acpi_CheckSDT(ACPIBase
))
332 D(bug("[ACPI] None of SDT entries are valid\n"));
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"));
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
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
);
360 ADD2INITLIB(acpi_Init
, 0);