Skip to content

Commit 8f716c9

Browse files
tlendackyIngo Molnar
authored andcommitted
x86/mm: Add support to access boot related data in the clear
Boot data (such as EFI related data) is not encrypted when the system is booted because UEFI/BIOS does not run with SME active. In order to access this data properly it needs to be mapped decrypted. Update early_memremap() to provide an arch specific routine to modify the pagetable protection attributes before they are applied to the new mapping. This is used to remove the encryption mask for boot related data. Update memremap() to provide an arch specific routine to determine if RAM remapping is allowed. RAM remapping will cause an encrypted mapping to be generated. By preventing RAM remapping, ioremap_cache() will be used instead, which will provide a decrypted mapping of the boot related data. Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Matt Fleming <matt@codeblueprint.co.uk> Reviewed-by: Borislav Petkov <bp@suse.de> Cc: Alexander Potapenko <glider@google.com> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Borislav Petkov <bp@alien8.de> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Dave Young <dyoung@redhat.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Larry Woodman <lwoodman@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Michael S. Tsirkin <mst@redhat.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Radim Krčmář <rkrcmar@redhat.com> Cc: Rik van Riel <riel@redhat.com> Cc: Toshimitsu Kani <toshi.kani@hpe.com> Cc: kasan-dev@googlegroups.com Cc: kvm@vger.kernel.org Cc: linux-arch@vger.kernel.org Cc: linux-doc@vger.kernel.org Cc: linux-efi@vger.kernel.org Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/81fb6b4117a5df6b9f2eda342f81bbef4b23d2e5.1500319216.git.thomas.lendacky@amd.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent 38eeccc commit 8f716c9

File tree

5 files changed

+218
-7
lines changed

5 files changed

+218
-7
lines changed

arch/x86/include/asm/io.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,4 +381,9 @@ extern void arch_io_free_memtype_wc(resource_size_t start, resource_size_t size)
381381
#define arch_io_reserve_memtype_wc arch_io_reserve_memtype_wc
382382
#endif
383383

384+
extern bool arch_memremap_can_ram_remap(resource_size_t offset,
385+
unsigned long size,
386+
unsigned long flags);
387+
#define arch_memremap_can_ram_remap arch_memremap_can_ram_remap
388+
384389
#endif /* _ASM_X86_IO_H */

arch/x86/mm/ioremap.c

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <linux/slab.h>
1414
#include <linux/vmalloc.h>
1515
#include <linux/mmiotrace.h>
16+
#include <linux/mem_encrypt.h>
17+
#include <linux/efi.h>
1618

1719
#include <asm/set_memory.h>
1820
#include <asm/e820/api.h>
@@ -21,6 +23,7 @@
2123
#include <asm/tlbflush.h>
2224
#include <asm/pgalloc.h>
2325
#include <asm/pat.h>
26+
#include <asm/setup.h>
2427

2528
#include "physaddr.h"
2629

@@ -417,6 +420,183 @@ void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
417420
iounmap((void __iomem *)((unsigned long)addr & PAGE_MASK));
418421
}
419422

423+
/*
424+
* Examine the physical address to determine if it is an area of memory
425+
* that should be mapped decrypted. If the memory is not part of the
426+
* kernel usable area it was accessed and created decrypted, so these
427+
* areas should be mapped decrypted.
428+
*/
429+
static bool memremap_should_map_decrypted(resource_size_t phys_addr,
430+
unsigned long size)
431+
{
432+
/* Check if the address is outside kernel usable area */
433+
switch (e820__get_entry_type(phys_addr, phys_addr + size - 1)) {
434+
case E820_TYPE_RESERVED:
435+
case E820_TYPE_ACPI:
436+
case E820_TYPE_NVS:
437+
case E820_TYPE_UNUSABLE:
438+
return true;
439+
default:
440+
break;
441+
}
442+
443+
return false;
444+
}
445+
446+
/*
447+
* Examine the physical address to determine if it is EFI data. Check
448+
* it against the boot params structure and EFI tables and memory types.
449+
*/
450+
static bool memremap_is_efi_data(resource_size_t phys_addr,
451+
unsigned long size)
452+
{
453+
u64 paddr;
454+
455+
/* Check if the address is part of EFI boot/runtime data */
456+
if (!efi_enabled(EFI_BOOT))
457+
return false;
458+
459+
paddr = boot_params.efi_info.efi_memmap_hi;
460+
paddr <<= 32;
461+
paddr |= boot_params.efi_info.efi_memmap;
462+
if (phys_addr == paddr)
463+
return true;
464+
465+
paddr = boot_params.efi_info.efi_systab_hi;
466+
paddr <<= 32;
467+
paddr |= boot_params.efi_info.efi_systab;
468+
if (phys_addr == paddr)
469+
return true;
470+
471+
if (efi_is_table_address(phys_addr))
472+
return true;
473+
474+
switch (efi_mem_type(phys_addr)) {
475+
case EFI_BOOT_SERVICES_DATA:
476+
case EFI_RUNTIME_SERVICES_DATA:
477+
return true;
478+
default:
479+
break;
480+
}
481+
482+
return false;
483+
}
484+
485+
/*
486+
* Examine the physical address to determine if it is boot data by checking
487+
* it against the boot params setup_data chain.
488+
*/
489+
static bool memremap_is_setup_data(resource_size_t phys_addr,
490+
unsigned long size)
491+
{
492+
struct setup_data *data;
493+
u64 paddr, paddr_next;
494+
495+
paddr = boot_params.hdr.setup_data;
496+
while (paddr) {
497+
unsigned int len;
498+
499+
if (phys_addr == paddr)
500+
return true;
501+
502+
data = memremap(paddr, sizeof(*data),
503+
MEMREMAP_WB | MEMREMAP_DEC);
504+
505+
paddr_next = data->next;
506+
len = data->len;
507+
508+
memunmap(data);
509+
510+
if ((phys_addr > paddr) && (phys_addr < (paddr + len)))
511+
return true;
512+
513+
paddr = paddr_next;
514+
}
515+
516+
return false;
517+
}
518+
519+
/*
520+
* Examine the physical address to determine if it is boot data by checking
521+
* it against the boot params setup_data chain (early boot version).
522+
*/
523+
static bool __init early_memremap_is_setup_data(resource_size_t phys_addr,
524+
unsigned long size)
525+
{
526+
struct setup_data *data;
527+
u64 paddr, paddr_next;
528+
529+
paddr = boot_params.hdr.setup_data;
530+
while (paddr) {
531+
unsigned int len;
532+
533+
if (phys_addr == paddr)
534+
return true;
535+
536+
data = early_memremap_decrypted(paddr, sizeof(*data));
537+
538+
paddr_next = data->next;
539+
len = data->len;
540+
541+
early_memunmap(data, sizeof(*data));
542+
543+
if ((phys_addr > paddr) && (phys_addr < (paddr + len)))
544+
return true;
545+
546+
paddr = paddr_next;
547+
}
548+
549+
return false;
550+
}
551+
552+
/*
553+
* Architecture function to determine if RAM remap is allowed. By default, a
554+
* RAM remap will map the data as encrypted. Determine if a RAM remap should
555+
* not be done so that the data will be mapped decrypted.
556+
*/
557+
bool arch_memremap_can_ram_remap(resource_size_t phys_addr, unsigned long size,
558+
unsigned long flags)
559+
{
560+
if (!sme_active())
561+
return true;
562+
563+
if (flags & MEMREMAP_ENC)
564+
return true;
565+
566+
if (flags & MEMREMAP_DEC)
567+
return false;
568+
569+
if (memremap_is_setup_data(phys_addr, size) ||
570+
memremap_is_efi_data(phys_addr, size) ||
571+
memremap_should_map_decrypted(phys_addr, size))
572+
return false;
573+
574+
return true;
575+
}
576+
577+
/*
578+
* Architecture override of __weak function to adjust the protection attributes
579+
* used when remapping memory. By default, early_memremap() will map the data
580+
* as encrypted. Determine if an encrypted mapping should not be done and set
581+
* the appropriate protection attributes.
582+
*/
583+
pgprot_t __init early_memremap_pgprot_adjust(resource_size_t phys_addr,
584+
unsigned long size,
585+
pgprot_t prot)
586+
{
587+
if (!sme_active())
588+
return prot;
589+
590+
if (early_memremap_is_setup_data(phys_addr, size) ||
591+
memremap_is_efi_data(phys_addr, size) ||
592+
memremap_should_map_decrypted(phys_addr, size))
593+
prot = pgprot_decrypted(prot);
594+
else
595+
prot = pgprot_encrypted(prot);
596+
597+
return prot;
598+
}
599+
420600
#ifdef CONFIG_ARCH_USE_MEMREMAP_PROT
421601
/* Remap memory with encryption */
422602
void __init *early_memremap_encrypted(resource_size_t phys_addr,

include/linux/io.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ enum {
157157
MEMREMAP_WB = 1 << 0,
158158
MEMREMAP_WT = 1 << 1,
159159
MEMREMAP_WC = 1 << 2,
160+
MEMREMAP_ENC = 1 << 3,
161+
MEMREMAP_DEC = 1 << 4,
160162
};
161163

162164
void *memremap(resource_size_t offset, size_t size, unsigned long flags);

kernel/memremap.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,33 @@ static void *arch_memremap_wb(resource_size_t offset, unsigned long size)
3434
}
3535
#endif
3636

37-
static void *try_ram_remap(resource_size_t offset, size_t size)
37+
#ifndef arch_memremap_can_ram_remap
38+
static bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size,
39+
unsigned long flags)
40+
{
41+
return true;
42+
}
43+
#endif
44+
45+
static void *try_ram_remap(resource_size_t offset, size_t size,
46+
unsigned long flags)
3847
{
3948
unsigned long pfn = PHYS_PFN(offset);
4049

4150
/* In the simple case just return the existing linear address */
42-
if (pfn_valid(pfn) && !PageHighMem(pfn_to_page(pfn)))
51+
if (pfn_valid(pfn) && !PageHighMem(pfn_to_page(pfn)) &&
52+
arch_memremap_can_ram_remap(offset, size, flags))
4353
return __va(offset);
54+
4455
return NULL; /* fallback to arch_memremap_wb */
4556
}
4657

4758
/**
4859
* memremap() - remap an iomem_resource as cacheable memory
4960
* @offset: iomem resource start address
5061
* @size: size of remap
51-
* @flags: any of MEMREMAP_WB, MEMREMAP_WT and MEMREMAP_WC
62+
* @flags: any of MEMREMAP_WB, MEMREMAP_WT, MEMREMAP_WC,
63+
* MEMREMAP_ENC, MEMREMAP_DEC
5264
*
5365
* memremap() is "ioremap" for cases where it is known that the resource
5466
* being mapped does not have i/o side effects and the __iomem
@@ -95,7 +107,7 @@ void *memremap(resource_size_t offset, size_t size, unsigned long flags)
95107
* the requested range is potentially in System RAM.
96108
*/
97109
if (is_ram == REGION_INTERSECTS)
98-
addr = try_ram_remap(offset, size);
110+
addr = try_ram_remap(offset, size, flags);
99111
if (!addr)
100112
addr = arch_memremap_wb(offset, size);
101113
}

mm/early_ioremap.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ early_param("early_ioremap_debug", early_ioremap_debug_setup);
3030

3131
static int after_paging_init __initdata;
3232

33+
pgprot_t __init __weak early_memremap_pgprot_adjust(resource_size_t phys_addr,
34+
unsigned long size,
35+
pgprot_t prot)
36+
{
37+
return prot;
38+
}
39+
3340
void __init __weak early_ioremap_shutdown(void)
3441
{
3542
}
@@ -215,14 +222,19 @@ early_ioremap(resource_size_t phys_addr, unsigned long size)
215222
void __init *
216223
early_memremap(resource_size_t phys_addr, unsigned long size)
217224
{
218-
return (__force void *)__early_ioremap(phys_addr, size,
219-
FIXMAP_PAGE_NORMAL);
225+
pgprot_t prot = early_memremap_pgprot_adjust(phys_addr, size,
226+
FIXMAP_PAGE_NORMAL);
227+
228+
return (__force void *)__early_ioremap(phys_addr, size, prot);
220229
}
221230
#ifdef FIXMAP_PAGE_RO
222231
void __init *
223232
early_memremap_ro(resource_size_t phys_addr, unsigned long size)
224233
{
225-
return (__force void *)__early_ioremap(phys_addr, size, FIXMAP_PAGE_RO);
234+
pgprot_t prot = early_memremap_pgprot_adjust(phys_addr, size,
235+
FIXMAP_PAGE_RO);
236+
237+
return (__force void *)__early_ioremap(phys_addr, size, prot);
226238
}
227239
#endif
228240

0 commit comments

Comments
 (0)