Changes to support Fuchsia
Adds support for a GN build and imports some changes from previous
ACPICA port to support Fuchsia. This library does not support
building for the kernel.
Change-Id: Iba9914c7b11534a429c35b52560213725afca148
diff --git a/BUILD.gn b/BUILD.gn
new file mode 100644
index 0000000..b4eb81a
--- /dev/null
+++ b/BUILD.gn
@@ -0,0 +1,248 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("$zx_build/public/gn/config/globals.gni")
+
+declare_args() {
+ # Enable debug output in the ACPI library (used by the ACPI bus driver).
+ acpica_debug_output = false
+}
+
+group("headers") {
+ public_configs = [
+ ":headers.config",
+ ":disable_warnings",
+ ]
+}
+
+config("headers.config") {
+ visibility = [ ":headers" ]
+ include_dirs = [ "include" ]
+
+ # UBSan warns on a few instances of misaligned loads. Define this macro to
+ # perform byte-by-byte accesses.
+ defines = [ "ACPI_MISALIGNMENT_NOT_SUPPORTED" ]
+}
+
+# Disable warnings we won't fix in third-party code. Putting this in a
+# separate config rather than directly in the target gets these flags
+# correctly ordered after the $zx/public/gn/config:default_warnings flags.
+config("disable_warnings") {
+ visibility = [ ":*" ]
+
+ cflags = [
+ "-Wno-implicit-fallthrough",
+ "-Wno-incompatible-pointer-types-discards-qualifiers",
+ "-Wno-null-pointer-arithmetic",
+ ]
+}
+
+static_library("acpica") {
+ public_deps = [ ":headers" ]
+
+ # Local sources use #include "acpi.h", not #include <acpica/acpi.h>.
+ include_dirs = [ "source/include" ]
+
+ configs += [ ":disable_warnings" ]
+
+ # We need to specify -fno-strict-aliasing, since ACPICA has a habit of
+ # violating strict aliasing rules in some of its macros. Rewriting this
+ # code would increase the maintenance cost of bringing in the latest
+ # upstream ACPICA, so instead we mitigate the problem with a compile-time
+ # flag. We take the more conservative approach of disabling
+ # strict-aliasing-based optimizations, rather than disabling warnings.
+ cflags = [ "-fno-strict-aliasing" ]
+
+ sources = [
+ "$zx/system/ulib/acpica/osfuchsia.cc",
+ "source/common/ahids.c",
+ "source/common/ahpredef.c",
+ "source/common/ahtable.c",
+ "source/common/dmtbdump.c",
+ "source/common/dmtbdump1.c",
+ "source/common/dmtbdump2.c",
+ "source/common/dmtbdump3.c",
+ "source/common/dmtbinfo.c",
+ "source/common/dmtbinfo1.c",
+ "source/common/dmtbinfo2.c",
+ "source/common/dmtbinfo3.c",
+ "source/components/dispatcher/dsargs.c",
+ "source/components/dispatcher/dscontrol.c",
+ "source/components/dispatcher/dsdebug.c",
+ "source/components/dispatcher/dsfield.c",
+ "source/components/dispatcher/dsinit.c",
+ "source/components/dispatcher/dsmethod.c",
+ "source/components/dispatcher/dsmthdat.c",
+ "source/components/dispatcher/dsobject.c",
+ "source/components/dispatcher/dsopcode.c",
+ "source/components/dispatcher/dspkginit.c",
+ "source/components/dispatcher/dsutils.c",
+ "source/components/dispatcher/dswexec.c",
+ "source/components/dispatcher/dswload.c",
+ "source/components/dispatcher/dswload2.c",
+ "source/components/dispatcher/dswscope.c",
+ "source/components/dispatcher/dswstate.c",
+ "source/components/events/evevent.c",
+ "source/components/events/evglock.c",
+ "source/components/events/evgpe.c",
+ "source/components/events/evgpeblk.c",
+ "source/components/events/evgpeinit.c",
+ "source/components/events/evgpeutil.c",
+ "source/components/events/evhandler.c",
+ "source/components/events/evmisc.c",
+ "source/components/events/evregion.c",
+ "source/components/events/evrgnini.c",
+ "source/components/events/evsci.c",
+ "source/components/events/evxface.c",
+ "source/components/events/evxfevnt.c",
+ "source/components/events/evxfgpe.c",
+ "source/components/events/evxfregn.c",
+ "source/components/executer/exconcat.c",
+ "source/components/executer/exconfig.c",
+ "source/components/executer/exconvrt.c",
+ "source/components/executer/excreate.c",
+ "source/components/executer/exdebug.c",
+ "source/components/executer/exdump.c",
+ "source/components/executer/exfield.c",
+ "source/components/executer/exfldio.c",
+ "source/components/executer/exmisc.c",
+ "source/components/executer/exmutex.c",
+ "source/components/executer/exnames.c",
+ "source/components/executer/exoparg1.c",
+ "source/components/executer/exoparg2.c",
+ "source/components/executer/exoparg3.c",
+ "source/components/executer/exoparg6.c",
+ "source/components/executer/exprep.c",
+ "source/components/executer/exregion.c",
+ "source/components/executer/exresnte.c",
+ "source/components/executer/exresolv.c",
+ "source/components/executer/exresop.c",
+ "source/components/executer/exserial.c",
+ "source/components/executer/exstore.c",
+ "source/components/executer/exstoren.c",
+ "source/components/executer/exstorob.c",
+ "source/components/executer/exsystem.c",
+ "source/components/executer/extrace.c",
+ "source/components/executer/exutils.c",
+ "source/components/hardware/hwacpi.c",
+ "source/components/hardware/hwesleep.c",
+ "source/components/hardware/hwgpe.c",
+ "source/components/hardware/hwpci.c",
+ "source/components/hardware/hwregs.c",
+ "source/components/hardware/hwsleep.c",
+ "source/components/hardware/hwtimer.c",
+ "source/components/hardware/hwvalid.c",
+ "source/components/hardware/hwxface.c",
+ "source/components/hardware/hwxfsleep.c",
+ "source/components/namespace/nsaccess.c",
+ "source/components/namespace/nsalloc.c",
+ "source/components/namespace/nsarguments.c",
+ "source/components/namespace/nsconvert.c",
+ "source/components/namespace/nsdump.c",
+ "source/components/namespace/nsdumpdv.c",
+ "source/components/namespace/nseval.c",
+ "source/components/namespace/nsinit.c",
+ "source/components/namespace/nsload.c",
+ "source/components/namespace/nsnames.c",
+ "source/components/namespace/nsobject.c",
+ "source/components/namespace/nsparse.c",
+ "source/components/namespace/nspredef.c",
+ "source/components/namespace/nsprepkg.c",
+ "source/components/namespace/nsrepair.c",
+ "source/components/namespace/nsrepair2.c",
+ "source/components/namespace/nssearch.c",
+ "source/components/namespace/nsutils.c",
+ "source/components/namespace/nswalk.c",
+ "source/components/namespace/nsxfeval.c",
+ "source/components/namespace/nsxfname.c",
+ "source/components/namespace/nsxfobj.c",
+ "source/components/parser/psargs.c",
+ "source/components/parser/psloop.c",
+ "source/components/parser/psobject.c",
+ "source/components/parser/psopcode.c",
+ "source/components/parser/psopinfo.c",
+ "source/components/parser/psparse.c",
+ "source/components/parser/psscope.c",
+ "source/components/parser/pstree.c",
+ "source/components/parser/psutils.c",
+ "source/components/parser/pswalk.c",
+ "source/components/parser/psxface.c",
+ "source/components/resources/rsaddr.c",
+ "source/components/resources/rscalc.c",
+ "source/components/resources/rscreate.c",
+ "source/components/resources/rsdumpinfo.c",
+ "source/components/resources/rsinfo.c",
+ "source/components/resources/rsio.c",
+ "source/components/resources/rsirq.c",
+ "source/components/resources/rslist.c",
+ "source/components/resources/rsmemory.c",
+ "source/components/resources/rsmisc.c",
+ "source/components/resources/rsserial.c",
+ "source/components/resources/rsutils.c",
+ "source/components/resources/rsxface.c",
+ "source/components/tables/tbdata.c",
+ "source/components/tables/tbfadt.c",
+ "source/components/tables/tbfind.c",
+ "source/components/tables/tbinstal.c",
+ "source/components/tables/tbprint.c",
+ "source/components/tables/tbutils.c",
+ "source/components/tables/tbxface.c",
+ "source/components/tables/tbxfload.c",
+ "source/components/tables/tbxfroot.c",
+ "source/components/utilities/utaddress.c",
+ "source/components/utilities/utalloc.c",
+ "source/components/utilities/utascii.c",
+ "source/components/utilities/utbuffer.c",
+ "source/components/utilities/utcache.c",
+ "source/components/utilities/utclib.c",
+ "source/components/utilities/utcopy.c",
+ "source/components/utilities/utdebug.c",
+ "source/components/utilities/utdecode.c",
+ "source/components/utilities/utdelete.c",
+ "source/components/utilities/uterror.c",
+ "source/components/utilities/uteval.c",
+ "source/components/utilities/utexcep.c",
+ "source/components/utilities/utglobal.c",
+ "source/components/utilities/uthex.c",
+ "source/components/utilities/utids.c",
+ "source/components/utilities/utinit.c",
+ "source/components/utilities/utlock.c",
+ "source/components/utilities/utmath.c",
+ "source/components/utilities/utmisc.c",
+ "source/components/utilities/utmutex.c",
+ "source/components/utilities/utnonansi.c",
+ "source/components/utilities/utobject.c",
+ "source/components/utilities/utosi.c",
+ "source/components/utilities/utownerid.c",
+ "source/components/utilities/utpredef.c",
+ "source/components/utilities/utresdecode.c",
+ "source/components/utilities/utresrc.c",
+ "source/components/utilities/utstate.c",
+ "source/components/utilities/utstring.c",
+ "source/components/utilities/utstrsuppt.c",
+ "source/components/utilities/utstrtoul64.c",
+ "source/components/utilities/uttrack.c",
+ "source/components/utilities/utuuid.c",
+ "source/components/utilities/utxface.c",
+ "source/components/utilities/utxferror.c",
+ "source/components/utilities/utxfinit.c",
+ "source/components/utilities/utxfmutex.c",
+ ]
+ deps = [
+ "//zircon/public/lib/ddk",
+ "//zircon/public/lib/fbl",
+ "//zircon/public/lib/pci",
+ "//zircon/public/lib/zircon-internal",
+ ]
+ defines = [ "_ALL_SOURCE" ]
+ if (acpica_debug_output) {
+ defines += [ "ACPI_DEBUG_OUTPUT" ]
+ }
+
+ # TODO(41663): UBSan has found an instance of undefined behavior in this target.
+ # Disable UBSan for this target temporarily until it is migrated into CI/CQ.
+ if (!is_gcc) {
+ cflags += [ "-fno-sanitize=undefined" ]
+ }
+}
diff --git a/README.fuchsia b/README.fuchsia
index 8494a16..3527f99 100644
--- a/README.fuchsia
+++ b/README.fuchsia
@@ -6,3 +6,13 @@
- Added README.fuchsia
- Removed optional GPL license banner from sources
- Added LICENSE containing copy of source license banner
+- Added BUILD.gn
+- Added symlink to wrap source/include as include/acpica
+- Added source/include/platform/acfuchsia.h
+- Modified source/include/platform/acenv.h to use aczircon.h/acfuchsia.h
+- Wrapped source/include/acpica/acpi.h with __BEGIN_CDECLS/__END_CDECLS
+- Modified AcpiHwLegacySleep to extract out a subfunction AcpiHwLegacySleepFinal (needed
+ for Zircon suspend-to-RAM support).
+- Fix instances of undefined behavior reported by UBSan (misaligned pointer
+ accesses, member accesses on nullptrs, and left shifting by 31 on ints)
+- Added workaround for use-after-free on NuC in AcpiNsTerminate
diff --git a/include/acpica b/include/acpica
new file mode 120000
index 0000000..c492e01
--- /dev/null
+++ b/include/acpica
@@ -0,0 +1 @@
+../source/include/
\ No newline at end of file
diff --git a/source/components/hardware/hwsleep.c b/source/components/hardware/hwsleep.c
index d96b57d..b3e7097 100644
--- a/source/components/hardware/hwsleep.c
+++ b/source/components/hardware/hwsleep.c
@@ -41,6 +41,8 @@
#include "acpi.h"
#include "accommon.h"
+#include <zircon/syscalls/system.h>
+
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME ("hwsleep")
@@ -65,9 +67,6 @@
{
ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo;
ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo;
- UINT32 Pm1aControl;
- UINT32 Pm1bControl;
- UINT32 InValue;
ACPI_STATUS Status;
@@ -108,6 +107,53 @@
return_ACPI_STATUS (Status);
}
+ /* The upstream ACPICA code expects that AcpiHwLegacySleep() is invoked with interrupts
+ /* disabled. It requires this because the last steps of going to sleep is writing to a few
+ /* registers, flushing the caches (so we don't lose data if the caches are dropped), and then
+ /* writing to a register to enter the sleep. If we were to take an interrupt after the cache
+ /* flush but before entering sleep, we could have inconsistent memory after waking up.*/
+
+ /* In Fuchsia, ACPICA runs in usermode and we don't expose a mechanism for it to disable
+ /* interrupts. To ensure a consistent sleep, we split AcpiHwLegacySleep into two parts, the
+ /* part that doesn't need interrupts disabled, and then the final part (AcpiHwLegacySleepFinal)
+ /* that does. We execute the first half in usermode, and then make a syscall into the kernel to
+ /* execute the final steps. */
+
+#if defined(__Fuchsia__) && !defined(_KERNEL)
+ extern zx_handle_t get_root_resource(void);
+
+ zx_system_powerctl_arg_t arg;
+ arg.acpi_transition_s_state.target_s_state = SleepState;
+ arg.acpi_transition_s_state.sleep_type_a = AcpiGbl_SleepTypeA;
+ arg.acpi_transition_s_state.sleep_type_b = AcpiGbl_SleepTypeB;
+ zx_status_t zx_status = zx_system_powerctl(get_root_resource(),
+ ZX_SYSTEM_POWERCTL_ACPI_TRANSITION_S_STATE,
+ &arg);
+ if (zx_status == ZX_OK) {
+ Status = AE_OK;
+ } else {
+ Status = AE_ERROR;
+ }
+#else
+ Status = AcpiHwLegacySleepFinal(SleepState, AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB);
+#endif
+ return_ACPI_STATUS (Status);
+}
+
+ACPI_STATUS
+AcpiHwLegacySleepFinal(UINT8 SleepState, UINT8 SleepTypeA, UINT8 SleepTypeB) {
+ ACPI_STATUS Status;
+ UINT32 Pm1aControl;
+ UINT32 Pm1bControl;
+ UINT32 InValue;
+ ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo;
+ ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo;
+
+ ACPI_FUNCTION_TRACE (HwLegacySleepFinal);
+
+ SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE);
+ SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE);
+
/* Get current value of PM1A control */
Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL,
diff --git a/source/components/namespace/nsutils.c b/source/components/namespace/nsutils.c
index 8c2b7b8..51004de 100644
--- a/source/components/namespace/nsutils.c
+++ b/source/components/namespace/nsutils.c
@@ -694,6 +694,46 @@
ACPI_FUNCTION_TRACE (NsTerminate);
+ {
+ /* Prior to deleting the entire namespace we want to manually check for and delete some top
+ * level nodes. On some NuC devices, these nodes are mistakenly placed under the root,
+ * despite referencing regions in a different sub tree. This results in a use after free
+ * due to the sub tree being deleted before these root level objects.
+ * This is described in the github issue https://github.com/acpica/acpica/issues/416
+ * There is no correctness requirement to deleting the tree in any particular order,
+ * AcpiNsDeleteNamespaceSubtree is simply doing the most optimal traversal. Therefore if we
+ * are not on a NuC and manage to find these nodes there is no harm to performing this early
+ * deletion.
+ * TODO(32590)
+ */
+ const char *EarlyDeleteList[] = {
+ "\\CARN",
+ "\\CBDR",
+ "\\LTDR",
+ "\\FDDR",
+ "\\CALE",
+ "\\CBLE",
+ "\\LTLE",
+ "\\FDLE",
+ "\\GLLE",
+ "\\GHLE",
+ "\\KCLE",
+ "\\MCLE",
+ "\\C1LE",
+ "\\C2LE",
+ NULL,
+ };
+ int Index;
+ for (Index = 0; EarlyDeleteList[Index] != NULL; Index++) {
+ ACPI_NAMESPACE_NODE *Node;
+ Status = AcpiNsGetNode(AcpiGbl_RootNode, EarlyDeleteList[Index], ACPI_NS_NO_UPSEARCH, &Node);
+ if (Status == AE_OK) {
+ AcpiNsDeleteChildren(Node);
+ AcpiUtRemoveReference(Node->Object);
+ AcpiNsRemoveNode(Node);
+ }
+ }
+ }
/*
* Free the entire namespace -- all nodes and all objects
diff --git a/source/components/resources/rsaddr.c b/source/components/resources/rsaddr.c
index cc98a67..2f08732 100644
--- a/source/components/resources/rsaddr.c
+++ b/source/components/resources/rsaddr.c
@@ -324,8 +324,15 @@
/* Validate the Resource Type */
- if ((Aml->Address.ResourceType > 2) &&
- (Aml->Address.ResourceType < 0xC0))
+ // Copy the value using memcpy() to safely access a misaligned pointer.
+ // We explicitely cast to AML_RESOURCE_ADDRESS instead of using
+ // `&Aml->Address` because the latter still results in a misaligned access
+ // that UBSan catches. We can safely do this cast since AML_RESOURCE is a
+ // union.
+ UINT8 ResourceType;
+ memcpy(&ResourceType, &((AML_RESOURCE_ADDRESS *)Aml)->ResourceType,
+ sizeof(ResourceType));
+ if (ResourceType > 2 && ResourceType < 0xC0)
{
return (FALSE);
}
diff --git a/source/components/tables/tbutils.c b/source/components/tables/tbutils.c
index 39bf181..18fff11 100644
--- a/source/components/tables/tbutils.c
+++ b/source/components/tables/tbutils.c
@@ -224,8 +224,11 @@
* 32-bit platform, RSDT: Return 32-bit table entry
* 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
*/
- return ((ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST_PTR (
- UINT32, TableEntry)));
+ // Copy the value using memcpy() to safely handle a load on a misaligned
+ // pointer.
+ UINT32 result;
+ ACPI_MOVE_32_TO_32(&result, TableEntry);
+ return result;
}
else
{
diff --git a/source/include/achware.h b/source/include/achware.h
index 51186b7..1396c3a 100644
--- a/source/include/achware.h
+++ b/source/include/achware.h
@@ -113,6 +113,9 @@
UINT8 SleepState);
ACPI_STATUS
+AcpiHwLegacySleepFinal(UINT8 SleepState, UINT8 SleepTypeA, UINT8 SleepTypeB);
+
+ACPI_STATUS
AcpiHwLegacyWakePrep (
UINT8 SleepState);
diff --git a/source/include/acpi.h b/source/include/acpi.h
index 1418d13..dc025b8 100644
--- a/source/include/acpi.h
+++ b/source/include/acpi.h
@@ -50,6 +50,8 @@
* Note: The order of these include files is important.
*/
#include "platform/acenv.h" /* Environment-specific items */
+__BEGIN_CDECLS
+
#include "actypes.h" /* ACPICA data types and structures */
#include "platform/acenvex.h" /* Extra environment-specific items */
#include "acnames.h" /* Common ACPI names and strings */
@@ -59,5 +61,6 @@
#include "acrestyp.h" /* Resource Descriptor structs */
#include "acpiosxf.h" /* OSL interfaces (ACPICA-to-OS) */
#include "acpixf.h" /* ACPI core subsystem external interfaces */
+__END_CDECLS
#endif /* __ACPI_H__ */
diff --git a/source/include/actypes.h b/source/include/actypes.h
index 803fd47..a8f5c6b 100644
--- a/source/include/actypes.h
+++ b/source/include/actypes.h
@@ -547,7 +547,9 @@
#define ACPI_TO_POINTER(i) ACPI_CAST_PTR (void, (ACPI_SIZE) (i))
#define ACPI_TO_INTEGER(p) ACPI_PTR_DIFF (p, (void *) 0)
-#define ACPI_OFFSET(d, f) ACPI_PTR_DIFF (&(((d *) 0)->f), (void *) 0)
+// Use offsetof() to avoid taking the offset of a nullptr, which is undefined
+// behavior.
+#define ACPI_OFFSET(d, f) offsetof(d, f)
#define ACPI_PHYSADDR_TO_PTR(i) ACPI_TO_POINTER(i)
#define ACPI_PTR_TO_PHYSADDR(i) ACPI_TO_INTEGER(i)
diff --git a/source/include/platform/acenv.h b/source/include/platform/acenv.h
index a650736..ee737a6 100644
--- a/source/include/platform/acenv.h
+++ b/source/include/platform/acenv.h
@@ -238,6 +238,9 @@
#elif defined(__QNX__)
#include "acqnx.h"
+#elif defined(__Fuchsia__)
+#include "acfuchsia.h"
+
/*
* EFI applications can be built with -nostdlib, in this case, it must be
* included after including all other host environmental definitions, in
diff --git a/source/include/platform/acfuchsia.h b/source/include/platform/acfuchsia.h
new file mode 100644
index 0000000..6379cb3
--- /dev/null
+++ b/source/include/platform/acfuchsia.h
@@ -0,0 +1,64 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <stdbool.h>
+#include <threads.h>
+
+#include <zircon/assert.h>
+#include <zircon/syscalls.h>
+#include <semaphore.h>
+
+/*
+ * Settings described in section 7 of
+ * https://acpica.org/sites/acpica/files/acpica-reference_17.pdf
+ */
+
+
+#if __x86_64__
+#define ACPI_MACHINE_WIDTH 64
+#elif __x86__
+#define ACPI_MACHINE_WIDTH 32
+#define ACPI_USE_NATIVE_DIVIDE
+#else
+#error Unexpected architecture
+#endif
+
+extern zx_handle_t root_resource_handle;
+
+// Make this a no-op. The only codepath we use it for is ACPI poweroff, in
+// which case we don't care about the cache state.
+#define ACPI_FLUSH_CPU_CACHE()
+
+// Use the standard library headers
+#define ACPI_USE_STANDARD_HEADERS
+#define ACPI_USE_SYSTEM_CLIBRARY
+
+// Use the builtin cache implementation
+#define ACPI_USE_LOCAL_CACHE
+
+#define ACPI_MUTEX_TYPE ACPI_OSL_MUTEX
+
+// Specify the types Fuchsia uses for various common objects
+#define ACPI_CPU_FLAGS int
+#define ACPI_SPINLOCK mtx_t*
+#define ACPI_MUTEX mtx_t*
+#define ACPI_SEMAPHORE sem_t*
+
+// Borrowed from aclinuxex.h
+
+// Include the gcc header since we're compiling on gcc
+#include "acgcc.h"
+
+__BEGIN_CDECLS
+bool _acpica_acquire_global_lock(void *FacsPtr);
+bool _acpica_release_global_lock(void *FacsPtr);
+
+void acpica_enable_noncontested_mode(void);
+void acpica_disable_noncontested_mode(void);
+__END_CDECLS
+
+#define ACPI_ACQUIRE_GLOBAL_LOCK(FacsPtr, Acq) Acq = _acpica_acquire_global_lock(FacsPtr)
+#define ACPI_RELEASE_GLOBAL_LOCK(FacsPtr, Pnd) Pnd = _acpica_release_global_lock(FacsPtr)