blob: 0c2d250b6969312a93aef1ce9eb7bfdb48c4f20d [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <assert.h>
#include <debug.h>
#include <err.h>
#include <stdio.h>
#include <trace.h>
#include <vm/vm_aspace.h>
#include <zircon/types.h>
#if ARCH_X86
#include <platform/pc/bootloader.h>
#else
#error "Unsupported architecture"
#endif
#include "acpi.h"
#define _COMPONENT ACPI_OS_SERVICES
ACPI_MODULE_NAME ("oszircon")
#define LOCAL_TRACE 0
/**
* @brief Initialize the OSL subsystem.
*
* This function allows the OSL to initialize itself. It is called during
* intiialization of the ACPICA subsystem.
*
* @return Initialization status
*/
ACPI_STATUS AcpiOsInitialize() {
return AE_OK;
}
/**
* @brief Terminate the OSL subsystem.
*
* This function allows the OSL to cleanup and terminate. It is called during
* termination of the ACPICA subsystem.
*
* @return Termination status
*/
ACPI_STATUS AcpiOsTerminate() {
return AE_OK;
}
/**
* @brief Obtain the Root ACPI table pointer (RSDP).
*
* @return The physical address of the RSDP
*/
ACPI_PHYSICAL_ADDRESS AcpiOsGetRootPointer() {
if (bootloader.acpi_rsdp) {
return bootloader.acpi_rsdp;
} else {
ACPI_PHYSICAL_ADDRESS TableAddress = 0;
ACPI_STATUS status = AcpiFindRootPointer(&TableAddress);
if (status != AE_OK) {
return 0;
}
return TableAddress;
}
}
/**
* @brief Allow the host OS to override a predefined ACPI object.
*
* @param PredefinedObject A pointer to a predefind object (name and initial
* value)
* @param NewValue Where a new value for the predefined object is returned.
* NULL if there is no override for this object.
*
* @return Exception code that indicates success or reason for failure.
*/
ACPI_STATUS AcpiOsPredefinedOverride(
const ACPI_PREDEFINED_NAMES *PredefinedObject,
ACPI_STRING *NewValue) {
*NewValue = NULL;
return AE_OK;
}
/**
* @brief Allow the host OS to override a firmware ACPI table via a logical
* address.
*
* @param ExistingTable A pointer to the header of the existing ACPI table
* @param NewTable Where the pointer to the replacment table is returned. The
* OSL returns NULL if no replacement is provided.
*
* @return Exception code that indicates success or reason for failure.
*/
ACPI_STATUS AcpiOsTableOverride(
ACPI_TABLE_HEADER *ExistingTable,
ACPI_TABLE_HEADER **NewTable) {
*NewTable = NULL;
return AE_OK;
}
/**
* @brief Allow the host OS to override a firmware ACPI table via a physical
* address.
*
* @param ExistingTable A pointer to the header of the existing ACPI table
* @param NewAddress Where the physical address of the replacment table is
* returned. The OSL returns NULL if no replacement is provided.
* @param NewLength Where the length of the replacement table is returned.
*
* @return Exception code that indicates success or reason for failure.
*/
ACPI_STATUS AcpiOsPhysicalTableOverride(
ACPI_TABLE_HEADER *ExistingTable,
ACPI_PHYSICAL_ADDRESS *NewAddress,
UINT32 *NewTableLength) {
*NewAddress = 0;
return AE_OK;
}
/**
* @brief Map physical memory into the caller's address space.
*
* @param PhysicalAddress A full physical address of the memory to be mapped
* into the caller's address space
* @param Length The amount of memory to mapped starting at the given physical
* address
*
* @return Logical pointer to the mapped memory. A NULL pointer indicated failures.
*/
void *AcpiOsMapMemory(
ACPI_PHYSICAL_ADDRESS PhysicalAddress,
ACPI_SIZE Length) {
// Caution: PhysicalAddress might not be page-aligned, Length might not
// be a page multiple.
ACPI_PHYSICAL_ADDRESS aligned_address = ROUNDDOWN(PhysicalAddress, PAGE_SIZE);
ACPI_PHYSICAL_ADDRESS end = ROUNDUP(PhysicalAddress + Length, PAGE_SIZE);
void *vaddr = NULL;
zx_status_t status = VmAspace::kernel_aspace()->AllocPhysical(
"acpi_mapping",
end - aligned_address,
&vaddr,
PAGE_SIZE_SHIFT,
aligned_address,
0,
ARCH_MMU_FLAG_PERM_READ | ARCH_MMU_FLAG_PERM_WRITE);
if (status != ZX_OK) {
return NULL;
}
const uintptr_t real_addr =
reinterpret_cast<uintptr_t>(vaddr) + (PhysicalAddress - aligned_address);
return reinterpret_cast<void*>(real_addr);
}
/**
* @brief Remove a physical to logical memory mapping.
*
* @param LogicalAddress The logical address that was returned from a previous
* call to AcpiOsMapMemory.
* @param Length The amount of memory that was mapped. This value must be
* identical to the value used in the call to AcpiOsMapMemory.
*/
void AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Length) {
zx_status_t status = VmAspace::kernel_aspace()->FreeRegion(
reinterpret_cast<vaddr_t>(LogicalAddress));
if (status != ZX_OK) {
TRACEF("WARNING: ACPI failed to free region %p, size %" PRIu64 "\n",
LogicalAddress, (uint64_t)Length);
}
}
/**
* @brief Read a value from a memory location.
*
* @param Address Memory address to be read.
* @param Value A pointer to a location where the data is to be returned.
* @param Width The memory width in bits, either 8, 16, 32, or 64.
*
* @return Exception code that indicates success or reason for failure.
*/
ACPI_STATUS AcpiOsReadMemory(
ACPI_PHYSICAL_ADDRESS Address,
UINT64 *Value,
UINT32 Width) {
PANIC_UNIMPLEMENTED;
}
/**
* @brief Write a value to a memory location.
*
* @param Address Memory address where data is to be written.
* @param Value Data to be written to the memory location.
* @param Width The memory width in bits, either 8, 16, 32, or 64.
*
* @return Exception code that indicates success or reason for failure.
*/
ACPI_STATUS AcpiOsWriteMemory(
ACPI_PHYSICAL_ADDRESS Address,
UINT64 Value,
UINT32 Width) {
PANIC_UNIMPLEMENTED;
}
/**
* @brief Wait for a short amount of time (fine granularity).
*
* Execution of the running thread is not suspended for this time.
*
* @param Microseconds The amount of time to delay, in microseconds.
*/
void AcpiOsStall(UINT32 Microseconds) {
spin(Microseconds);
}
/**
* @brief Read a value from an input port.
*
* @param Address Hardware I/O port address to be read.
* @param Value A pointer to a location where the data is to be returned.
* @param Width The port width in bits, either 8, 16, or 32.
*
* @return Exception code that indicates success or reason for failure.
*/
ACPI_STATUS AcpiOsReadPort(
ACPI_IO_ADDRESS Address,
UINT32 *Value,
UINT32 Width) {
if (Address > 0xffff) {
return AE_BAD_PARAMETER;
}
switch (Width) {
case 8:
*Value = inp((uint16_t)Address);
break;
case 16:
*Value = inpw((uint16_t)Address);
break;
case 32:
*Value = inpd((uint16_t)Address);
break;
default:
return AE_BAD_PARAMETER;
}
return AE_OK;
}
/**
* @brief Write a value to an output port.
*
* @param Address Hardware I/O port address where data is to be written.
* @param Value The value to be written.
* @param Width The port width in bits, either 8, 16, or 32.
*
* @return Exception code that indicates success or reason for failure.
*/
ACPI_STATUS AcpiOsWritePort(
ACPI_IO_ADDRESS Address,
UINT32 Value,
UINT32 Width) {
if (Address > 0xffff) {
return AE_BAD_PARAMETER;
}
switch (Width) {
case 8:
outp((uint16_t)Address, (uint8_t)Value);
break;
case 16:
outpw((uint16_t)Address, (uint16_t)Value);
break;
case 32:
outpd((uint16_t)Address, (uint32_t)Value);
break;
default:
return AE_BAD_PARAMETER;
}
return AE_OK;
}
/**
* @brief Allocate memory from the dynamic memory pool.
*
* @param Size Amount of memory to allocate.
*
* @return A pointer to the allocated memory. A NULL pointer is returned on
* error.
*/
void *AcpiOsAllocate(ACPI_SIZE Size) {
return malloc(Size);
}
/**
* @brief Free previously allocated memory.
*
* @param Memory A pointer to the memory to be freed.
*/
void AcpiOsFree(void *Memory) {
free(Memory);
}
/**
* @brief Formatted stream output.
*
* @param Format A standard print format string.
* @param ...
*/
void ACPI_INTERNAL_VAR_XFACE AcpiOsPrintf(const char *Format, ...) {
va_list argp;
va_start(argp, Format);
AcpiOsVprintf(Format, argp);
va_end(argp);
}
/**
* @brief Formatted stream output.
*
* @param Format A standard print format string.
* @param Args A variable parameter list
*/
void AcpiOsVprintf(const char *Format, va_list Args) {
}