--- /dev/null
+/** @file\r
+ Reset System lib using PSCI hypervisor or secure monitor calls\r
+\r
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
+ Copyright (c) 2013, ARM Ltd. All rights reserved.<BR>\r
+ Copyright (c) 2014-2020, Linaro Ltd. All rights reserved.<BR>\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <PiPei.h>\r
+\r
+#include <libfdt.h>\r
+#include <Library/ArmHvcLib.h>\r
+#include <Library/ArmSmcLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/ResetSystemLib.h>\r
+\r
+#include <IndustryStandard/ArmStdSmc.h>\r
+\r
+typedef enum {\r
+ PsciMethodUnknown,\r
+ PsciMethodSmc,\r
+ PsciMethodHvc,\r
+} PSCI_METHOD;\r
+\r
+STATIC\r
+PSCI_METHOD\r
+DiscoverPsciMethod (\r
+ VOID\r
+ )\r
+{\r
+ VOID *DeviceTreeBase;\r
+ INT32 Node, Prev;\r
+ INT32 Len;\r
+ CONST CHAR8 *Compatible;\r
+ CONST CHAR8 *CompatibleItem;\r
+ CONST VOID *Prop;\r
+\r
+ DeviceTreeBase = (VOID*)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress);\r
+ ASSERT (fdt_check_header (DeviceTreeBase) == 0);\r
+\r
+ //\r
+ // Enumerate all FDT nodes looking for the PSCI node and capture the method\r
+ //\r
+ for (Prev = 0;; Prev = Node) {\r
+ Node = fdt_next_node (DeviceTreeBase, Prev, NULL);\r
+ if (Node < 0) {\r
+ break;\r
+ }\r
+\r
+ Compatible = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);\r
+ if (Compatible == NULL) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Iterate over the NULL-separated items in the compatible string\r
+ //\r
+ for (CompatibleItem = Compatible; CompatibleItem < Compatible + Len;\r
+ CompatibleItem += 1 + AsciiStrLen (CompatibleItem)) {\r
+\r
+ if (AsciiStrCmp (CompatibleItem, "arm,psci-0.2") != 0) {\r
+ continue;\r
+ }\r
+\r
+ Prop = fdt_getprop (DeviceTreeBase, Node, "method", NULL);\r
+ if (!Prop) {\r
+ DEBUG ((DEBUG_ERROR, "%a: Missing PSCI method property\n",\r
+ __FUNCTION__));\r
+ return PsciMethodUnknown;\r
+ }\r
+\r
+ if (AsciiStrnCmp (Prop, "hvc", 3) == 0) {\r
+ return PsciMethodHvc;\r
+ } else if (AsciiStrnCmp (Prop, "smc", 3) == 0) {\r
+ return PsciMethodSmc;\r
+ } else {\r
+ DEBUG ((DEBUG_ERROR, "%a: Unknown PSCI method \"%a\"\n", __FUNCTION__,\r
+ Prop));\r
+ return PsciMethodUnknown;\r
+ }\r
+ }\r
+ }\r
+ return PsciMethodUnknown;\r
+}\r
+\r
+STATIC\r
+VOID\r
+PerformPsciAction (\r
+ IN UINTN Arg0\r
+ )\r
+{\r
+ ARM_SMC_ARGS ArmSmcArgs;\r
+ ARM_HVC_ARGS ArmHvcArgs;\r
+\r
+ ArmSmcArgs.Arg0 = Arg0;\r
+ ArmHvcArgs.Arg0 = Arg0;\r
+\r
+ switch (DiscoverPsciMethod ()) {\r
+ case PsciMethodHvc:\r
+ ArmCallHvc (&ArmHvcArgs);\r
+ break;\r
+\r
+ case PsciMethodSmc:\r
+ ArmCallSmc (&ArmSmcArgs);\r
+ break;\r
+\r
+ default:\r
+ DEBUG ((DEBUG_ERROR, "%a: no PSCI method defined\n", __FUNCTION__));\r
+ ASSERT (FALSE);\r
+ }\r
+}\r
+\r
+/**\r
+ This function causes a system-wide reset (cold reset), in which\r
+ all circuitry within the system returns to its initial state. This type of reset\r
+ is asynchronous to system operation and operates without regard to\r
+ cycle boundaries.\r
+\r
+ If this function returns, it means that the system does not support cold reset.\r
+**/\r
+VOID\r
+EFIAPI\r
+ResetCold (\r
+ VOID\r
+ )\r
+{\r
+ // Send a PSCI 0.2 SYSTEM_RESET command\r
+ PerformPsciAction (ARM_SMC_ID_PSCI_SYSTEM_RESET);\r
+}\r
+\r
+/**\r
+ This function causes a system-wide initialization (warm reset), in which all processors\r
+ are set to their initial state. Pending cycles are not corrupted.\r
+\r
+ If this function returns, it means that the system does not support warm reset.\r
+**/\r
+VOID\r
+EFIAPI\r
+ResetWarm (\r
+ VOID\r
+ )\r
+{\r
+ // Map a warm reset into a cold reset\r
+ ResetCold ();\r
+}\r
+\r
+/**\r
+ This function causes the system to enter a power state equivalent\r
+ to the ACPI G2/S5 or G3 states.\r
+\r
+ If this function returns, it means that the system does not support shutdown reset.\r
+**/\r
+VOID\r
+EFIAPI\r
+ResetShutdown (\r
+ VOID\r
+ )\r
+{\r
+ // Send a PSCI 0.2 SYSTEM_OFF command\r
+ PerformPsciAction (ARM_SMC_ID_PSCI_SYSTEM_OFF);\r
+}\r
+\r
+/**\r
+ This function causes a systemwide reset. The exact type of the reset is\r
+ defined by the EFI_GUID that follows the Null-terminated Unicode string passed\r
+ into ResetData. If the platform does not recognize the EFI_GUID in ResetData\r
+ the platform must pick a supported reset type to perform.The platform may\r
+ optionally log the parameters from any non-normal reset that occurs.\r
+\r
+ @param[in] DataSize The size, in bytes, of ResetData.\r
+ @param[in] ResetData The data buffer starts with a Null-terminated string,\r
+ followed by the EFI_GUID.\r
+**/\r
+VOID\r
+EFIAPI\r
+ResetPlatformSpecific (\r
+ IN UINTN DataSize,\r
+ IN VOID *ResetData\r
+ )\r
+{\r
+ // Map the platform specific reset as reboot\r
+ ResetCold ();\r
+}\r
+\r
+/**\r
+ The ResetSystem function resets the entire platform.\r
+\r
+ @param[in] ResetType The type of reset to perform.\r
+ @param[in] ResetStatus The status code for the reset.\r
+ @param[in] DataSize The size, in bytes, of ResetData.\r
+ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown\r
+ the data buffer starts with a Null-terminated string, optionally\r
+ followed by additional binary data. The string is a description\r
+ that the caller may use to further indicate the reason for the\r
+ system reset.\r
+**/\r
+VOID\r
+EFIAPI\r
+ResetSystem (\r
+ IN EFI_RESET_TYPE ResetType,\r
+ IN EFI_STATUS ResetStatus,\r
+ IN UINTN DataSize,\r
+ IN VOID *ResetData OPTIONAL\r
+ )\r
+{\r
+ switch (ResetType) {\r
+ case EfiResetWarm:\r
+ ResetWarm ();\r
+ break;\r
+\r
+ case EfiResetCold:\r
+ ResetCold ();\r
+ break;\r
+\r
+ case EfiResetShutdown:\r
+ ResetShutdown ();\r
+ return;\r
+\r
+ case EfiResetPlatformSpecific:\r
+ ResetPlatformSpecific (DataSize, ResetData);\r
+ return;\r
+\r
+ default:\r
+ return;\r
+ }\r
+}\r