]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmVirtPkg/HighMemDxe/HighMemDxe.c
ArmVirtPkg/HighMemDxe: use CPU arch protocol to apply memprotect policy
[mirror_edk2.git] / ArmVirtPkg / HighMemDxe / HighMemDxe.c
index 4d56e6236b54eeac81e80550c924cd66347d57f9..4e41120deff3a198b83739d9f1b869ff8ed72cf6 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 *  High memory node enumeration DXE driver for ARM Virtual Machines\r
 *\r
-*  Copyright (c) 2015, Linaro Ltd. All rights reserved.\r
+*  Copyright (c) 2015-2016, Linaro Ltd. All rights reserved.\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
 **/\r
 \r
 #include <Library/BaseLib.h>\r
-#include <Library/UefiDriverEntryPoint.h>\r
 #include <Library/DebugLib.h>\r
-#include <Library/PcdLib.h>\r
-#include <Library/HobLib.h>\r
-#include <libfdt.h>\r
 #include <Library/DxeServicesTableLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+#include <Protocol/Cpu.h>\r
+#include <Protocol/FdtClient.h>\r
 \r
 EFI_STATUS\r
 EFIAPI\r
@@ -29,76 +30,94 @@ InitializeHighMemDxe (
   IN EFI_SYSTEM_TABLE     *SystemTable\r
   )\r
 {\r
-  VOID             *Hob;\r
-  VOID             *DeviceTreeBase;\r
-  INT32            Node, Prev;\r
-  EFI_STATUS       Status;\r
-  CONST CHAR8      *Type;\r
-  INT32            Len;\r
-  CONST VOID       *RegProp;\r
-  UINT64           CurBase;\r
-  UINT64           CurSize;\r
+  FDT_CLIENT_PROTOCOL   *FdtClient;\r
+  EFI_CPU_ARCH_PROTOCOL *Cpu;\r
+  EFI_STATUS            Status, FindNodeStatus;\r
+  INT32                 Node;\r
+  CONST UINT32          *Reg;\r
+  UINT32                RegSize;\r
+  UINTN                 AddressCells, SizeCells;\r
+  UINT64                CurBase;\r
+  UINT64                CurSize;\r
+  UINT64                Attributes;\r
 \r
-  Hob = GetFirstGuidHob(&gFdtHobGuid);\r
-  if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {\r
-    return EFI_NOT_FOUND;\r
-  }\r
-  DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);\r
+  Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL,\r
+                  (VOID **)&FdtClient);\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
-  if (fdt_check_header (DeviceTreeBase) != 0) {\r
-    DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__,\r
-      DeviceTreeBase));\r
-    return EFI_NOT_FOUND;\r
-  }\r
-\r
-  DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));\r
+  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL,\r
+                  (VOID **)&Cpu);\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
   //\r
-  // Check for memory node and add the memory spaces expect the lowest one\r
+  // Check for memory node and add the memory spaces except the lowest one\r
   //\r
-  for (Prev = 0;; Prev = Node) {\r
-    Node = fdt_next_node (DeviceTreeBase, Prev, NULL);\r
-    if (Node < 0) {\r
-      break;\r
-    }\r
+  for (FindNodeStatus = FdtClient->FindMemoryNodeReg (FdtClient, &Node,\r
+                                     (CONST VOID **) &Reg, &AddressCells,\r
+                                     &SizeCells, &RegSize);\r
+       !EFI_ERROR (FindNodeStatus);\r
+       FindNodeStatus = FdtClient->FindNextMemoryNodeReg (FdtClient, Node,\r
+                                     &Node, (CONST VOID **) &Reg, &AddressCells,\r
+                                     &SizeCells, &RegSize)) {\r
+    ASSERT (AddressCells <= 2);\r
+    ASSERT (SizeCells <= 2);\r
 \r
-    Type = fdt_getprop (DeviceTreeBase, Node, "device_type", &Len);\r
-    if (Type && AsciiStrnCmp (Type, "memory", Len) == 0) {\r
-      //\r
-      // Get the 'reg' property of this node. For now, we will assume\r
-      // two 8 byte quantities for base and size, respectively.\r
-      //\r
-      RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);\r
-      if (RegProp != NULL && Len == (2 * sizeof (UINT64))) {\r
+    while (RegSize > 0) {\r
+      CurBase = SwapBytes32 (*Reg++);\r
+      if (AddressCells > 1) {\r
+        CurBase = (CurBase << 32) | SwapBytes32 (*Reg++);\r
+      }\r
+      CurSize = SwapBytes32 (*Reg++);\r
+      if (SizeCells > 1) {\r
+        CurSize = (CurSize << 32) | SwapBytes32 (*Reg++);\r
+      }\r
+      RegSize -= (AddressCells + SizeCells) * sizeof (UINT32);\r
+\r
+      if (PcdGet64 (PcdSystemMemoryBase) != CurBase) {\r
+        Status = gDS->AddMemorySpace (EfiGcdMemoryTypeSystemMemory, CurBase,\r
+                        CurSize, EFI_MEMORY_WB);\r
 \r
-        CurBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
-        CurSize = fdt64_to_cpu (((UINT64 *)RegProp)[1]);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR,\r
+            "%a: Failed to add System RAM @ 0x%lx - 0x%lx (%r)\n",\r
+            __FUNCTION__, CurBase, CurBase + CurSize - 1, Status));\r
+          continue;\r
+        }\r
 \r
-        if (PcdGet64 (PcdSystemMemoryBase) != CurBase) {\r
-          Status = gDS->AddMemorySpace (\r
-                          EfiGcdMemoryTypeSystemMemory,\r
-                          CurBase, CurSize,\r
-                          EFI_MEMORY_WB);\r
+        Status = gDS->SetMemorySpaceAttributes (CurBase, CurSize,\r
+                        EFI_MEMORY_WB);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((DEBUG_WARN,\r
+            "%a: gDS->SetMemorySpaceAttributes() failed on region 0x%lx - 0x%lx (%r)\n",\r
+            __FUNCTION__, CurBase, CurBase + CurSize - 1, Status));\r
+        }\r
 \r
-          if (EFI_ERROR (Status)) {\r
-            DEBUG ((EFI_D_ERROR,\r
-              "%a: Failed to add System RAM @ 0x%lx - 0x%lx (%r)\n",\r
-              __FUNCTION__, CurBase, CurBase + CurSize - 1, Status));\r
-            continue;\r
-          }\r
+        //\r
+        // Due to the ambiguous nature of the RO/XP GCD memory space attributes,\r
+        // it is impossible to add a memory space with the XP attribute in a way\r
+        // that does not result in the XP attribute being set on *all* UEFI\r
+        // memory map entries that are carved from it, including code regions\r
+        // that require executable permissions.\r
+        //\r
+        // So instead, we never set the RO/XP attributes in the GCD memory space\r
+        // capabilities or attribute fields, and apply any protections directly\r
+        // on the page table mappings by going through the cpu arch protocol.\r
+        //\r
+        Attributes = EFI_MEMORY_WB;\r
+        if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) &\r
+             (1U << (UINT32)EfiConventionalMemory)) != 0) {\r
+          Attributes |= EFI_MEMORY_XP;\r
+        }\r
 \r
-          Status = gDS->SetMemorySpaceAttributes (\r
-                          CurBase, CurSize,\r
-                          EFI_MEMORY_WB);\r
+        Status = Cpu->SetMemoryAttributes (Cpu, CurBase, CurSize, Attributes);\r
 \r
-          if (EFI_ERROR (Status)) {\r
-            DEBUG ((EFI_D_ERROR,\r
-              "%a: Failed to set System RAM @ 0x%lx - 0x%lx attribute (%r)\n",\r
-              __FUNCTION__, CurBase, CurBase + CurSize - 1, Status));\r
-          } else {\r
-            DEBUG ((EFI_D_INFO, "%a: Add System RAM @ 0x%lx - 0x%lx\n",\r
-              __FUNCTION__, CurBase, CurBase + CurSize - 1));\r
-          }\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR,\r
+            "%a: Failed to set System RAM @ 0x%lx - 0x%lx attribute (%r)\n",\r
+            __FUNCTION__, CurBase, CurBase + CurSize - 1, Status));\r
+        } else {\r
+          DEBUG ((EFI_D_INFO, "%a: Add System RAM @ 0x%lx - 0x%lx\n",\r
+            __FUNCTION__, CurBase, CurBase + CurSize - 1));\r
         }\r
       }\r
     }\r