arm64/acpi: disallow AML memory opregions to access kernel memory
[linux-2.6-microblaze.git] / arch / arm64 / kernel / acpi.c
index a7586a4..01b861e 100644 (file)
@@ -261,6 +261,72 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
        return __pgprot(PROT_DEVICE_nGnRnE);
 }
 
+void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
+{
+       efi_memory_desc_t *md, *region = NULL;
+       pgprot_t prot;
+
+       if (WARN_ON_ONCE(!efi_enabled(EFI_MEMMAP)))
+               return NULL;
+
+       for_each_efi_memory_desc(md) {
+               u64 end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+
+               if (phys < md->phys_addr || phys >= end)
+                       continue;
+
+               if (phys + size > end) {
+                       pr_warn(FW_BUG "requested region covers multiple EFI memory regions\n");
+                       return NULL;
+               }
+               region = md;
+               break;
+       }
+
+       /*
+        * It is fine for AML to remap regions that are not represented in the
+        * EFI memory map at all, as it only describes normal memory, and MMIO
+        * regions that require a virtual mapping to make them accessible to
+        * the EFI runtime services.
+        */
+       prot = __pgprot(PROT_DEVICE_nGnRnE);
+       if (region) {
+               switch (region->type) {
+               case EFI_LOADER_CODE:
+               case EFI_LOADER_DATA:
+               case EFI_BOOT_SERVICES_CODE:
+               case EFI_BOOT_SERVICES_DATA:
+               case EFI_CONVENTIONAL_MEMORY:
+               case EFI_PERSISTENT_MEMORY:
+                       pr_warn(FW_BUG "requested region covers kernel memory @ %pa\n", &phys);
+                       return NULL;
+
+               case EFI_ACPI_RECLAIM_MEMORY:
+                       /*
+                        * ACPI reclaim memory is used to pass firmware tables
+                        * and other data that is intended for consumption by
+                        * the OS only, which may decide it wants to reclaim
+                        * that memory and use it for something else. We never
+                        * do that, but we usually add it to the linear map
+                        * anyway, in which case we should use the existing
+                        * mapping.
+                        */
+                       if (memblock_is_map_memory(phys))
+                               return (void __iomem *)__phys_to_virt(phys);
+                       /* fall through */
+
+               default:
+                       if (region->attribute & EFI_MEMORY_WB)
+                               prot = PAGE_KERNEL;
+                       else if (region->attribute & EFI_MEMORY_WT)
+                               prot = __pgprot(PROT_NORMAL_WT);
+                       else if (region->attribute & EFI_MEMORY_WC)
+                               prot = __pgprot(PROT_NORMAL_NC);
+               }
+       }
+       return __ioremap(phys, size, prot);
+}
+
 /*
  * Claim Synchronous External Aborts as a firmware first notification.
  *