Commit 5da04cc8 authored by Lianbo Jiang's avatar Lianbo Jiang Committed by Borislav Petkov

x86/mm: Rework ioremap resource mapping determination

On ioremap(), __ioremap_check_mem() does a couple of checks on the
supplied memory range to determine how the range should be mapped and in
particular what protection flags should be used.

Generalize the procedure by introducing IORES_MAP_* flags which control
different aspects of the ioremapping and use them in the respective
helpers which determine which descriptor flags should be set per range.

 [ bp:
   - Rewrite commit message.
   - Add/improve comments.
   - Reflow __ioremap_caller()'s args.
   - s/__ioremap_check_desc/__ioremap_check_encrypted/g;
   - s/__ioremap_res_check/__ioremap_collect_map_flags/g;
   - clarify __ioremap_check_ram()'s purpose. ]
Signed-off-by: default avatarLianbo Jiang <lijiang@redhat.com>
Co-developed-by: default avatarBorislav Petkov <bp@suse.de>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: bhe@redhat.com
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: dyoung@redhat.com
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: kexec@lists.infradead.org
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: x86-ml <x86@kernel.org>
Link: https://lkml.kernel.org/r/20190423013007.17838-3-lijiang@redhat.com
parent ae9e13d6
......@@ -28,9 +28,11 @@
#include "physaddr.h"
struct ioremap_mem_flags {
bool system_ram;
bool desc_other;
/*
* Descriptor controlling ioremap() behavior.
*/
struct ioremap_desc {
unsigned int flags;
};
/*
......@@ -62,13 +64,14 @@ int ioremap_change_attr(unsigned long vaddr, unsigned long size,
return err;
}
static bool __ioremap_check_ram(struct resource *res)
/* Does the range (or a subset of) contain normal RAM? */
static unsigned int __ioremap_check_ram(struct resource *res)
{
unsigned long start_pfn, stop_pfn;
unsigned long i;
if ((res->flags & IORESOURCE_SYSTEM_RAM) != IORESOURCE_SYSTEM_RAM)
return false;
return 0;
start_pfn = (res->start + PAGE_SIZE - 1) >> PAGE_SHIFT;
stop_pfn = (res->end + 1) >> PAGE_SHIFT;
......@@ -76,28 +79,44 @@ static bool __ioremap_check_ram(struct resource *res)
for (i = 0; i < (stop_pfn - start_pfn); ++i)
if (pfn_valid(start_pfn + i) &&
!PageReserved(pfn_to_page(start_pfn + i)))
return true;
return IORES_MAP_SYSTEM_RAM;
}
return false;
return 0;
}
static int __ioremap_check_desc_other(struct resource *res)
/*
* In a SEV guest, NONE and RESERVED should not be mapped encrypted because
* there the whole memory is already encrypted.
*/
static unsigned int __ioremap_check_encrypted(struct resource *res)
{
return (res->desc != IORES_DESC_NONE);
if (!sev_active())
return 0;
switch (res->desc) {
case IORES_DESC_NONE:
case IORES_DESC_RESERVED:
break;
default:
return IORES_MAP_ENCRYPTED;
}
return 0;
}
static int __ioremap_res_check(struct resource *res, void *arg)
static int __ioremap_collect_map_flags(struct resource *res, void *arg)
{
struct ioremap_mem_flags *flags = arg;
struct ioremap_desc *desc = arg;
if (!flags->system_ram)
flags->system_ram = __ioremap_check_ram(res);
if (!(desc->flags & IORES_MAP_SYSTEM_RAM))
desc->flags |= __ioremap_check_ram(res);
if (!flags->desc_other)
flags->desc_other = __ioremap_check_desc_other(res);
if (!(desc->flags & IORES_MAP_ENCRYPTED))
desc->flags |= __ioremap_check_encrypted(res);
return flags->system_ram && flags->desc_other;
return ((desc->flags & (IORES_MAP_SYSTEM_RAM | IORES_MAP_ENCRYPTED)) ==
(IORES_MAP_SYSTEM_RAM | IORES_MAP_ENCRYPTED));
}
/*
......@@ -106,15 +125,15 @@ static int __ioremap_res_check(struct resource *res, void *arg)
* resource described not as IORES_DESC_NONE (e.g. IORES_DESC_ACPI_TABLES).
*/
static void __ioremap_check_mem(resource_size_t addr, unsigned long size,
struct ioremap_mem_flags *flags)
struct ioremap_desc *desc)
{
u64 start, end;
start = (u64)addr;
end = start + size - 1;
memset(flags, 0, sizeof(*flags));
memset(desc, 0, sizeof(struct ioremap_desc));
walk_mem_res(start, end, flags, __ioremap_res_check);
walk_mem_res(start, end, desc, __ioremap_collect_map_flags);
}
/*
......@@ -131,15 +150,15 @@ static void __ioremap_check_mem(resource_size_t addr, unsigned long size,
* have to convert them into an offset in a page-aligned mapping, but the
* caller shouldn't need to know that small detail.
*/
static void __iomem *__ioremap_caller(resource_size_t phys_addr,
unsigned long size, enum page_cache_mode pcm,
void *caller, bool encrypted)
static void __iomem *
__ioremap_caller(resource_size_t phys_addr, unsigned long size,
enum page_cache_mode pcm, void *caller, bool encrypted)
{
unsigned long offset, vaddr;
resource_size_t last_addr;
const resource_size_t unaligned_phys_addr = phys_addr;
const unsigned long unaligned_size = size;
struct ioremap_mem_flags mem_flags;
struct ioremap_desc io_desc;
struct vm_struct *area;
enum page_cache_mode new_pcm;
pgprot_t prot;
......@@ -158,12 +177,12 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
return NULL;
}
__ioremap_check_mem(phys_addr, size, &mem_flags);
__ioremap_check_mem(phys_addr, size, &io_desc);
/*
* Don't allow anybody to remap normal RAM that we're using..
*/
if (mem_flags.system_ram) {
if (io_desc.flags & IORES_MAP_SYSTEM_RAM) {
WARN_ONCE(1, "ioremap on RAM at %pa - %pa\n",
&phys_addr, &last_addr);
return NULL;
......@@ -201,7 +220,7 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
* resulting mapping.
*/
prot = PAGE_KERNEL_IO;
if ((sev_active() && mem_flags.desc_other) || encrypted)
if ((io_desc.flags & IORES_MAP_ENCRYPTED) || encrypted)
prot = pgprot_encrypted(prot);
switch (pcm) {
......
......@@ -12,6 +12,7 @@
#ifndef __ASSEMBLY__
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/bits.h>
/*
* Resources are tree-like, allowing
* nesting etc..
......@@ -136,6 +137,14 @@ enum {
IORES_DESC_RESERVED = 8,
};
/*
* Flags controlling ioremap() behavior.
*/
enum {
IORES_MAP_SYSTEM_RAM = BIT(0),
IORES_MAP_ENCRYPTED = BIT(1),
};
/* helpers to define resources */
#define DEFINE_RES_NAMED(_start, _size, _name, _flags) \
{ \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment