EFI: add ACPI support
Also add support in the kernel to get the ACPI RSDP from the bootloader, and pass onto the ACPI driver using get_boot_item.
This commit is contained in:
@@ -38,6 +38,8 @@ typedef struct {
|
|||||||
// hpet stuff
|
// hpet stuff
|
||||||
uint32 hpet_phys;
|
uint32 hpet_phys;
|
||||||
FixedWidthPointer<void> hpet;
|
FixedWidthPointer<void> hpet;
|
||||||
|
// needed for UEFI, otherwise kernel acpi support can't find ACPI root
|
||||||
|
FixedWidthPointer<void> acpi_root;
|
||||||
} _PACKED arch_kernel_args;
|
} _PACKED arch_kernel_args;
|
||||||
|
|
||||||
#endif /* KERNEL_ARCH_x86_KERNEL_ARGS_H */
|
#endif /* KERNEL_ARCH_x86_KERNEL_ARGS_H */
|
||||||
|
|||||||
@@ -127,6 +127,7 @@
|
|||||||
# include <dpc.h>
|
# include <dpc.h>
|
||||||
# include <PCI.h>
|
# include <PCI.h>
|
||||||
|
|
||||||
|
# include <boot_item.h>
|
||||||
# include <kernel.h>
|
# include <kernel.h>
|
||||||
# include <vm/vm.h>
|
# include <vm/vm.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -181,7 +182,7 @@ extern void *gDPCHandle;
|
|||||||
extern FILE *AcpiGbl_DebugFile;
|
extern FILE *AcpiGbl_DebugFile;
|
||||||
FILE *AcpiGbl_OutputFile;
|
FILE *AcpiGbl_OutputFile;
|
||||||
|
|
||||||
static uint32 sACPIRoot = 0;
|
static ACPI_PHYSICAL_ADDRESS sACPIRoot = 0;
|
||||||
static void *sInterruptHandlerData[32];
|
static void *sInterruptHandlerData[32];
|
||||||
|
|
||||||
|
|
||||||
@@ -233,12 +234,15 @@ AcpiOsGetRootPointer()
|
|||||||
{
|
{
|
||||||
#ifdef _KERNEL_MODE
|
#ifdef _KERNEL_MODE
|
||||||
ACPI_PHYSICAL_ADDRESS address;
|
ACPI_PHYSICAL_ADDRESS address;
|
||||||
ACPI_STATUS status;
|
ACPI_STATUS status = AE_OK;
|
||||||
DEBUG_FUNCTION();
|
DEBUG_FUNCTION();
|
||||||
if (sACPIRoot == 0) {
|
if (sACPIRoot == 0) {
|
||||||
status = AcpiFindRootPointer(&address);
|
sACPIRoot = (ACPI_PHYSICAL_ADDRESS)get_boot_item("ACPI_ROOT_POINTER", NULL);
|
||||||
if (status == AE_OK)
|
if (sACPIRoot == 0) {
|
||||||
sACPIRoot = address;
|
status = AcpiFindRootPointer(&address);
|
||||||
|
if (status == AE_OK)
|
||||||
|
sACPIRoot = address;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sACPIRoot;
|
return sACPIRoot;
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ local platform_src =
|
|||||||
entry.S
|
entry.S
|
||||||
mmu.cpp
|
mmu.cpp
|
||||||
heap.cpp
|
heap.cpp
|
||||||
|
acpi.cpp
|
||||||
menu.cpp
|
menu.cpp
|
||||||
devices.cpp
|
devices.cpp
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014, Jessica Hamilton, [email protected].
|
||||||
|
* Copyright 2011, Rene Gollent, [email protected].
|
||||||
|
* Copyright 2008, Dustin Howett, [email protected]. All rights reserved.
|
||||||
|
* Copyright 2007, Michael Lotz, [email protected]
|
||||||
|
* Copyright 2004-2005, Axel Dörfler, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||||
|
* Distributed under the terms of the NewOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
#include <arch/x86/arch_acpi.h>
|
||||||
|
#include <boot/stage2.h>
|
||||||
|
#include <boot/platform.h>
|
||||||
|
#include <boot/stdio.h>
|
||||||
|
|
||||||
|
#include "efi_platform.h"
|
||||||
|
#include "acpi.h"
|
||||||
|
#include "mmu.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define TRACE_ACPI
|
||||||
|
#ifdef TRACE_ACPI
|
||||||
|
# define TRACE(x) dprintf x
|
||||||
|
#else
|
||||||
|
# define TRACE(x) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static acpi_descriptor_header* sAcpiRsdt; // System Description Table
|
||||||
|
static acpi_descriptor_header* sAcpiXsdt; // Extended System Description Table
|
||||||
|
static int32 sNumEntries = -1;
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" addr_t
|
||||||
|
mmu_map_physical_memory(addr_t physicalAddress, size_t size, uint32 flags)
|
||||||
|
{
|
||||||
|
return physicalAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void
|
||||||
|
mmu_free(void *virtualAddress, size_t size)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
acpi_validate_rsdp(acpi_rsdp* rsdp)
|
||||||
|
{
|
||||||
|
const char* data = (const char*)rsdp;
|
||||||
|
unsigned char checksum = 0;
|
||||||
|
for (uint32 i = 0; i < sizeof(acpi_rsdp_legacy); i++)
|
||||||
|
checksum += data[i];
|
||||||
|
|
||||||
|
if ((checksum & 0xff) != 0) {
|
||||||
|
TRACE(("acpi: rsdp failed basic checksum\n"));
|
||||||
|
return B_BAD_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for ACPI 2.0+ we need to also validate the extended checksum
|
||||||
|
if (rsdp->revision > 0) {
|
||||||
|
for (uint32 i = sizeof(acpi_rsdp_legacy);
|
||||||
|
i < sizeof(acpi_rsdp_extended); i++) {
|
||||||
|
checksum += data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((checksum & 0xff) != 0) {
|
||||||
|
TRACE(("acpi: rsdp failed extended checksum\n"));
|
||||||
|
return B_BAD_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
acpi_validate_rsdt(acpi_descriptor_header* rsdt)
|
||||||
|
{
|
||||||
|
const char* data = (const char*)rsdt;
|
||||||
|
unsigned char checksum = 0;
|
||||||
|
for (uint32 i = 0; i < rsdt->length; i++)
|
||||||
|
checksum += data[i];
|
||||||
|
|
||||||
|
return checksum == 0 ? B_OK : B_BAD_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
acpi_check_rsdt(acpi_rsdp* rsdp)
|
||||||
|
{
|
||||||
|
if (acpi_validate_rsdp(rsdp) != B_OK)
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
|
bool usingXsdt = false;
|
||||||
|
|
||||||
|
TRACE(("acpi: found rsdp at %p oem id: %.6s, rev %d\n",
|
||||||
|
rsdp, rsdp->oem_id, rsdp->revision));
|
||||||
|
TRACE(("acpi: rsdp points to rsdt at 0x%x\n", rsdp->rsdt_address));
|
||||||
|
|
||||||
|
uint32 length = 0;
|
||||||
|
acpi_descriptor_header* rsdt = NULL;
|
||||||
|
if (rsdp->revision > 0) {
|
||||||
|
length = rsdp->xsdt_length;
|
||||||
|
rsdt = (acpi_descriptor_header*)mmu_map_physical_memory(
|
||||||
|
(uint32)rsdp->xsdt_address, rsdp->xsdt_length, kDefaultPageFlags);
|
||||||
|
if (rsdt != NULL
|
||||||
|
&& strncmp(rsdt->signature, ACPI_XSDT_SIGNATURE, 4) != 0) {
|
||||||
|
mmu_free(rsdt, rsdp->xsdt_length);
|
||||||
|
rsdt = NULL;
|
||||||
|
TRACE(("acpi: invalid extended system description table\n"));
|
||||||
|
} else
|
||||||
|
usingXsdt = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're ACPI v1 or we fail to map the XSDT for some reason,
|
||||||
|
// attempt to use the RSDT instead.
|
||||||
|
if (rsdt == NULL) {
|
||||||
|
// map and validate the root system description table
|
||||||
|
rsdt = (acpi_descriptor_header*)mmu_map_physical_memory(
|
||||||
|
rsdp->rsdt_address, sizeof(acpi_descriptor_header),
|
||||||
|
kDefaultPageFlags);
|
||||||
|
if (rsdt == NULL) {
|
||||||
|
TRACE(("acpi: couldn't map rsdt header\n"));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
if (strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 0) {
|
||||||
|
mmu_free(rsdt, sizeof(acpi_descriptor_header));
|
||||||
|
rsdt = NULL;
|
||||||
|
TRACE(("acpi: invalid root system description table\n"));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = rsdt->length;
|
||||||
|
// Map the whole table, not just the header
|
||||||
|
TRACE(("acpi: rsdt length: %u\n", length));
|
||||||
|
mmu_free(rsdt, sizeof(acpi_descriptor_header));
|
||||||
|
rsdt = (acpi_descriptor_header*)mmu_map_physical_memory(
|
||||||
|
rsdp->rsdt_address, length, kDefaultPageFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rsdt != NULL) {
|
||||||
|
if (acpi_validate_rsdt(rsdt) != B_OK) {
|
||||||
|
TRACE(("acpi: rsdt failed checksum validation\n"));
|
||||||
|
mmu_free(rsdt, length);
|
||||||
|
return B_ERROR;
|
||||||
|
} else {
|
||||||
|
if (usingXsdt)
|
||||||
|
sAcpiXsdt = rsdt;
|
||||||
|
else
|
||||||
|
sAcpiRsdt = rsdt;
|
||||||
|
TRACE(("acpi: found valid %s at %p\n",
|
||||||
|
usingXsdt ? ACPI_XSDT_SIGNATURE : ACPI_RSDT_SIGNATURE,
|
||||||
|
rsdt));
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename PointerType>
|
||||||
|
acpi_descriptor_header*
|
||||||
|
acpi_find_table_generic(const char* signature, acpi_descriptor_header* acpiSdt)
|
||||||
|
{
|
||||||
|
if (acpiSdt == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (sNumEntries == -1) {
|
||||||
|
// if using the xsdt, our entries are 64 bits wide.
|
||||||
|
sNumEntries = (acpiSdt->length
|
||||||
|
- sizeof(acpi_descriptor_header))
|
||||||
|
/ sizeof(PointerType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sNumEntries <= 0) {
|
||||||
|
TRACE(("acpi: root system description table is empty\n"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE(("acpi: searching %d entries for table '%.4s'\n", sNumEntries,
|
||||||
|
signature));
|
||||||
|
|
||||||
|
PointerType* pointer = (PointerType*)((uint8*)acpiSdt
|
||||||
|
+ sizeof(acpi_descriptor_header));
|
||||||
|
|
||||||
|
acpi_descriptor_header* header = NULL;
|
||||||
|
for (int32 j = 0; j < sNumEntries; j++, pointer++) {
|
||||||
|
header = (acpi_descriptor_header*)
|
||||||
|
mmu_map_physical_memory((uint32)*pointer,
|
||||||
|
sizeof(acpi_descriptor_header), kDefaultPageFlags);
|
||||||
|
|
||||||
|
if (header == NULL
|
||||||
|
|| strncmp(header->signature, signature, 4) != 0) {
|
||||||
|
// not interesting for us
|
||||||
|
TRACE(("acpi: Looking for '%.4s'. Skipping '%.4s'\n",
|
||||||
|
signature, header != NULL ? header->signature : "null"));
|
||||||
|
|
||||||
|
if (header != NULL) {
|
||||||
|
mmu_free(header, sizeof(acpi_descriptor_header));
|
||||||
|
header = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE(("acpi: Found '%.4s' @ %p\n", signature, pointer));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (header == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Map the whole table, not just the header
|
||||||
|
uint32 length = header->length;
|
||||||
|
mmu_free(header, sizeof(acpi_descriptor_header));
|
||||||
|
|
||||||
|
return (acpi_descriptor_header*)mmu_map_physical_memory(
|
||||||
|
(uint32)*pointer, length, kDefaultPageFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
acpi_descriptor_header*
|
||||||
|
acpi_find_table(const char* signature)
|
||||||
|
{
|
||||||
|
if (sAcpiRsdt != NULL)
|
||||||
|
return acpi_find_table_generic<uint32>(signature, sAcpiRsdt);
|
||||||
|
else if (sAcpiXsdt != NULL)
|
||||||
|
return acpi_find_table_generic<uint64>(signature, sAcpiXsdt);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
acpi_init()
|
||||||
|
{
|
||||||
|
EFI_GUID acpi = ACPI_20_TABLE_GUID;
|
||||||
|
EFI_CONFIGURATION_TABLE *table = kSystemTable->ConfigurationTable;
|
||||||
|
UINTN entries = kSystemTable->NumberOfTableEntries;
|
||||||
|
|
||||||
|
// Try to find the ACPI RSDP.
|
||||||
|
for (uint32 i = 0; i < entries; i++) {
|
||||||
|
acpi_rsdp *rsdp = NULL;
|
||||||
|
|
||||||
|
EFI_GUID vendor = table[i].VendorGuid;
|
||||||
|
|
||||||
|
if (vendor.Data1 == acpi.Data1
|
||||||
|
&& vendor.Data2 == acpi.Data2
|
||||||
|
&& vendor.Data3 == acpi.Data3
|
||||||
|
&& strncmp((char *)vendor.Data4, (char *)acpi.Data4, 8) == 0) {
|
||||||
|
rsdp = (acpi_rsdp *)(table[i].VendorTable);
|
||||||
|
if (strncmp((char *)rsdp, ACPI_RSDP_SIGNATURE, 8) == 0)
|
||||||
|
TRACE(("acpi_init: found ACPI RSDP signature at %p\n", rsdp));
|
||||||
|
|
||||||
|
if (rsdp != NULL && acpi_check_rsdt(rsdp) == B_OK) {
|
||||||
|
gKernelArgs.arch_args.acpi_root = rsdp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef ACPI_H
|
||||||
|
#define ACPI_H
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
#include <arch/x86/arch_acpi.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
acpi_descriptor_header *acpi_find_table(const char *signature);
|
||||||
|
void acpi_init(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ACPI_H */
|
||||||
@@ -13,11 +13,13 @@
|
|||||||
|
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
#include <arch/x86/descriptors.h>
|
#include <arch/x86/descriptors.h>
|
||||||
|
#include <boot/kernel_args.h>
|
||||||
#include <boot/platform.h>
|
#include <boot/platform.h>
|
||||||
#include <boot/stage2.h>
|
#include <boot/stage2.h>
|
||||||
#include <boot/stdio.h>
|
#include <boot/stdio.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
|
|
||||||
|
#include "acpi.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "efi_platform.h"
|
#include "efi_platform.h"
|
||||||
#include "mmu.h"
|
#include "mmu.h"
|
||||||
@@ -270,6 +272,9 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable)
|
|||||||
|
|
||||||
// disable apm in case we ever load a 32-bit kernel...
|
// disable apm in case we ever load a 32-bit kernel...
|
||||||
gKernelArgs.platform_args.apm.version = 0;
|
gKernelArgs.platform_args.apm.version = 0;
|
||||||
|
|
||||||
|
acpi_init();
|
||||||
|
|
||||||
gKernelArgs.num_cpus = 1;
|
gKernelArgs.num_cpus = 1;
|
||||||
gKernelArgs.arch_args.hpet_phys = 0;
|
gKernelArgs.arch_args.hpet_phys = 0;
|
||||||
gKernelArgs.arch_args.hpet = NULL;
|
gKernelArgs.arch_args.hpet = NULL;
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include <arch/platform.h>
|
#include <arch/platform.h>
|
||||||
#include <apm.h>
|
#include <apm.h>
|
||||||
|
#include <boot_item.h>
|
||||||
|
#include <boot/stage2.h>
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
@@ -22,6 +24,10 @@ arch_platform_init(struct kernel_args *args)
|
|||||||
status_t
|
status_t
|
||||||
arch_platform_init_post_vm(struct kernel_args *args)
|
arch_platform_init_post_vm(struct kernel_args *args)
|
||||||
{
|
{
|
||||||
|
// Now we can add boot items; pass on the ACPI root pointer
|
||||||
|
add_boot_item("ACPI_ROOT_POINTER",
|
||||||
|
args->arch_args.acpi_root.Pointer(), sizeof(void*));
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user