arm64: permit ACPI core to map kernel memory used for table overrides
[linux-2.6-microblaze.git] / arch / arm64 / kernel / acpi.c
index 4559664..cada0b8 100644 (file)
@@ -298,8 +298,21 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
                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;
+                       if (memblock_is_map_memory(phys) ||
+                           !memblock_is_region_memory(phys, size)) {
+                               pr_warn(FW_BUG "requested region covers kernel memory @ %pa\n", &phys);
+                               return NULL;
+                       }
+                       /*
+                        * Mapping kernel memory is permitted if the region in
+                        * question is covered by a single memblock with the
+                        * NOMAP attribute set: this enables the use of ACPI
+                        * table overrides passed via initramfs, which are
+                        * reserved in memory using arch_reserve_mem_area()
+                        * below. As this particular use case only requires
+                        * read access, fall through to the R/O mapping case.
+                        */
+                       fallthrough;
 
                case EFI_RUNTIME_SERVICES_CODE:
                        /*
@@ -322,7 +335,7 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
                         */
                        if (memblock_is_map_memory(phys))
                                return (void __iomem *)__phys_to_virt(phys);
-                       /* fall through */
+                       fallthrough;
 
                default:
                        if (region->attribute & EFI_MEMORY_WB)
@@ -388,3 +401,8 @@ int apei_claim_sea(struct pt_regs *regs)
 
        return err;
 }
+
+void arch_reserve_mem_area(acpi_physical_address addr, size_t size)
+{
+       memblock_mark_nomap(addr, size);
+}