|
@@ -13,6 +13,8 @@
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/vmalloc.h>
|
|
|
#include <linux/mmiotrace.h>
|
|
|
+#include <linux/mem_encrypt.h>
|
|
|
+#include <linux/efi.h>
|
|
|
|
|
|
#include <asm/set_memory.h>
|
|
|
#include <asm/e820/api.h>
|
|
@@ -21,6 +23,7 @@
|
|
|
#include <asm/tlbflush.h>
|
|
|
#include <asm/pgalloc.h>
|
|
|
#include <asm/pat.h>
|
|
|
+#include <asm/setup.h>
|
|
|
|
|
|
#include "physaddr.h"
|
|
|
|
|
@@ -417,6 +420,183 @@ void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
|
|
|
iounmap((void __iomem *)((unsigned long)addr & PAGE_MASK));
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Examine the physical address to determine if it is an area of memory
|
|
|
+ * that should be mapped decrypted. If the memory is not part of the
|
|
|
+ * kernel usable area it was accessed and created decrypted, so these
|
|
|
+ * areas should be mapped decrypted.
|
|
|
+ */
|
|
|
+static bool memremap_should_map_decrypted(resource_size_t phys_addr,
|
|
|
+ unsigned long size)
|
|
|
+{
|
|
|
+ /* Check if the address is outside kernel usable area */
|
|
|
+ switch (e820__get_entry_type(phys_addr, phys_addr + size - 1)) {
|
|
|
+ case E820_TYPE_RESERVED:
|
|
|
+ case E820_TYPE_ACPI:
|
|
|
+ case E820_TYPE_NVS:
|
|
|
+ case E820_TYPE_UNUSABLE:
|
|
|
+ return true;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Examine the physical address to determine if it is EFI data. Check
|
|
|
+ * it against the boot params structure and EFI tables and memory types.
|
|
|
+ */
|
|
|
+static bool memremap_is_efi_data(resource_size_t phys_addr,
|
|
|
+ unsigned long size)
|
|
|
+{
|
|
|
+ u64 paddr;
|
|
|
+
|
|
|
+ /* Check if the address is part of EFI boot/runtime data */
|
|
|
+ if (!efi_enabled(EFI_BOOT))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ paddr = boot_params.efi_info.efi_memmap_hi;
|
|
|
+ paddr <<= 32;
|
|
|
+ paddr |= boot_params.efi_info.efi_memmap;
|
|
|
+ if (phys_addr == paddr)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ paddr = boot_params.efi_info.efi_systab_hi;
|
|
|
+ paddr <<= 32;
|
|
|
+ paddr |= boot_params.efi_info.efi_systab;
|
|
|
+ if (phys_addr == paddr)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ if (efi_is_table_address(phys_addr))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ switch (efi_mem_type(phys_addr)) {
|
|
|
+ case EFI_BOOT_SERVICES_DATA:
|
|
|
+ case EFI_RUNTIME_SERVICES_DATA:
|
|
|
+ return true;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Examine the physical address to determine if it is boot data by checking
|
|
|
+ * it against the boot params setup_data chain.
|
|
|
+ */
|
|
|
+static bool memremap_is_setup_data(resource_size_t phys_addr,
|
|
|
+ unsigned long size)
|
|
|
+{
|
|
|
+ struct setup_data *data;
|
|
|
+ u64 paddr, paddr_next;
|
|
|
+
|
|
|
+ paddr = boot_params.hdr.setup_data;
|
|
|
+ while (paddr) {
|
|
|
+ unsigned int len;
|
|
|
+
|
|
|
+ if (phys_addr == paddr)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ data = memremap(paddr, sizeof(*data),
|
|
|
+ MEMREMAP_WB | MEMREMAP_DEC);
|
|
|
+
|
|
|
+ paddr_next = data->next;
|
|
|
+ len = data->len;
|
|
|
+
|
|
|
+ memunmap(data);
|
|
|
+
|
|
|
+ if ((phys_addr > paddr) && (phys_addr < (paddr + len)))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ paddr = paddr_next;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Examine the physical address to determine if it is boot data by checking
|
|
|
+ * it against the boot params setup_data chain (early boot version).
|
|
|
+ */
|
|
|
+static bool __init early_memremap_is_setup_data(resource_size_t phys_addr,
|
|
|
+ unsigned long size)
|
|
|
+{
|
|
|
+ struct setup_data *data;
|
|
|
+ u64 paddr, paddr_next;
|
|
|
+
|
|
|
+ paddr = boot_params.hdr.setup_data;
|
|
|
+ while (paddr) {
|
|
|
+ unsigned int len;
|
|
|
+
|
|
|
+ if (phys_addr == paddr)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ data = early_memremap_decrypted(paddr, sizeof(*data));
|
|
|
+
|
|
|
+ paddr_next = data->next;
|
|
|
+ len = data->len;
|
|
|
+
|
|
|
+ early_memunmap(data, sizeof(*data));
|
|
|
+
|
|
|
+ if ((phys_addr > paddr) && (phys_addr < (paddr + len)))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ paddr = paddr_next;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Architecture function to determine if RAM remap is allowed. By default, a
|
|
|
+ * RAM remap will map the data as encrypted. Determine if a RAM remap should
|
|
|
+ * not be done so that the data will be mapped decrypted.
|
|
|
+ */
|
|
|
+bool arch_memremap_can_ram_remap(resource_size_t phys_addr, unsigned long size,
|
|
|
+ unsigned long flags)
|
|
|
+{
|
|
|
+ if (!sme_active())
|
|
|
+ return true;
|
|
|
+
|
|
|
+ if (flags & MEMREMAP_ENC)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ if (flags & MEMREMAP_DEC)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (memremap_is_setup_data(phys_addr, size) ||
|
|
|
+ memremap_is_efi_data(phys_addr, size) ||
|
|
|
+ memremap_should_map_decrypted(phys_addr, size))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Architecture override of __weak function to adjust the protection attributes
|
|
|
+ * used when remapping memory. By default, early_memremap() will map the data
|
|
|
+ * as encrypted. Determine if an encrypted mapping should not be done and set
|
|
|
+ * the appropriate protection attributes.
|
|
|
+ */
|
|
|
+pgprot_t __init early_memremap_pgprot_adjust(resource_size_t phys_addr,
|
|
|
+ unsigned long size,
|
|
|
+ pgprot_t prot)
|
|
|
+{
|
|
|
+ if (!sme_active())
|
|
|
+ return prot;
|
|
|
+
|
|
|
+ if (early_memremap_is_setup_data(phys_addr, size) ||
|
|
|
+ memremap_is_efi_data(phys_addr, size) ||
|
|
|
+ memremap_should_map_decrypted(phys_addr, size))
|
|
|
+ prot = pgprot_decrypted(prot);
|
|
|
+ else
|
|
|
+ prot = pgprot_encrypted(prot);
|
|
|
+
|
|
|
+ return prot;
|
|
|
+}
|
|
|
+
|
|
|
#ifdef CONFIG_ARCH_USE_MEMREMAP_PROT
|
|
|
/* Remap memory with encryption */
|
|
|
void __init *early_memremap_encrypted(resource_size_t phys_addr,
|