+ /** @file\r
+ ARM implementation of architecture specific routines related to\r
+ PersistAcrossReset capsules\r
+\r
+ Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "CapsuleService.h"\r
+\r
+#include <Library/CacheMaintenanceLib.h>\r
+\r
+/**\r
+ Whether the platform supports capsules that persist across reset. Note that\r
+ some platforms only support such capsules at boot time.\r
+\r
+ @return TRUE if a PersistAcrossReset capsule may be passed to UpdateCapsule()\r
+ at this time\r
+ FALSE otherwise\r
+**/\r
+BOOLEAN\r
+IsPersistAcrossResetCapsuleSupported (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // ARM requires the capsule payload to be cleaned to the point of coherency\r
+ // (PoC), but only permits doing so using cache maintenance instructions that\r
+ // operate on virtual addresses. Since at runtime, we don't know the virtual\r
+ // addresses of the data structures that make up the scatter/gather list, we\r
+ // cannot perform the maintenance, and all we can do is give up.\r
+ //\r
+ return FeaturePcdGet (PcdSupportUpdateCapsuleReset) && !EfiAtRuntime ();\r
+}\r
+\r
+/**\r
+ Writes Back a range of data cache lines covering a set of capsules in memory.\r
+\r
+ Writes Back the data cache lines specified by ScatterGatherList.\r
+\r
+ @param ScatterGatherList Physical address of the data structure that\r
+ describes a set of capsules in memory\r
+\r
+**/\r
+VOID\r
+CapsuleCacheWriteBack (\r
+ IN EFI_PHYSICAL_ADDRESS ScatterGatherList\r
+ )\r
+{\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *Desc;\r
+\r
+ Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)ScatterGatherList;\r
+ do {\r
+ WriteBackDataCacheRange (Desc, sizeof *Desc);\r
+\r
+ if (Desc->Length > 0) {\r
+ WriteBackDataCacheRange ((VOID *)(UINTN)Desc->Union.DataBlock,\r
+ Desc->Length\r
+ );\r
+ Desc++;\r
+ } else if (Desc->Union.ContinuationPointer > 0) {\r
+ Desc = (EFI_CAPSULE_BLOCK_DESCRIPTOR *)(UINTN)Desc->Union.ContinuationPointer;\r
+ }\r
+ } while (Desc->Length > 0 || Desc->Union.ContinuationPointer > 0);\r
+\r
+ WriteBackDataCacheRange (Desc, sizeof *Desc);\r
+}\r