Merge branch 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 mm updates from Ingo Molnar: - Extend the memmap= boot parameter syntax to allow the redeclaration and dropping of existing ranges, and to support all e820 range types (Jan H. Schönherr) - Improve the W+X boot time security checks to remove false positive warnings on Xen (Jan Beulich) - Support booting as Xen PVH guest (Juergen Gross) - Improved 5-level paging (LA57) support, in particular it's possible now to have a single kernel image for both 4-level and 5-level hardware (Kirill A. Shutemov) - AMD hardware RAM encryption support (SME/SEV) fixes (Tom Lendacky) - Preparatory commits for hardware-encrypted RAM support on Intel CPUs. (Kirill A. Shutemov) - Improved Intel-MID support (Andy Shevchenko) - Show EFI page tables in page_tables debug files (Andy Lutomirski) - ... plus misc fixes and smaller cleanups * 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (56 commits) x86/cpu/tme: Fix spelling: "configuation" -> "configuration" x86/boot: Fix SEV boot failure from change to __PHYSICAL_MASK_SHIFT x86/mm: Update comment in detect_tme() regarding x86_phys_bits x86/mm/32: Remove unused node_memmap_size_bytes() & CONFIG_NEED_NODE_MEMMAP_SIZE logic x86/mm: Remove pointless checks in vmalloc_fault x86/platform/intel-mid: Add special handling for ACPI HW reduced platforms ACPI, x86/boot: Introduce the ->reduced_hw_early_init() ACPI callback ACPI, x86/boot: Split out acpi_generic_reduce_hw_init() and export x86/pconfig: Provide defines and helper to run MKTME_KEY_PROG leaf x86/pconfig: Detect PCONFIG targets x86/tme: Detect if TME and MKTME is activated by BIOS x86/boot/compressed/64: Handle 5-level paging boot if kernel is above 4G x86/boot/compressed/64: Use page table in trampoline memory x86/boot/compressed/64: Use stack from trampoline memory x86/boot/compressed/64: Make sure we have a 32-bit code segment x86/mm: Do not use paravirtualized calls in native_set_p4d() kdump, vmcoreinfo: Export pgtable_l5_enabled value x86/boot/compressed/64: Prepare new top-level page table for trampoline x86/boot/compressed/64: Set up trampoline memory x86/boot/compressed/64: Save and restore trampoline memory ...
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Kernel does not boot with instrumentation of tlb.c and mem_encrypt.c
|
||||
KCOV_INSTRUMENT_tlb.o := n
|
||||
KCOV_INSTRUMENT_mem_encrypt.o := n
|
||||
# Kernel does not boot with instrumentation of tlb.c and mem_encrypt*.c
|
||||
KCOV_INSTRUMENT_tlb.o := n
|
||||
KCOV_INSTRUMENT_mem_encrypt.o := n
|
||||
KCOV_INSTRUMENT_mem_encrypt_identity.o := n
|
||||
|
||||
KASAN_SANITIZE_mem_encrypt.o := n
|
||||
KASAN_SANITIZE_mem_encrypt.o := n
|
||||
KASAN_SANITIZE_mem_encrypt_identity.o := n
|
||||
|
||||
ifdef CONFIG_FUNCTION_TRACER
|
||||
CFLAGS_REMOVE_mem_encrypt.o = -pg
|
||||
CFLAGS_REMOVE_mem_encrypt.o = -pg
|
||||
CFLAGS_REMOVE_mem_encrypt_identity.o = -pg
|
||||
endif
|
||||
|
||||
obj-y := init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \
|
||||
@@ -16,6 +19,7 @@ obj-y := init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \
|
||||
nostackp := $(call cc-option, -fno-stack-protector)
|
||||
CFLAGS_physaddr.o := $(nostackp)
|
||||
CFLAGS_setup_nx.o := $(nostackp)
|
||||
CFLAGS_mem_encrypt_identity.o := $(nostackp)
|
||||
|
||||
CFLAGS_fault.o := -I$(src)/../include/asm/trace
|
||||
|
||||
@@ -47,4 +51,5 @@ obj-$(CONFIG_RANDOMIZE_MEMORY) += kaslr.o
|
||||
obj-$(CONFIG_PAGE_TABLE_ISOLATION) += pti.o
|
||||
|
||||
obj-$(CONFIG_AMD_MEM_ENCRYPT) += mem_encrypt.o
|
||||
obj-$(CONFIG_AMD_MEM_ENCRYPT) += mem_encrypt_identity.o
|
||||
obj-$(CONFIG_AMD_MEM_ENCRYPT) += mem_encrypt_boot.o
|
||||
|
@@ -72,6 +72,31 @@ static const struct file_operations ptdump_curusr_fops = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_EFI) && defined(CONFIG_X86_64)
|
||||
extern pgd_t *efi_pgd;
|
||||
static struct dentry *pe_efi;
|
||||
|
||||
static int ptdump_show_efi(struct seq_file *m, void *v)
|
||||
{
|
||||
if (efi_pgd)
|
||||
ptdump_walk_pgd_level_debugfs(m, efi_pgd, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ptdump_open_efi(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return single_open(filp, ptdump_show_efi, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations ptdump_efi_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ptdump_open_efi,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct dentry *dir, *pe_knl, *pe_curknl;
|
||||
|
||||
static int __init pt_dump_debug_init(void)
|
||||
@@ -96,6 +121,13 @@ static int __init pt_dump_debug_init(void)
|
||||
if (!pe_curusr)
|
||||
goto err;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_EFI) && defined(CONFIG_X86_64)
|
||||
pe_efi = debugfs_create_file("efi", 0400, dir, NULL, &ptdump_efi_fops);
|
||||
if (!pe_efi)
|
||||
goto err;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
err:
|
||||
debugfs_remove_recursive(dir);
|
||||
|
@@ -29,6 +29,7 @@
|
||||
struct pg_state {
|
||||
int level;
|
||||
pgprot_t current_prot;
|
||||
pgprotval_t effective_prot;
|
||||
unsigned long start_address;
|
||||
unsigned long current_address;
|
||||
const struct addr_marker *marker;
|
||||
@@ -85,11 +86,15 @@ static struct addr_marker address_markers[] = {
|
||||
[VMALLOC_START_NR] = { 0UL, "vmalloc() Area" },
|
||||
[VMEMMAP_START_NR] = { 0UL, "Vmemmap" },
|
||||
#ifdef CONFIG_KASAN
|
||||
[KASAN_SHADOW_START_NR] = { KASAN_SHADOW_START, "KASAN shadow" },
|
||||
[KASAN_SHADOW_END_NR] = { KASAN_SHADOW_END, "KASAN shadow end" },
|
||||
/*
|
||||
* These fields get initialized with the (dynamic)
|
||||
* KASAN_SHADOW_{START,END} values in pt_dump_init().
|
||||
*/
|
||||
[KASAN_SHADOW_START_NR] = { 0UL, "KASAN shadow" },
|
||||
[KASAN_SHADOW_END_NR] = { 0UL, "KASAN shadow end" },
|
||||
#endif
|
||||
#ifdef CONFIG_MODIFY_LDT_SYSCALL
|
||||
[LDT_NR] = { LDT_BASE_ADDR, "LDT remap" },
|
||||
[LDT_NR] = { 0UL, "LDT remap" },
|
||||
#endif
|
||||
[CPU_ENTRY_AREA_NR] = { CPU_ENTRY_AREA_BASE,"CPU entry Area" },
|
||||
#ifdef CONFIG_X86_ESPFIX64
|
||||
@@ -231,9 +236,9 @@ static unsigned long normalize_addr(unsigned long u)
|
||||
* print what we collected so far.
|
||||
*/
|
||||
static void note_page(struct seq_file *m, struct pg_state *st,
|
||||
pgprot_t new_prot, int level)
|
||||
pgprot_t new_prot, pgprotval_t new_eff, int level)
|
||||
{
|
||||
pgprotval_t prot, cur;
|
||||
pgprotval_t prot, cur, eff;
|
||||
static const char units[] = "BKMGTPE";
|
||||
|
||||
/*
|
||||
@@ -243,23 +248,24 @@ static void note_page(struct seq_file *m, struct pg_state *st,
|
||||
*/
|
||||
prot = pgprot_val(new_prot);
|
||||
cur = pgprot_val(st->current_prot);
|
||||
eff = st->effective_prot;
|
||||
|
||||
if (!st->level) {
|
||||
/* First entry */
|
||||
st->current_prot = new_prot;
|
||||
st->effective_prot = new_eff;
|
||||
st->level = level;
|
||||
st->marker = address_markers;
|
||||
st->lines = 0;
|
||||
pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
|
||||
st->marker->name);
|
||||
} else if (prot != cur || level != st->level ||
|
||||
} else if (prot != cur || new_eff != eff || level != st->level ||
|
||||
st->current_address >= st->marker[1].start_address) {
|
||||
const char *unit = units;
|
||||
unsigned long delta;
|
||||
int width = sizeof(unsigned long) * 2;
|
||||
pgprotval_t pr = pgprot_val(st->current_prot);
|
||||
|
||||
if (st->check_wx && (pr & _PAGE_RW) && !(pr & _PAGE_NX)) {
|
||||
if (st->check_wx && (eff & _PAGE_RW) && !(eff & _PAGE_NX)) {
|
||||
WARN_ONCE(1,
|
||||
"x86/mm: Found insecure W+X mapping at address %p/%pS\n",
|
||||
(void *)st->start_address,
|
||||
@@ -313,21 +319,30 @@ static void note_page(struct seq_file *m, struct pg_state *st,
|
||||
|
||||
st->start_address = st->current_address;
|
||||
st->current_prot = new_prot;
|
||||
st->effective_prot = new_eff;
|
||||
st->level = level;
|
||||
}
|
||||
}
|
||||
|
||||
static void walk_pte_level(struct seq_file *m, struct pg_state *st, pmd_t addr, unsigned long P)
|
||||
static inline pgprotval_t effective_prot(pgprotval_t prot1, pgprotval_t prot2)
|
||||
{
|
||||
return (prot1 & prot2 & (_PAGE_USER | _PAGE_RW)) |
|
||||
((prot1 | prot2) & _PAGE_NX);
|
||||
}
|
||||
|
||||
static void walk_pte_level(struct seq_file *m, struct pg_state *st, pmd_t addr,
|
||||
pgprotval_t eff_in, unsigned long P)
|
||||
{
|
||||
int i;
|
||||
pte_t *start;
|
||||
pgprotval_t prot;
|
||||
pgprotval_t prot, eff;
|
||||
|
||||
start = (pte_t *)pmd_page_vaddr(addr);
|
||||
for (i = 0; i < PTRS_PER_PTE; i++) {
|
||||
prot = pte_flags(*start);
|
||||
eff = effective_prot(eff_in, prot);
|
||||
st->current_address = normalize_addr(P + i * PTE_LEVEL_MULT);
|
||||
note_page(m, st, __pgprot(prot), 5);
|
||||
note_page(m, st, __pgprot(prot), eff, 5);
|
||||
start++;
|
||||
}
|
||||
}
|
||||
@@ -344,12 +359,10 @@ static inline bool kasan_page_table(struct seq_file *m, struct pg_state *st,
|
||||
void *pt)
|
||||
{
|
||||
if (__pa(pt) == __pa(kasan_zero_pmd) ||
|
||||
#ifdef CONFIG_X86_5LEVEL
|
||||
__pa(pt) == __pa(kasan_zero_p4d) ||
|
||||
#endif
|
||||
(pgtable_l5_enabled && __pa(pt) == __pa(kasan_zero_p4d)) ||
|
||||
__pa(pt) == __pa(kasan_zero_pud)) {
|
||||
pgprotval_t prot = pte_flags(kasan_zero_pte[0]);
|
||||
note_page(m, st, __pgprot(prot), 5);
|
||||
note_page(m, st, __pgprot(prot), 0, 5);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -364,42 +377,45 @@ static inline bool kasan_page_table(struct seq_file *m, struct pg_state *st,
|
||||
|
||||
#if PTRS_PER_PMD > 1
|
||||
|
||||
static void walk_pmd_level(struct seq_file *m, struct pg_state *st, pud_t addr, unsigned long P)
|
||||
static void walk_pmd_level(struct seq_file *m, struct pg_state *st, pud_t addr,
|
||||
pgprotval_t eff_in, unsigned long P)
|
||||
{
|
||||
int i;
|
||||
pmd_t *start, *pmd_start;
|
||||
pgprotval_t prot;
|
||||
pgprotval_t prot, eff;
|
||||
|
||||
pmd_start = start = (pmd_t *)pud_page_vaddr(addr);
|
||||
for (i = 0; i < PTRS_PER_PMD; i++) {
|
||||
st->current_address = normalize_addr(P + i * PMD_LEVEL_MULT);
|
||||
if (!pmd_none(*start)) {
|
||||
prot = pmd_flags(*start);
|
||||
eff = effective_prot(eff_in, prot);
|
||||
if (pmd_large(*start) || !pmd_present(*start)) {
|
||||
prot = pmd_flags(*start);
|
||||
note_page(m, st, __pgprot(prot), 4);
|
||||
note_page(m, st, __pgprot(prot), eff, 4);
|
||||
} else if (!kasan_page_table(m, st, pmd_start)) {
|
||||
walk_pte_level(m, st, *start,
|
||||
walk_pte_level(m, st, *start, eff,
|
||||
P + i * PMD_LEVEL_MULT);
|
||||
}
|
||||
} else
|
||||
note_page(m, st, __pgprot(0), 4);
|
||||
note_page(m, st, __pgprot(0), 0, 4);
|
||||
start++;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#define walk_pmd_level(m,s,a,p) walk_pte_level(m,s,__pmd(pud_val(a)),p)
|
||||
#define walk_pmd_level(m,s,a,e,p) walk_pte_level(m,s,__pmd(pud_val(a)),e,p)
|
||||
#define pud_large(a) pmd_large(__pmd(pud_val(a)))
|
||||
#define pud_none(a) pmd_none(__pmd(pud_val(a)))
|
||||
#endif
|
||||
|
||||
#if PTRS_PER_PUD > 1
|
||||
|
||||
static void walk_pud_level(struct seq_file *m, struct pg_state *st, p4d_t addr, unsigned long P)
|
||||
static void walk_pud_level(struct seq_file *m, struct pg_state *st, p4d_t addr,
|
||||
pgprotval_t eff_in, unsigned long P)
|
||||
{
|
||||
int i;
|
||||
pud_t *start, *pud_start;
|
||||
pgprotval_t prot;
|
||||
pgprotval_t prot, eff;
|
||||
pud_t *prev_pud = NULL;
|
||||
|
||||
pud_start = start = (pud_t *)p4d_page_vaddr(addr);
|
||||
@@ -407,15 +423,16 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, p4d_t addr,
|
||||
for (i = 0; i < PTRS_PER_PUD; i++) {
|
||||
st->current_address = normalize_addr(P + i * PUD_LEVEL_MULT);
|
||||
if (!pud_none(*start)) {
|
||||
prot = pud_flags(*start);
|
||||
eff = effective_prot(eff_in, prot);
|
||||
if (pud_large(*start) || !pud_present(*start)) {
|
||||
prot = pud_flags(*start);
|
||||
note_page(m, st, __pgprot(prot), 3);
|
||||
note_page(m, st, __pgprot(prot), eff, 3);
|
||||
} else if (!kasan_page_table(m, st, pud_start)) {
|
||||
walk_pmd_level(m, st, *start,
|
||||
walk_pmd_level(m, st, *start, eff,
|
||||
P + i * PUD_LEVEL_MULT);
|
||||
}
|
||||
} else
|
||||
note_page(m, st, __pgprot(0), 3);
|
||||
note_page(m, st, __pgprot(0), 0, 3);
|
||||
|
||||
prev_pud = start;
|
||||
start++;
|
||||
@@ -423,43 +440,43 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, p4d_t addr,
|
||||
}
|
||||
|
||||
#else
|
||||
#define walk_pud_level(m,s,a,p) walk_pmd_level(m,s,__pud(p4d_val(a)),p)
|
||||
#define walk_pud_level(m,s,a,e,p) walk_pmd_level(m,s,__pud(p4d_val(a)),e,p)
|
||||
#define p4d_large(a) pud_large(__pud(p4d_val(a)))
|
||||
#define p4d_none(a) pud_none(__pud(p4d_val(a)))
|
||||
#endif
|
||||
|
||||
#if PTRS_PER_P4D > 1
|
||||
|
||||
static void walk_p4d_level(struct seq_file *m, struct pg_state *st, pgd_t addr, unsigned long P)
|
||||
static void walk_p4d_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
|
||||
pgprotval_t eff_in, unsigned long P)
|
||||
{
|
||||
int i;
|
||||
p4d_t *start, *p4d_start;
|
||||
pgprotval_t prot;
|
||||
pgprotval_t prot, eff;
|
||||
|
||||
if (PTRS_PER_P4D == 1)
|
||||
return walk_pud_level(m, st, __p4d(pgd_val(addr)), eff_in, P);
|
||||
|
||||
p4d_start = start = (p4d_t *)pgd_page_vaddr(addr);
|
||||
|
||||
for (i = 0; i < PTRS_PER_P4D; i++) {
|
||||
st->current_address = normalize_addr(P + i * P4D_LEVEL_MULT);
|
||||
if (!p4d_none(*start)) {
|
||||
prot = p4d_flags(*start);
|
||||
eff = effective_prot(eff_in, prot);
|
||||
if (p4d_large(*start) || !p4d_present(*start)) {
|
||||
prot = p4d_flags(*start);
|
||||
note_page(m, st, __pgprot(prot), 2);
|
||||
note_page(m, st, __pgprot(prot), eff, 2);
|
||||
} else if (!kasan_page_table(m, st, p4d_start)) {
|
||||
walk_pud_level(m, st, *start,
|
||||
walk_pud_level(m, st, *start, eff,
|
||||
P + i * P4D_LEVEL_MULT);
|
||||
}
|
||||
} else
|
||||
note_page(m, st, __pgprot(0), 2);
|
||||
note_page(m, st, __pgprot(0), 0, 2);
|
||||
|
||||
start++;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#define walk_p4d_level(m,s,a,p) walk_pud_level(m,s,__p4d(pgd_val(a)),p)
|
||||
#define pgd_large(a) p4d_large(__p4d(pgd_val(a)))
|
||||
#define pgd_none(a) p4d_none(__p4d(pgd_val(a)))
|
||||
#endif
|
||||
#define pgd_large(a) (pgtable_l5_enabled ? pgd_large(a) : p4d_large(__p4d(pgd_val(a))))
|
||||
#define pgd_none(a) (pgtable_l5_enabled ? pgd_none(a) : p4d_none(__p4d(pgd_val(a))))
|
||||
|
||||
static inline bool is_hypervisor_range(int idx)
|
||||
{
|
||||
@@ -483,7 +500,7 @@ static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd,
|
||||
#else
|
||||
pgd_t *start = swapper_pg_dir;
|
||||
#endif
|
||||
pgprotval_t prot;
|
||||
pgprotval_t prot, eff;
|
||||
int i;
|
||||
struct pg_state st = {};
|
||||
|
||||
@@ -499,15 +516,20 @@ static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd,
|
||||
for (i = 0; i < PTRS_PER_PGD; i++) {
|
||||
st.current_address = normalize_addr(i * PGD_LEVEL_MULT);
|
||||
if (!pgd_none(*start) && !is_hypervisor_range(i)) {
|
||||
prot = pgd_flags(*start);
|
||||
#ifdef CONFIG_X86_PAE
|
||||
eff = _PAGE_USER | _PAGE_RW;
|
||||
#else
|
||||
eff = prot;
|
||||
#endif
|
||||
if (pgd_large(*start) || !pgd_present(*start)) {
|
||||
prot = pgd_flags(*start);
|
||||
note_page(m, &st, __pgprot(prot), 1);
|
||||
note_page(m, &st, __pgprot(prot), eff, 1);
|
||||
} else {
|
||||
walk_p4d_level(m, &st, *start,
|
||||
walk_p4d_level(m, &st, *start, eff,
|
||||
i * PGD_LEVEL_MULT);
|
||||
}
|
||||
} else
|
||||
note_page(m, &st, __pgprot(0), 1);
|
||||
note_page(m, &st, __pgprot(0), 0, 1);
|
||||
|
||||
cond_resched();
|
||||
start++;
|
||||
@@ -515,7 +537,7 @@ static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd,
|
||||
|
||||
/* Flush out the last page */
|
||||
st.current_address = normalize_addr(PTRS_PER_PGD*PGD_LEVEL_MULT);
|
||||
note_page(m, &st, __pgprot(0), 0);
|
||||
note_page(m, &st, __pgprot(0), 0, 0);
|
||||
if (!checkwx)
|
||||
return;
|
||||
if (st.wx_pages)
|
||||
@@ -570,6 +592,13 @@ static int __init pt_dump_init(void)
|
||||
address_markers[LOW_KERNEL_NR].start_address = PAGE_OFFSET;
|
||||
address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
|
||||
address_markers[VMEMMAP_START_NR].start_address = VMEMMAP_START;
|
||||
#ifdef CONFIG_MODIFY_LDT_SYSCALL
|
||||
address_markers[LDT_NR].start_address = LDT_BASE_ADDR;
|
||||
#endif
|
||||
#ifdef CONFIG_KASAN
|
||||
address_markers[KASAN_SHADOW_START_NR].start_address = KASAN_SHADOW_START;
|
||||
address_markers[KASAN_SHADOW_END_NR].start_address = KASAN_SHADOW_END;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_X86_32
|
||||
address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
|
||||
|
@@ -417,11 +417,11 @@ void vmalloc_sync_all(void)
|
||||
*/
|
||||
static noinline int vmalloc_fault(unsigned long address)
|
||||
{
|
||||
pgd_t *pgd, *pgd_ref;
|
||||
p4d_t *p4d, *p4d_ref;
|
||||
pud_t *pud, *pud_ref;
|
||||
pmd_t *pmd, *pmd_ref;
|
||||
pte_t *pte, *pte_ref;
|
||||
pgd_t *pgd, *pgd_k;
|
||||
p4d_t *p4d, *p4d_k;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
|
||||
/* Make sure we are in vmalloc area: */
|
||||
if (!(address >= VMALLOC_START && address < VMALLOC_END))
|
||||
@@ -435,73 +435,51 @@ static noinline int vmalloc_fault(unsigned long address)
|
||||
* case just flush:
|
||||
*/
|
||||
pgd = (pgd_t *)__va(read_cr3_pa()) + pgd_index(address);
|
||||
pgd_ref = pgd_offset_k(address);
|
||||
if (pgd_none(*pgd_ref))
|
||||
pgd_k = pgd_offset_k(address);
|
||||
if (pgd_none(*pgd_k))
|
||||
return -1;
|
||||
|
||||
if (CONFIG_PGTABLE_LEVELS > 4) {
|
||||
if (pgtable_l5_enabled) {
|
||||
if (pgd_none(*pgd)) {
|
||||
set_pgd(pgd, *pgd_ref);
|
||||
set_pgd(pgd, *pgd_k);
|
||||
arch_flush_lazy_mmu_mode();
|
||||
} else {
|
||||
BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
|
||||
BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_k));
|
||||
}
|
||||
}
|
||||
|
||||
/* With 4-level paging, copying happens on the p4d level. */
|
||||
p4d = p4d_offset(pgd, address);
|
||||
p4d_ref = p4d_offset(pgd_ref, address);
|
||||
if (p4d_none(*p4d_ref))
|
||||
p4d_k = p4d_offset(pgd_k, address);
|
||||
if (p4d_none(*p4d_k))
|
||||
return -1;
|
||||
|
||||
if (p4d_none(*p4d) && CONFIG_PGTABLE_LEVELS == 4) {
|
||||
set_p4d(p4d, *p4d_ref);
|
||||
if (p4d_none(*p4d) && !pgtable_l5_enabled) {
|
||||
set_p4d(p4d, *p4d_k);
|
||||
arch_flush_lazy_mmu_mode();
|
||||
} else {
|
||||
BUG_ON(p4d_pfn(*p4d) != p4d_pfn(*p4d_ref));
|
||||
BUG_ON(p4d_pfn(*p4d) != p4d_pfn(*p4d_k));
|
||||
}
|
||||
|
||||
/*
|
||||
* Below here mismatches are bugs because these lower tables
|
||||
* are shared:
|
||||
*/
|
||||
BUILD_BUG_ON(CONFIG_PGTABLE_LEVELS < 4);
|
||||
|
||||
pud = pud_offset(p4d, address);
|
||||
pud_ref = pud_offset(p4d_ref, address);
|
||||
if (pud_none(*pud_ref))
|
||||
if (pud_none(*pud))
|
||||
return -1;
|
||||
|
||||
if (pud_none(*pud) || pud_pfn(*pud) != pud_pfn(*pud_ref))
|
||||
BUG();
|
||||
|
||||
if (pud_large(*pud))
|
||||
return 0;
|
||||
|
||||
pmd = pmd_offset(pud, address);
|
||||
pmd_ref = pmd_offset(pud_ref, address);
|
||||
if (pmd_none(*pmd_ref))
|
||||
if (pmd_none(*pmd))
|
||||
return -1;
|
||||
|
||||
if (pmd_none(*pmd) || pmd_pfn(*pmd) != pmd_pfn(*pmd_ref))
|
||||
BUG();
|
||||
|
||||
if (pmd_large(*pmd))
|
||||
return 0;
|
||||
|
||||
pte_ref = pte_offset_kernel(pmd_ref, address);
|
||||
if (!pte_present(*pte_ref))
|
||||
return -1;
|
||||
|
||||
pte = pte_offset_kernel(pmd, address);
|
||||
|
||||
/*
|
||||
* Don't use pte_page here, because the mappings can point
|
||||
* outside mem_map, and the NUMA hash lookup cannot handle
|
||||
* that:
|
||||
*/
|
||||
if (!pte_present(*pte) || pte_pfn(*pte) != pte_pfn(*pte_ref))
|
||||
BUG();
|
||||
if (!pte_present(*pte))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -120,7 +120,7 @@ int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
|
||||
result = ident_p4d_init(info, p4d, addr, next);
|
||||
if (result)
|
||||
return result;
|
||||
if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
|
||||
if (pgtable_l5_enabled) {
|
||||
set_pgd(pgd, __pgd(__pa(p4d) | info->kernpg_flag));
|
||||
} else {
|
||||
/*
|
||||
|
@@ -88,12 +88,7 @@ static int __init nonx32_setup(char *str)
|
||||
}
|
||||
__setup("noexec32=", nonx32_setup);
|
||||
|
||||
/*
|
||||
* When memory was added make sure all the processes MM have
|
||||
* suitable PGD entries in the local PGD level page.
|
||||
*/
|
||||
#ifdef CONFIG_X86_5LEVEL
|
||||
void sync_global_pgds(unsigned long start, unsigned long end)
|
||||
static void sync_global_pgds_l5(unsigned long start, unsigned long end)
|
||||
{
|
||||
unsigned long addr;
|
||||
|
||||
@@ -129,8 +124,8 @@ void sync_global_pgds(unsigned long start, unsigned long end)
|
||||
spin_unlock(&pgd_lock);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void sync_global_pgds(unsigned long start, unsigned long end)
|
||||
|
||||
static void sync_global_pgds_l4(unsigned long start, unsigned long end)
|
||||
{
|
||||
unsigned long addr;
|
||||
|
||||
@@ -143,7 +138,7 @@ void sync_global_pgds(unsigned long start, unsigned long end)
|
||||
* With folded p4d, pgd_none() is always false, we need to
|
||||
* handle synchonization on p4d level.
|
||||
*/
|
||||
BUILD_BUG_ON(pgd_none(*pgd_ref));
|
||||
MAYBE_BUILD_BUG_ON(pgd_none(*pgd_ref));
|
||||
p4d_ref = p4d_offset(pgd_ref, addr);
|
||||
|
||||
if (p4d_none(*p4d_ref))
|
||||
@@ -173,7 +168,18 @@ void sync_global_pgds(unsigned long start, unsigned long end)
|
||||
spin_unlock(&pgd_lock);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When memory was added make sure all the processes MM have
|
||||
* suitable PGD entries in the local PGD level page.
|
||||
*/
|
||||
void sync_global_pgds(unsigned long start, unsigned long end)
|
||||
{
|
||||
if (pgtable_l5_enabled)
|
||||
sync_global_pgds_l5(start, end);
|
||||
else
|
||||
sync_global_pgds_l4(start, end);
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: This function is marked __ref because it calls __init function
|
||||
@@ -632,7 +638,7 @@ phys_p4d_init(p4d_t *p4d_page, unsigned long paddr, unsigned long paddr_end,
|
||||
unsigned long vaddr = (unsigned long)__va(paddr);
|
||||
int i = p4d_index(vaddr);
|
||||
|
||||
if (!IS_ENABLED(CONFIG_X86_5LEVEL))
|
||||
if (!pgtable_l5_enabled)
|
||||
return phys_pud_init((pud_t *) p4d_page, paddr, paddr_end, page_size_mask);
|
||||
|
||||
for (; i < PTRS_PER_P4D; i++, paddr = paddr_next) {
|
||||
@@ -712,7 +718,7 @@ kernel_physical_mapping_init(unsigned long paddr_start,
|
||||
page_size_mask);
|
||||
|
||||
spin_lock(&init_mm.page_table_lock);
|
||||
if (IS_ENABLED(CONFIG_X86_5LEVEL))
|
||||
if (pgtable_l5_enabled)
|
||||
pgd_populate(&init_mm, pgd, p4d);
|
||||
else
|
||||
p4d_populate(&init_mm, p4d_offset(pgd, vaddr), (pud_t *) p4d);
|
||||
@@ -1089,7 +1095,7 @@ remove_p4d_table(p4d_t *p4d_start, unsigned long addr, unsigned long end,
|
||||
* 5-level case we should free them. This code will have to change
|
||||
* to adapt for boot-time switching between 4 and 5 level page tables.
|
||||
*/
|
||||
if (CONFIG_PGTABLE_LEVELS == 5)
|
||||
if (pgtable_l5_enabled)
|
||||
free_pud_table(pud_base, p4d);
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#define DISABLE_BRANCH_PROFILING
|
||||
#define pr_fmt(fmt) "kasan: " fmt
|
||||
|
||||
#ifdef CONFIG_X86_5LEVEL
|
||||
/* Too early to use cpu_feature_enabled() */
|
||||
#define pgtable_l5_enabled __pgtable_l5_enabled
|
||||
#endif
|
||||
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/kasan.h>
|
||||
#include <linux/kdebug.h>
|
||||
@@ -19,7 +25,7 @@
|
||||
|
||||
extern struct range pfn_mapped[E820_MAX_ENTRIES];
|
||||
|
||||
static p4d_t tmp_p4d_table[PTRS_PER_P4D] __initdata __aligned(PAGE_SIZE);
|
||||
static p4d_t tmp_p4d_table[MAX_PTRS_PER_P4D] __initdata __aligned(PAGE_SIZE);
|
||||
|
||||
static __init void *early_alloc(size_t size, int nid, bool panic)
|
||||
{
|
||||
@@ -176,10 +182,10 @@ static void __init clear_pgds(unsigned long start,
|
||||
* With folded p4d, pgd_clear() is nop, use p4d_clear()
|
||||
* instead.
|
||||
*/
|
||||
if (CONFIG_PGTABLE_LEVELS < 5)
|
||||
p4d_clear(p4d_offset(pgd, start));
|
||||
else
|
||||
if (pgtable_l5_enabled)
|
||||
pgd_clear(pgd);
|
||||
else
|
||||
p4d_clear(p4d_offset(pgd, start));
|
||||
}
|
||||
|
||||
pgd = pgd_offset_k(start);
|
||||
@@ -191,7 +197,7 @@ static inline p4d_t *early_p4d_offset(pgd_t *pgd, unsigned long addr)
|
||||
{
|
||||
unsigned long p4d;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_X86_5LEVEL))
|
||||
if (!pgtable_l5_enabled)
|
||||
return (p4d_t *)pgd;
|
||||
|
||||
p4d = __pa_nodebug(pgd_val(*pgd)) & PTE_PFN_MASK;
|
||||
@@ -272,7 +278,7 @@ void __init kasan_early_init(void)
|
||||
for (i = 0; i < PTRS_PER_PUD; i++)
|
||||
kasan_zero_pud[i] = __pud(pud_val);
|
||||
|
||||
for (i = 0; IS_ENABLED(CONFIG_X86_5LEVEL) && i < PTRS_PER_P4D; i++)
|
||||
for (i = 0; pgtable_l5_enabled && i < PTRS_PER_P4D; i++)
|
||||
kasan_zero_p4d[i] = __p4d(p4d_val);
|
||||
|
||||
kasan_map_early_shadow(early_top_pgt);
|
||||
@@ -303,7 +309,7 @@ void __init kasan_init(void)
|
||||
* bunch of things like kernel code, modules, EFI mapping, etc.
|
||||
* We need to take extra steps to not overwrite them.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
|
||||
if (pgtable_l5_enabled) {
|
||||
void *ptr;
|
||||
|
||||
ptr = (void *)pgd_page_vaddr(*pgd_offset_k(KASAN_SHADOW_END));
|
||||
|
@@ -34,23 +34,12 @@
|
||||
#define TB_SHIFT 40
|
||||
|
||||
/*
|
||||
* Virtual address start and end range for randomization.
|
||||
*
|
||||
* The end address could depend on more configuration options to make the
|
||||
* highest amount of space for randomization available, but that's too hard
|
||||
* to keep straight and caused issues already.
|
||||
*/
|
||||
static const unsigned long vaddr_start = __PAGE_OFFSET_BASE;
|
||||
static const unsigned long vaddr_end = CPU_ENTRY_AREA_BASE;
|
||||
|
||||
/* Default values */
|
||||
unsigned long page_offset_base = __PAGE_OFFSET_BASE;
|
||||
EXPORT_SYMBOL(page_offset_base);
|
||||
unsigned long vmalloc_base = __VMALLOC_BASE;
|
||||
EXPORT_SYMBOL(vmalloc_base);
|
||||
unsigned long vmemmap_base = __VMEMMAP_BASE;
|
||||
EXPORT_SYMBOL(vmemmap_base);
|
||||
|
||||
/*
|
||||
* Memory regions randomized by KASLR (except modules that use a separate logic
|
||||
* earlier during boot). The list is ordered based on virtual addresses. This
|
||||
@@ -60,8 +49,8 @@ static __initdata struct kaslr_memory_region {
|
||||
unsigned long *base;
|
||||
unsigned long size_tb;
|
||||
} kaslr_regions[] = {
|
||||
{ &page_offset_base, 1 << (__PHYSICAL_MASK_SHIFT - TB_SHIFT) /* Maximum */ },
|
||||
{ &vmalloc_base, VMALLOC_SIZE_TB },
|
||||
{ &page_offset_base, 0 },
|
||||
{ &vmalloc_base, 0 },
|
||||
{ &vmemmap_base, 1 },
|
||||
};
|
||||
|
||||
@@ -84,11 +73,14 @@ static inline bool kaslr_memory_enabled(void)
|
||||
void __init kernel_randomize_memory(void)
|
||||
{
|
||||
size_t i;
|
||||
unsigned long vaddr = vaddr_start;
|
||||
unsigned long vaddr_start, vaddr;
|
||||
unsigned long rand, memory_tb;
|
||||
struct rnd_state rand_state;
|
||||
unsigned long remain_entropy;
|
||||
|
||||
vaddr_start = pgtable_l5_enabled ? __PAGE_OFFSET_BASE_L5 : __PAGE_OFFSET_BASE_L4;
|
||||
vaddr = vaddr_start;
|
||||
|
||||
/*
|
||||
* These BUILD_BUG_ON checks ensure the memory layout is consistent
|
||||
* with the vaddr_start/vaddr_end variables. These checks are very
|
||||
@@ -101,6 +93,9 @@ void __init kernel_randomize_memory(void)
|
||||
if (!kaslr_memory_enabled())
|
||||
return;
|
||||
|
||||
kaslr_regions[0].size_tb = 1 << (__PHYSICAL_MASK_SHIFT - TB_SHIFT);
|
||||
kaslr_regions[1].size_tb = VMALLOC_SIZE_TB;
|
||||
|
||||
/*
|
||||
* Update Physical memory mapping to available and
|
||||
* add padding if needed (especially for memory hotplug support).
|
||||
@@ -129,7 +124,7 @@ void __init kernel_randomize_memory(void)
|
||||
*/
|
||||
entropy = remain_entropy / (ARRAY_SIZE(kaslr_regions) - i);
|
||||
prandom_bytes_state(&rand_state, &rand, sizeof(rand));
|
||||
if (IS_ENABLED(CONFIG_X86_5LEVEL))
|
||||
if (pgtable_l5_enabled)
|
||||
entropy = (rand % (entropy + 1)) & P4D_MASK;
|
||||
else
|
||||
entropy = (rand % (entropy + 1)) & PUD_MASK;
|
||||
@@ -141,7 +136,7 @@ void __init kernel_randomize_memory(void)
|
||||
* randomization alignment.
|
||||
*/
|
||||
vaddr += get_padding(&kaslr_regions[i]);
|
||||
if (IS_ENABLED(CONFIG_X86_5LEVEL))
|
||||
if (pgtable_l5_enabled)
|
||||
vaddr = round_up(vaddr + 1, P4D_SIZE);
|
||||
else
|
||||
vaddr = round_up(vaddr + 1, PUD_SIZE);
|
||||
@@ -217,7 +212,7 @@ void __meminit init_trampoline(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_X86_5LEVEL))
|
||||
if (pgtable_l5_enabled)
|
||||
init_trampoline_p4d();
|
||||
else
|
||||
init_trampoline_pud();
|
||||
|
@@ -25,17 +25,12 @@
|
||||
#include <asm/bootparam.h>
|
||||
#include <asm/set_memory.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/processor-flags.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/cmdline.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
|
||||
static char sme_cmdline_arg[] __initdata = "mem_encrypt";
|
||||
static char sme_cmdline_on[] __initdata = "on";
|
||||
static char sme_cmdline_off[] __initdata = "off";
|
||||
|
||||
/*
|
||||
* Since SME related variables are set early in the boot process they must
|
||||
* reside in the .data section so as not to be zeroed out when the .bss
|
||||
@@ -46,7 +41,7 @@ EXPORT_SYMBOL(sme_me_mask);
|
||||
DEFINE_STATIC_KEY_FALSE(sev_enable_key);
|
||||
EXPORT_SYMBOL_GPL(sev_enable_key);
|
||||
|
||||
static bool sev_enabled __section(.data);
|
||||
bool sev_enabled __section(.data);
|
||||
|
||||
/* Buffer used for early in-place encryption by BSP, no locking needed */
|
||||
static char sme_early_buffer[PAGE_SIZE] __aligned(PAGE_SIZE);
|
||||
@@ -463,574 +458,3 @@ void swiotlb_set_mem_attributes(void *vaddr, unsigned long size)
|
||||
/* Make the SWIOTLB buffer area decrypted */
|
||||
set_memory_decrypted((unsigned long)vaddr, size >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
struct sme_populate_pgd_data {
|
||||
void *pgtable_area;
|
||||
pgd_t *pgd;
|
||||
|
||||
pmdval_t pmd_flags;
|
||||
pteval_t pte_flags;
|
||||
unsigned long paddr;
|
||||
|
||||
unsigned long vaddr;
|
||||
unsigned long vaddr_end;
|
||||
};
|
||||
|
||||
static void __init sme_clear_pgd(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
unsigned long pgd_start, pgd_end, pgd_size;
|
||||
pgd_t *pgd_p;
|
||||
|
||||
pgd_start = ppd->vaddr & PGDIR_MASK;
|
||||
pgd_end = ppd->vaddr_end & PGDIR_MASK;
|
||||
|
||||
pgd_size = (((pgd_end - pgd_start) / PGDIR_SIZE) + 1) * sizeof(pgd_t);
|
||||
|
||||
pgd_p = ppd->pgd + pgd_index(ppd->vaddr);
|
||||
|
||||
memset(pgd_p, 0, pgd_size);
|
||||
}
|
||||
|
||||
#define PGD_FLAGS _KERNPG_TABLE_NOENC
|
||||
#define P4D_FLAGS _KERNPG_TABLE_NOENC
|
||||
#define PUD_FLAGS _KERNPG_TABLE_NOENC
|
||||
#define PMD_FLAGS _KERNPG_TABLE_NOENC
|
||||
|
||||
#define PMD_FLAGS_LARGE (__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL)
|
||||
|
||||
#define PMD_FLAGS_DEC PMD_FLAGS_LARGE
|
||||
#define PMD_FLAGS_DEC_WP ((PMD_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \
|
||||
(_PAGE_PAT | _PAGE_PWT))
|
||||
|
||||
#define PMD_FLAGS_ENC (PMD_FLAGS_LARGE | _PAGE_ENC)
|
||||
|
||||
#define PTE_FLAGS (__PAGE_KERNEL_EXEC & ~_PAGE_GLOBAL)
|
||||
|
||||
#define PTE_FLAGS_DEC PTE_FLAGS
|
||||
#define PTE_FLAGS_DEC_WP ((PTE_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \
|
||||
(_PAGE_PAT | _PAGE_PWT))
|
||||
|
||||
#define PTE_FLAGS_ENC (PTE_FLAGS | _PAGE_ENC)
|
||||
|
||||
static pmd_t __init *sme_prepare_pgd(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
pgd_t *pgd_p;
|
||||
p4d_t *p4d_p;
|
||||
pud_t *pud_p;
|
||||
pmd_t *pmd_p;
|
||||
|
||||
pgd_p = ppd->pgd + pgd_index(ppd->vaddr);
|
||||
if (native_pgd_val(*pgd_p)) {
|
||||
if (IS_ENABLED(CONFIG_X86_5LEVEL))
|
||||
p4d_p = (p4d_t *)(native_pgd_val(*pgd_p) & ~PTE_FLAGS_MASK);
|
||||
else
|
||||
pud_p = (pud_t *)(native_pgd_val(*pgd_p) & ~PTE_FLAGS_MASK);
|
||||
} else {
|
||||
pgd_t pgd;
|
||||
|
||||
if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
|
||||
p4d_p = ppd->pgtable_area;
|
||||
memset(p4d_p, 0, sizeof(*p4d_p) * PTRS_PER_P4D);
|
||||
ppd->pgtable_area += sizeof(*p4d_p) * PTRS_PER_P4D;
|
||||
|
||||
pgd = native_make_pgd((pgdval_t)p4d_p + PGD_FLAGS);
|
||||
} else {
|
||||
pud_p = ppd->pgtable_area;
|
||||
memset(pud_p, 0, sizeof(*pud_p) * PTRS_PER_PUD);
|
||||
ppd->pgtable_area += sizeof(*pud_p) * PTRS_PER_PUD;
|
||||
|
||||
pgd = native_make_pgd((pgdval_t)pud_p + PGD_FLAGS);
|
||||
}
|
||||
native_set_pgd(pgd_p, pgd);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
|
||||
p4d_p += p4d_index(ppd->vaddr);
|
||||
if (native_p4d_val(*p4d_p)) {
|
||||
pud_p = (pud_t *)(native_p4d_val(*p4d_p) & ~PTE_FLAGS_MASK);
|
||||
} else {
|
||||
p4d_t p4d;
|
||||
|
||||
pud_p = ppd->pgtable_area;
|
||||
memset(pud_p, 0, sizeof(*pud_p) * PTRS_PER_PUD);
|
||||
ppd->pgtable_area += sizeof(*pud_p) * PTRS_PER_PUD;
|
||||
|
||||
p4d = native_make_p4d((pudval_t)pud_p + P4D_FLAGS);
|
||||
native_set_p4d(p4d_p, p4d);
|
||||
}
|
||||
}
|
||||
|
||||
pud_p += pud_index(ppd->vaddr);
|
||||
if (native_pud_val(*pud_p)) {
|
||||
if (native_pud_val(*pud_p) & _PAGE_PSE)
|
||||
return NULL;
|
||||
|
||||
pmd_p = (pmd_t *)(native_pud_val(*pud_p) & ~PTE_FLAGS_MASK);
|
||||
} else {
|
||||
pud_t pud;
|
||||
|
||||
pmd_p = ppd->pgtable_area;
|
||||
memset(pmd_p, 0, sizeof(*pmd_p) * PTRS_PER_PMD);
|
||||
ppd->pgtable_area += sizeof(*pmd_p) * PTRS_PER_PMD;
|
||||
|
||||
pud = native_make_pud((pmdval_t)pmd_p + PUD_FLAGS);
|
||||
native_set_pud(pud_p, pud);
|
||||
}
|
||||
|
||||
return pmd_p;
|
||||
}
|
||||
|
||||
static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
pmd_t *pmd_p;
|
||||
|
||||
pmd_p = sme_prepare_pgd(ppd);
|
||||
if (!pmd_p)
|
||||
return;
|
||||
|
||||
pmd_p += pmd_index(ppd->vaddr);
|
||||
if (!native_pmd_val(*pmd_p) || !(native_pmd_val(*pmd_p) & _PAGE_PSE))
|
||||
native_set_pmd(pmd_p, native_make_pmd(ppd->paddr | ppd->pmd_flags));
|
||||
}
|
||||
|
||||
static void __init sme_populate_pgd(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
pmd_t *pmd_p;
|
||||
pte_t *pte_p;
|
||||
|
||||
pmd_p = sme_prepare_pgd(ppd);
|
||||
if (!pmd_p)
|
||||
return;
|
||||
|
||||
pmd_p += pmd_index(ppd->vaddr);
|
||||
if (native_pmd_val(*pmd_p)) {
|
||||
if (native_pmd_val(*pmd_p) & _PAGE_PSE)
|
||||
return;
|
||||
|
||||
pte_p = (pte_t *)(native_pmd_val(*pmd_p) & ~PTE_FLAGS_MASK);
|
||||
} else {
|
||||
pmd_t pmd;
|
||||
|
||||
pte_p = ppd->pgtable_area;
|
||||
memset(pte_p, 0, sizeof(*pte_p) * PTRS_PER_PTE);
|
||||
ppd->pgtable_area += sizeof(*pte_p) * PTRS_PER_PTE;
|
||||
|
||||
pmd = native_make_pmd((pteval_t)pte_p + PMD_FLAGS);
|
||||
native_set_pmd(pmd_p, pmd);
|
||||
}
|
||||
|
||||
pte_p += pte_index(ppd->vaddr);
|
||||
if (!native_pte_val(*pte_p))
|
||||
native_set_pte(pte_p, native_make_pte(ppd->paddr | ppd->pte_flags));
|
||||
}
|
||||
|
||||
static void __init __sme_map_range_pmd(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
while (ppd->vaddr < ppd->vaddr_end) {
|
||||
sme_populate_pgd_large(ppd);
|
||||
|
||||
ppd->vaddr += PMD_PAGE_SIZE;
|
||||
ppd->paddr += PMD_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void __init __sme_map_range_pte(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
while (ppd->vaddr < ppd->vaddr_end) {
|
||||
sme_populate_pgd(ppd);
|
||||
|
||||
ppd->vaddr += PAGE_SIZE;
|
||||
ppd->paddr += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void __init __sme_map_range(struct sme_populate_pgd_data *ppd,
|
||||
pmdval_t pmd_flags, pteval_t pte_flags)
|
||||
{
|
||||
unsigned long vaddr_end;
|
||||
|
||||
ppd->pmd_flags = pmd_flags;
|
||||
ppd->pte_flags = pte_flags;
|
||||
|
||||
/* Save original end value since we modify the struct value */
|
||||
vaddr_end = ppd->vaddr_end;
|
||||
|
||||
/* If start is not 2MB aligned, create PTE entries */
|
||||
ppd->vaddr_end = ALIGN(ppd->vaddr, PMD_PAGE_SIZE);
|
||||
__sme_map_range_pte(ppd);
|
||||
|
||||
/* Create PMD entries */
|
||||
ppd->vaddr_end = vaddr_end & PMD_PAGE_MASK;
|
||||
__sme_map_range_pmd(ppd);
|
||||
|
||||
/* If end is not 2MB aligned, create PTE entries */
|
||||
ppd->vaddr_end = vaddr_end;
|
||||
__sme_map_range_pte(ppd);
|
||||
}
|
||||
|
||||
static void __init sme_map_range_encrypted(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
__sme_map_range(ppd, PMD_FLAGS_ENC, PTE_FLAGS_ENC);
|
||||
}
|
||||
|
||||
static void __init sme_map_range_decrypted(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
__sme_map_range(ppd, PMD_FLAGS_DEC, PTE_FLAGS_DEC);
|
||||
}
|
||||
|
||||
static void __init sme_map_range_decrypted_wp(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
__sme_map_range(ppd, PMD_FLAGS_DEC_WP, PTE_FLAGS_DEC_WP);
|
||||
}
|
||||
|
||||
static unsigned long __init sme_pgtable_calc(unsigned long len)
|
||||
{
|
||||
unsigned long p4d_size, pud_size, pmd_size, pte_size;
|
||||
unsigned long total;
|
||||
|
||||
/*
|
||||
* Perform a relatively simplistic calculation of the pagetable
|
||||
* entries that are needed. Those mappings will be covered mostly
|
||||
* by 2MB PMD entries so we can conservatively calculate the required
|
||||
* number of P4D, PUD and PMD structures needed to perform the
|
||||
* mappings. For mappings that are not 2MB aligned, PTE mappings
|
||||
* would be needed for the start and end portion of the address range
|
||||
* that fall outside of the 2MB alignment. This results in, at most,
|
||||
* two extra pages to hold PTE entries for each range that is mapped.
|
||||
* Incrementing the count for each covers the case where the addresses
|
||||
* cross entries.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
|
||||
p4d_size = (ALIGN(len, PGDIR_SIZE) / PGDIR_SIZE) + 1;
|
||||
p4d_size *= sizeof(p4d_t) * PTRS_PER_P4D;
|
||||
pud_size = (ALIGN(len, P4D_SIZE) / P4D_SIZE) + 1;
|
||||
pud_size *= sizeof(pud_t) * PTRS_PER_PUD;
|
||||
} else {
|
||||
p4d_size = 0;
|
||||
pud_size = (ALIGN(len, PGDIR_SIZE) / PGDIR_SIZE) + 1;
|
||||
pud_size *= sizeof(pud_t) * PTRS_PER_PUD;
|
||||
}
|
||||
pmd_size = (ALIGN(len, PUD_SIZE) / PUD_SIZE) + 1;
|
||||
pmd_size *= sizeof(pmd_t) * PTRS_PER_PMD;
|
||||
pte_size = 2 * sizeof(pte_t) * PTRS_PER_PTE;
|
||||
|
||||
total = p4d_size + pud_size + pmd_size + pte_size;
|
||||
|
||||
/*
|
||||
* Now calculate the added pagetable structures needed to populate
|
||||
* the new pagetables.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
|
||||
p4d_size = ALIGN(total, PGDIR_SIZE) / PGDIR_SIZE;
|
||||
p4d_size *= sizeof(p4d_t) * PTRS_PER_P4D;
|
||||
pud_size = ALIGN(total, P4D_SIZE) / P4D_SIZE;
|
||||
pud_size *= sizeof(pud_t) * PTRS_PER_PUD;
|
||||
} else {
|
||||
p4d_size = 0;
|
||||
pud_size = ALIGN(total, PGDIR_SIZE) / PGDIR_SIZE;
|
||||
pud_size *= sizeof(pud_t) * PTRS_PER_PUD;
|
||||
}
|
||||
pmd_size = ALIGN(total, PUD_SIZE) / PUD_SIZE;
|
||||
pmd_size *= sizeof(pmd_t) * PTRS_PER_PMD;
|
||||
|
||||
total += p4d_size + pud_size + pmd_size;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void __init __nostackprotector sme_encrypt_kernel(struct boot_params *bp)
|
||||
{
|
||||
unsigned long workarea_start, workarea_end, workarea_len;
|
||||
unsigned long execute_start, execute_end, execute_len;
|
||||
unsigned long kernel_start, kernel_end, kernel_len;
|
||||
unsigned long initrd_start, initrd_end, initrd_len;
|
||||
struct sme_populate_pgd_data ppd;
|
||||
unsigned long pgtable_area_len;
|
||||
unsigned long decrypted_base;
|
||||
|
||||
if (!sme_active())
|
||||
return;
|
||||
|
||||
/*
|
||||
* Prepare for encrypting the kernel and initrd by building new
|
||||
* pagetables with the necessary attributes needed to encrypt the
|
||||
* kernel in place.
|
||||
*
|
||||
* One range of virtual addresses will map the memory occupied
|
||||
* by the kernel and initrd as encrypted.
|
||||
*
|
||||
* Another range of virtual addresses will map the memory occupied
|
||||
* by the kernel and initrd as decrypted and write-protected.
|
||||
*
|
||||
* The use of write-protect attribute will prevent any of the
|
||||
* memory from being cached.
|
||||
*/
|
||||
|
||||
/* Physical addresses gives us the identity mapped virtual addresses */
|
||||
kernel_start = __pa_symbol(_text);
|
||||
kernel_end = ALIGN(__pa_symbol(_end), PMD_PAGE_SIZE);
|
||||
kernel_len = kernel_end - kernel_start;
|
||||
|
||||
initrd_start = 0;
|
||||
initrd_end = 0;
|
||||
initrd_len = 0;
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
initrd_len = (unsigned long)bp->hdr.ramdisk_size |
|
||||
((unsigned long)bp->ext_ramdisk_size << 32);
|
||||
if (initrd_len) {
|
||||
initrd_start = (unsigned long)bp->hdr.ramdisk_image |
|
||||
((unsigned long)bp->ext_ramdisk_image << 32);
|
||||
initrd_end = PAGE_ALIGN(initrd_start + initrd_len);
|
||||
initrd_len = initrd_end - initrd_start;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set the encryption workarea to be immediately after the kernel */
|
||||
workarea_start = kernel_end;
|
||||
|
||||
/*
|
||||
* Calculate required number of workarea bytes needed:
|
||||
* executable encryption area size:
|
||||
* stack page (PAGE_SIZE)
|
||||
* encryption routine page (PAGE_SIZE)
|
||||
* intermediate copy buffer (PMD_PAGE_SIZE)
|
||||
* pagetable structures for the encryption of the kernel
|
||||
* pagetable structures for workarea (in case not currently mapped)
|
||||
*/
|
||||
execute_start = workarea_start;
|
||||
execute_end = execute_start + (PAGE_SIZE * 2) + PMD_PAGE_SIZE;
|
||||
execute_len = execute_end - execute_start;
|
||||
|
||||
/*
|
||||
* One PGD for both encrypted and decrypted mappings and a set of
|
||||
* PUDs and PMDs for each of the encrypted and decrypted mappings.
|
||||
*/
|
||||
pgtable_area_len = sizeof(pgd_t) * PTRS_PER_PGD;
|
||||
pgtable_area_len += sme_pgtable_calc(execute_end - kernel_start) * 2;
|
||||
if (initrd_len)
|
||||
pgtable_area_len += sme_pgtable_calc(initrd_len) * 2;
|
||||
|
||||
/* PUDs and PMDs needed in the current pagetables for the workarea */
|
||||
pgtable_area_len += sme_pgtable_calc(execute_len + pgtable_area_len);
|
||||
|
||||
/*
|
||||
* The total workarea includes the executable encryption area and
|
||||
* the pagetable area. The start of the workarea is already 2MB
|
||||
* aligned, align the end of the workarea on a 2MB boundary so that
|
||||
* we don't try to create/allocate PTE entries from the workarea
|
||||
* before it is mapped.
|
||||
*/
|
||||
workarea_len = execute_len + pgtable_area_len;
|
||||
workarea_end = ALIGN(workarea_start + workarea_len, PMD_PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* Set the address to the start of where newly created pagetable
|
||||
* structures (PGDs, PUDs and PMDs) will be allocated. New pagetable
|
||||
* structures are created when the workarea is added to the current
|
||||
* pagetables and when the new encrypted and decrypted kernel
|
||||
* mappings are populated.
|
||||
*/
|
||||
ppd.pgtable_area = (void *)execute_end;
|
||||
|
||||
/*
|
||||
* Make sure the current pagetable structure has entries for
|
||||
* addressing the workarea.
|
||||
*/
|
||||
ppd.pgd = (pgd_t *)native_read_cr3_pa();
|
||||
ppd.paddr = workarea_start;
|
||||
ppd.vaddr = workarea_start;
|
||||
ppd.vaddr_end = workarea_end;
|
||||
sme_map_range_decrypted(&ppd);
|
||||
|
||||
/* Flush the TLB - no globals so cr3 is enough */
|
||||
native_write_cr3(__native_read_cr3());
|
||||
|
||||
/*
|
||||
* A new pagetable structure is being built to allow for the kernel
|
||||
* and initrd to be encrypted. It starts with an empty PGD that will
|
||||
* then be populated with new PUDs and PMDs as the encrypted and
|
||||
* decrypted kernel mappings are created.
|
||||
*/
|
||||
ppd.pgd = ppd.pgtable_area;
|
||||
memset(ppd.pgd, 0, sizeof(pgd_t) * PTRS_PER_PGD);
|
||||
ppd.pgtable_area += sizeof(pgd_t) * PTRS_PER_PGD;
|
||||
|
||||
/*
|
||||
* A different PGD index/entry must be used to get different
|
||||
* pagetable entries for the decrypted mapping. Choose the next
|
||||
* PGD index and convert it to a virtual address to be used as
|
||||
* the base of the mapping.
|
||||
*/
|
||||
decrypted_base = (pgd_index(workarea_end) + 1) & (PTRS_PER_PGD - 1);
|
||||
if (initrd_len) {
|
||||
unsigned long check_base;
|
||||
|
||||
check_base = (pgd_index(initrd_end) + 1) & (PTRS_PER_PGD - 1);
|
||||
decrypted_base = max(decrypted_base, check_base);
|
||||
}
|
||||
decrypted_base <<= PGDIR_SHIFT;
|
||||
|
||||
/* Add encrypted kernel (identity) mappings */
|
||||
ppd.paddr = kernel_start;
|
||||
ppd.vaddr = kernel_start;
|
||||
ppd.vaddr_end = kernel_end;
|
||||
sme_map_range_encrypted(&ppd);
|
||||
|
||||
/* Add decrypted, write-protected kernel (non-identity) mappings */
|
||||
ppd.paddr = kernel_start;
|
||||
ppd.vaddr = kernel_start + decrypted_base;
|
||||
ppd.vaddr_end = kernel_end + decrypted_base;
|
||||
sme_map_range_decrypted_wp(&ppd);
|
||||
|
||||
if (initrd_len) {
|
||||
/* Add encrypted initrd (identity) mappings */
|
||||
ppd.paddr = initrd_start;
|
||||
ppd.vaddr = initrd_start;
|
||||
ppd.vaddr_end = initrd_end;
|
||||
sme_map_range_encrypted(&ppd);
|
||||
/*
|
||||
* Add decrypted, write-protected initrd (non-identity) mappings
|
||||
*/
|
||||
ppd.paddr = initrd_start;
|
||||
ppd.vaddr = initrd_start + decrypted_base;
|
||||
ppd.vaddr_end = initrd_end + decrypted_base;
|
||||
sme_map_range_decrypted_wp(&ppd);
|
||||
}
|
||||
|
||||
/* Add decrypted workarea mappings to both kernel mappings */
|
||||
ppd.paddr = workarea_start;
|
||||
ppd.vaddr = workarea_start;
|
||||
ppd.vaddr_end = workarea_end;
|
||||
sme_map_range_decrypted(&ppd);
|
||||
|
||||
ppd.paddr = workarea_start;
|
||||
ppd.vaddr = workarea_start + decrypted_base;
|
||||
ppd.vaddr_end = workarea_end + decrypted_base;
|
||||
sme_map_range_decrypted(&ppd);
|
||||
|
||||
/* Perform the encryption */
|
||||
sme_encrypt_execute(kernel_start, kernel_start + decrypted_base,
|
||||
kernel_len, workarea_start, (unsigned long)ppd.pgd);
|
||||
|
||||
if (initrd_len)
|
||||
sme_encrypt_execute(initrd_start, initrd_start + decrypted_base,
|
||||
initrd_len, workarea_start,
|
||||
(unsigned long)ppd.pgd);
|
||||
|
||||
/*
|
||||
* At this point we are running encrypted. Remove the mappings for
|
||||
* the decrypted areas - all that is needed for this is to remove
|
||||
* the PGD entry/entries.
|
||||
*/
|
||||
ppd.vaddr = kernel_start + decrypted_base;
|
||||
ppd.vaddr_end = kernel_end + decrypted_base;
|
||||
sme_clear_pgd(&ppd);
|
||||
|
||||
if (initrd_len) {
|
||||
ppd.vaddr = initrd_start + decrypted_base;
|
||||
ppd.vaddr_end = initrd_end + decrypted_base;
|
||||
sme_clear_pgd(&ppd);
|
||||
}
|
||||
|
||||
ppd.vaddr = workarea_start + decrypted_base;
|
||||
ppd.vaddr_end = workarea_end + decrypted_base;
|
||||
sme_clear_pgd(&ppd);
|
||||
|
||||
/* Flush the TLB - no globals so cr3 is enough */
|
||||
native_write_cr3(__native_read_cr3());
|
||||
}
|
||||
|
||||
void __init __nostackprotector sme_enable(struct boot_params *bp)
|
||||
{
|
||||
const char *cmdline_ptr, *cmdline_arg, *cmdline_on, *cmdline_off;
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
unsigned long feature_mask;
|
||||
bool active_by_default;
|
||||
unsigned long me_mask;
|
||||
char buffer[16];
|
||||
u64 msr;
|
||||
|
||||
/* Check for the SME/SEV support leaf */
|
||||
eax = 0x80000000;
|
||||
ecx = 0;
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
if (eax < 0x8000001f)
|
||||
return;
|
||||
|
||||
#define AMD_SME_BIT BIT(0)
|
||||
#define AMD_SEV_BIT BIT(1)
|
||||
/*
|
||||
* Set the feature mask (SME or SEV) based on whether we are
|
||||
* running under a hypervisor.
|
||||
*/
|
||||
eax = 1;
|
||||
ecx = 0;
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
feature_mask = (ecx & BIT(31)) ? AMD_SEV_BIT : AMD_SME_BIT;
|
||||
|
||||
/*
|
||||
* Check for the SME/SEV feature:
|
||||
* CPUID Fn8000_001F[EAX]
|
||||
* - Bit 0 - Secure Memory Encryption support
|
||||
* - Bit 1 - Secure Encrypted Virtualization support
|
||||
* CPUID Fn8000_001F[EBX]
|
||||
* - Bits 5:0 - Pagetable bit position used to indicate encryption
|
||||
*/
|
||||
eax = 0x8000001f;
|
||||
ecx = 0;
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
if (!(eax & feature_mask))
|
||||
return;
|
||||
|
||||
me_mask = 1UL << (ebx & 0x3f);
|
||||
|
||||
/* Check if memory encryption is enabled */
|
||||
if (feature_mask == AMD_SME_BIT) {
|
||||
/* For SME, check the SYSCFG MSR */
|
||||
msr = __rdmsr(MSR_K8_SYSCFG);
|
||||
if (!(msr & MSR_K8_SYSCFG_MEM_ENCRYPT))
|
||||
return;
|
||||
} else {
|
||||
/* For SEV, check the SEV MSR */
|
||||
msr = __rdmsr(MSR_AMD64_SEV);
|
||||
if (!(msr & MSR_AMD64_SEV_ENABLED))
|
||||
return;
|
||||
|
||||
/* SEV state cannot be controlled by a command line option */
|
||||
sme_me_mask = me_mask;
|
||||
sev_enabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fixups have not been applied to phys_base yet and we're running
|
||||
* identity mapped, so we must obtain the address to the SME command
|
||||
* line argument data using rip-relative addressing.
|
||||
*/
|
||||
asm ("lea sme_cmdline_arg(%%rip), %0"
|
||||
: "=r" (cmdline_arg)
|
||||
: "p" (sme_cmdline_arg));
|
||||
asm ("lea sme_cmdline_on(%%rip), %0"
|
||||
: "=r" (cmdline_on)
|
||||
: "p" (sme_cmdline_on));
|
||||
asm ("lea sme_cmdline_off(%%rip), %0"
|
||||
: "=r" (cmdline_off)
|
||||
: "p" (sme_cmdline_off));
|
||||
|
||||
if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT))
|
||||
active_by_default = true;
|
||||
else
|
||||
active_by_default = false;
|
||||
|
||||
cmdline_ptr = (const char *)((u64)bp->hdr.cmd_line_ptr |
|
||||
((u64)bp->ext_cmd_line_ptr << 32));
|
||||
|
||||
cmdline_find_option(cmdline_ptr, cmdline_arg, buffer, sizeof(buffer));
|
||||
|
||||
if (!strncmp(buffer, cmdline_on, sizeof(buffer)))
|
||||
sme_me_mask = me_mask;
|
||||
else if (!strncmp(buffer, cmdline_off, sizeof(buffer)))
|
||||
sme_me_mask = 0;
|
||||
else
|
||||
sme_me_mask = active_by_default ? me_mask : 0;
|
||||
}
|
||||
|
564
arch/x86/mm/mem_encrypt_identity.c
Normal file
564
arch/x86/mm/mem_encrypt_identity.c
Normal file
@@ -0,0 +1,564 @@
|
||||
/*
|
||||
* AMD Memory Encryption Support
|
||||
*
|
||||
* Copyright (C) 2016 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Author: Tom Lendacky <thomas.lendacky@amd.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define DISABLE_BRANCH_PROFILING
|
||||
|
||||
/*
|
||||
* Since we're dealing with identity mappings, physical and virtual
|
||||
* addresses are the same, so override these defines which are ultimately
|
||||
* used by the headers in misc.h.
|
||||
*/
|
||||
#define __pa(x) ((unsigned long)(x))
|
||||
#define __va(x) ((void *)((unsigned long)(x)))
|
||||
|
||||
/*
|
||||
* Special hack: we have to be careful, because no indirections are
|
||||
* allowed here, and paravirt_ops is a kind of one. As it will only run in
|
||||
* baremetal anyway, we just keep it from happening. (This list needs to
|
||||
* be extended when new paravirt and debugging variants are added.)
|
||||
*/
|
||||
#undef CONFIG_PARAVIRT
|
||||
#undef CONFIG_PARAVIRT_SPINLOCKS
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mem_encrypt.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/cmdline.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
|
||||
#define PGD_FLAGS _KERNPG_TABLE_NOENC
|
||||
#define P4D_FLAGS _KERNPG_TABLE_NOENC
|
||||
#define PUD_FLAGS _KERNPG_TABLE_NOENC
|
||||
#define PMD_FLAGS _KERNPG_TABLE_NOENC
|
||||
|
||||
#define PMD_FLAGS_LARGE (__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL)
|
||||
|
||||
#define PMD_FLAGS_DEC PMD_FLAGS_LARGE
|
||||
#define PMD_FLAGS_DEC_WP ((PMD_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \
|
||||
(_PAGE_PAT | _PAGE_PWT))
|
||||
|
||||
#define PMD_FLAGS_ENC (PMD_FLAGS_LARGE | _PAGE_ENC)
|
||||
|
||||
#define PTE_FLAGS (__PAGE_KERNEL_EXEC & ~_PAGE_GLOBAL)
|
||||
|
||||
#define PTE_FLAGS_DEC PTE_FLAGS
|
||||
#define PTE_FLAGS_DEC_WP ((PTE_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \
|
||||
(_PAGE_PAT | _PAGE_PWT))
|
||||
|
||||
#define PTE_FLAGS_ENC (PTE_FLAGS | _PAGE_ENC)
|
||||
|
||||
struct sme_populate_pgd_data {
|
||||
void *pgtable_area;
|
||||
pgd_t *pgd;
|
||||
|
||||
pmdval_t pmd_flags;
|
||||
pteval_t pte_flags;
|
||||
unsigned long paddr;
|
||||
|
||||
unsigned long vaddr;
|
||||
unsigned long vaddr_end;
|
||||
};
|
||||
|
||||
static char sme_cmdline_arg[] __initdata = "mem_encrypt";
|
||||
static char sme_cmdline_on[] __initdata = "on";
|
||||
static char sme_cmdline_off[] __initdata = "off";
|
||||
|
||||
static void __init sme_clear_pgd(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
unsigned long pgd_start, pgd_end, pgd_size;
|
||||
pgd_t *pgd_p;
|
||||
|
||||
pgd_start = ppd->vaddr & PGDIR_MASK;
|
||||
pgd_end = ppd->vaddr_end & PGDIR_MASK;
|
||||
|
||||
pgd_size = (((pgd_end - pgd_start) / PGDIR_SIZE) + 1) * sizeof(pgd_t);
|
||||
|
||||
pgd_p = ppd->pgd + pgd_index(ppd->vaddr);
|
||||
|
||||
memset(pgd_p, 0, pgd_size);
|
||||
}
|
||||
|
||||
static pud_t __init *sme_prepare_pgd(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
p4d_t *p4d;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
|
||||
pgd = ppd->pgd + pgd_index(ppd->vaddr);
|
||||
if (pgd_none(*pgd)) {
|
||||
p4d = ppd->pgtable_area;
|
||||
memset(p4d, 0, sizeof(*p4d) * PTRS_PER_P4D);
|
||||
ppd->pgtable_area += sizeof(*p4d) * PTRS_PER_P4D;
|
||||
set_pgd(pgd, __pgd(PGD_FLAGS | __pa(p4d)));
|
||||
}
|
||||
|
||||
p4d = p4d_offset(pgd, ppd->vaddr);
|
||||
if (p4d_none(*p4d)) {
|
||||
pud = ppd->pgtable_area;
|
||||
memset(pud, 0, sizeof(*pud) * PTRS_PER_PUD);
|
||||
ppd->pgtable_area += sizeof(*pud) * PTRS_PER_PUD;
|
||||
set_p4d(p4d, __p4d(P4D_FLAGS | __pa(pud)));
|
||||
}
|
||||
|
||||
pud = pud_offset(p4d, ppd->vaddr);
|
||||
if (pud_none(*pud)) {
|
||||
pmd = ppd->pgtable_area;
|
||||
memset(pmd, 0, sizeof(*pmd) * PTRS_PER_PMD);
|
||||
ppd->pgtable_area += sizeof(*pmd) * PTRS_PER_PMD;
|
||||
set_pud(pud, __pud(PUD_FLAGS | __pa(pmd)));
|
||||
}
|
||||
|
||||
if (pud_large(*pud))
|
||||
return NULL;
|
||||
|
||||
return pud;
|
||||
}
|
||||
|
||||
static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
|
||||
pud = sme_prepare_pgd(ppd);
|
||||
if (!pud)
|
||||
return;
|
||||
|
||||
pmd = pmd_offset(pud, ppd->vaddr);
|
||||
if (pmd_large(*pmd))
|
||||
return;
|
||||
|
||||
set_pmd(pmd, __pmd(ppd->paddr | ppd->pmd_flags));
|
||||
}
|
||||
|
||||
static void __init sme_populate_pgd(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
|
||||
pud = sme_prepare_pgd(ppd);
|
||||
if (!pud)
|
||||
return;
|
||||
|
||||
pmd = pmd_offset(pud, ppd->vaddr);
|
||||
if (pmd_none(*pmd)) {
|
||||
pte = ppd->pgtable_area;
|
||||
memset(pte, 0, sizeof(pte) * PTRS_PER_PTE);
|
||||
ppd->pgtable_area += sizeof(pte) * PTRS_PER_PTE;
|
||||
set_pmd(pmd, __pmd(PMD_FLAGS | __pa(pte)));
|
||||
}
|
||||
|
||||
if (pmd_large(*pmd))
|
||||
return;
|
||||
|
||||
pte = pte_offset_map(pmd, ppd->vaddr);
|
||||
if (pte_none(*pte))
|
||||
set_pte(pte, __pte(ppd->paddr | ppd->pte_flags));
|
||||
}
|
||||
|
||||
static void __init __sme_map_range_pmd(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
while (ppd->vaddr < ppd->vaddr_end) {
|
||||
sme_populate_pgd_large(ppd);
|
||||
|
||||
ppd->vaddr += PMD_PAGE_SIZE;
|
||||
ppd->paddr += PMD_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void __init __sme_map_range_pte(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
while (ppd->vaddr < ppd->vaddr_end) {
|
||||
sme_populate_pgd(ppd);
|
||||
|
||||
ppd->vaddr += PAGE_SIZE;
|
||||
ppd->paddr += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void __init __sme_map_range(struct sme_populate_pgd_data *ppd,
|
||||
pmdval_t pmd_flags, pteval_t pte_flags)
|
||||
{
|
||||
unsigned long vaddr_end;
|
||||
|
||||
ppd->pmd_flags = pmd_flags;
|
||||
ppd->pte_flags = pte_flags;
|
||||
|
||||
/* Save original end value since we modify the struct value */
|
||||
vaddr_end = ppd->vaddr_end;
|
||||
|
||||
/* If start is not 2MB aligned, create PTE entries */
|
||||
ppd->vaddr_end = ALIGN(ppd->vaddr, PMD_PAGE_SIZE);
|
||||
__sme_map_range_pte(ppd);
|
||||
|
||||
/* Create PMD entries */
|
||||
ppd->vaddr_end = vaddr_end & PMD_PAGE_MASK;
|
||||
__sme_map_range_pmd(ppd);
|
||||
|
||||
/* If end is not 2MB aligned, create PTE entries */
|
||||
ppd->vaddr_end = vaddr_end;
|
||||
__sme_map_range_pte(ppd);
|
||||
}
|
||||
|
||||
static void __init sme_map_range_encrypted(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
__sme_map_range(ppd, PMD_FLAGS_ENC, PTE_FLAGS_ENC);
|
||||
}
|
||||
|
||||
static void __init sme_map_range_decrypted(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
__sme_map_range(ppd, PMD_FLAGS_DEC, PTE_FLAGS_DEC);
|
||||
}
|
||||
|
||||
static void __init sme_map_range_decrypted_wp(struct sme_populate_pgd_data *ppd)
|
||||
{
|
||||
__sme_map_range(ppd, PMD_FLAGS_DEC_WP, PTE_FLAGS_DEC_WP);
|
||||
}
|
||||
|
||||
static unsigned long __init sme_pgtable_calc(unsigned long len)
|
||||
{
|
||||
unsigned long entries = 0, tables = 0;
|
||||
|
||||
/*
|
||||
* Perform a relatively simplistic calculation of the pagetable
|
||||
* entries that are needed. Those mappings will be covered mostly
|
||||
* by 2MB PMD entries so we can conservatively calculate the required
|
||||
* number of P4D, PUD and PMD structures needed to perform the
|
||||
* mappings. For mappings that are not 2MB aligned, PTE mappings
|
||||
* would be needed for the start and end portion of the address range
|
||||
* that fall outside of the 2MB alignment. This results in, at most,
|
||||
* two extra pages to hold PTE entries for each range that is mapped.
|
||||
* Incrementing the count for each covers the case where the addresses
|
||||
* cross entries.
|
||||
*/
|
||||
|
||||
/* PGDIR_SIZE is equal to P4D_SIZE on 4-level machine. */
|
||||
if (PTRS_PER_P4D > 1)
|
||||
entries += (DIV_ROUND_UP(len, PGDIR_SIZE) + 1) * sizeof(p4d_t) * PTRS_PER_P4D;
|
||||
entries += (DIV_ROUND_UP(len, P4D_SIZE) + 1) * sizeof(pud_t) * PTRS_PER_PUD;
|
||||
entries += (DIV_ROUND_UP(len, PUD_SIZE) + 1) * sizeof(pmd_t) * PTRS_PER_PMD;
|
||||
entries += 2 * sizeof(pte_t) * PTRS_PER_PTE;
|
||||
|
||||
/*
|
||||
* Now calculate the added pagetable structures needed to populate
|
||||
* the new pagetables.
|
||||
*/
|
||||
|
||||
if (PTRS_PER_P4D > 1)
|
||||
tables += DIV_ROUND_UP(entries, PGDIR_SIZE) * sizeof(p4d_t) * PTRS_PER_P4D;
|
||||
tables += DIV_ROUND_UP(entries, P4D_SIZE) * sizeof(pud_t) * PTRS_PER_PUD;
|
||||
tables += DIV_ROUND_UP(entries, PUD_SIZE) * sizeof(pmd_t) * PTRS_PER_PMD;
|
||||
|
||||
return entries + tables;
|
||||
}
|
||||
|
||||
void __init sme_encrypt_kernel(struct boot_params *bp)
|
||||
{
|
||||
unsigned long workarea_start, workarea_end, workarea_len;
|
||||
unsigned long execute_start, execute_end, execute_len;
|
||||
unsigned long kernel_start, kernel_end, kernel_len;
|
||||
unsigned long initrd_start, initrd_end, initrd_len;
|
||||
struct sme_populate_pgd_data ppd;
|
||||
unsigned long pgtable_area_len;
|
||||
unsigned long decrypted_base;
|
||||
|
||||
if (!sme_active())
|
||||
return;
|
||||
|
||||
/*
|
||||
* Prepare for encrypting the kernel and initrd by building new
|
||||
* pagetables with the necessary attributes needed to encrypt the
|
||||
* kernel in place.
|
||||
*
|
||||
* One range of virtual addresses will map the memory occupied
|
||||
* by the kernel and initrd as encrypted.
|
||||
*
|
||||
* Another range of virtual addresses will map the memory occupied
|
||||
* by the kernel and initrd as decrypted and write-protected.
|
||||
*
|
||||
* The use of write-protect attribute will prevent any of the
|
||||
* memory from being cached.
|
||||
*/
|
||||
|
||||
/* Physical addresses gives us the identity mapped virtual addresses */
|
||||
kernel_start = __pa_symbol(_text);
|
||||
kernel_end = ALIGN(__pa_symbol(_end), PMD_PAGE_SIZE);
|
||||
kernel_len = kernel_end - kernel_start;
|
||||
|
||||
initrd_start = 0;
|
||||
initrd_end = 0;
|
||||
initrd_len = 0;
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
initrd_len = (unsigned long)bp->hdr.ramdisk_size |
|
||||
((unsigned long)bp->ext_ramdisk_size << 32);
|
||||
if (initrd_len) {
|
||||
initrd_start = (unsigned long)bp->hdr.ramdisk_image |
|
||||
((unsigned long)bp->ext_ramdisk_image << 32);
|
||||
initrd_end = PAGE_ALIGN(initrd_start + initrd_len);
|
||||
initrd_len = initrd_end - initrd_start;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set the encryption workarea to be immediately after the kernel */
|
||||
workarea_start = kernel_end;
|
||||
|
||||
/*
|
||||
* Calculate required number of workarea bytes needed:
|
||||
* executable encryption area size:
|
||||
* stack page (PAGE_SIZE)
|
||||
* encryption routine page (PAGE_SIZE)
|
||||
* intermediate copy buffer (PMD_PAGE_SIZE)
|
||||
* pagetable structures for the encryption of the kernel
|
||||
* pagetable structures for workarea (in case not currently mapped)
|
||||
*/
|
||||
execute_start = workarea_start;
|
||||
execute_end = execute_start + (PAGE_SIZE * 2) + PMD_PAGE_SIZE;
|
||||
execute_len = execute_end - execute_start;
|
||||
|
||||
/*
|
||||
* One PGD for both encrypted and decrypted mappings and a set of
|
||||
* PUDs and PMDs for each of the encrypted and decrypted mappings.
|
||||
*/
|
||||
pgtable_area_len = sizeof(pgd_t) * PTRS_PER_PGD;
|
||||
pgtable_area_len += sme_pgtable_calc(execute_end - kernel_start) * 2;
|
||||
if (initrd_len)
|
||||
pgtable_area_len += sme_pgtable_calc(initrd_len) * 2;
|
||||
|
||||
/* PUDs and PMDs needed in the current pagetables for the workarea */
|
||||
pgtable_area_len += sme_pgtable_calc(execute_len + pgtable_area_len);
|
||||
|
||||
/*
|
||||
* The total workarea includes the executable encryption area and
|
||||
* the pagetable area. The start of the workarea is already 2MB
|
||||
* aligned, align the end of the workarea on a 2MB boundary so that
|
||||
* we don't try to create/allocate PTE entries from the workarea
|
||||
* before it is mapped.
|
||||
*/
|
||||
workarea_len = execute_len + pgtable_area_len;
|
||||
workarea_end = ALIGN(workarea_start + workarea_len, PMD_PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* Set the address to the start of where newly created pagetable
|
||||
* structures (PGDs, PUDs and PMDs) will be allocated. New pagetable
|
||||
* structures are created when the workarea is added to the current
|
||||
* pagetables and when the new encrypted and decrypted kernel
|
||||
* mappings are populated.
|
||||
*/
|
||||
ppd.pgtable_area = (void *)execute_end;
|
||||
|
||||
/*
|
||||
* Make sure the current pagetable structure has entries for
|
||||
* addressing the workarea.
|
||||
*/
|
||||
ppd.pgd = (pgd_t *)native_read_cr3_pa();
|
||||
ppd.paddr = workarea_start;
|
||||
ppd.vaddr = workarea_start;
|
||||
ppd.vaddr_end = workarea_end;
|
||||
sme_map_range_decrypted(&ppd);
|
||||
|
||||
/* Flush the TLB - no globals so cr3 is enough */
|
||||
native_write_cr3(__native_read_cr3());
|
||||
|
||||
/*
|
||||
* A new pagetable structure is being built to allow for the kernel
|
||||
* and initrd to be encrypted. It starts with an empty PGD that will
|
||||
* then be populated with new PUDs and PMDs as the encrypted and
|
||||
* decrypted kernel mappings are created.
|
||||
*/
|
||||
ppd.pgd = ppd.pgtable_area;
|
||||
memset(ppd.pgd, 0, sizeof(pgd_t) * PTRS_PER_PGD);
|
||||
ppd.pgtable_area += sizeof(pgd_t) * PTRS_PER_PGD;
|
||||
|
||||
/*
|
||||
* A different PGD index/entry must be used to get different
|
||||
* pagetable entries for the decrypted mapping. Choose the next
|
||||
* PGD index and convert it to a virtual address to be used as
|
||||
* the base of the mapping.
|
||||
*/
|
||||
decrypted_base = (pgd_index(workarea_end) + 1) & (PTRS_PER_PGD - 1);
|
||||
if (initrd_len) {
|
||||
unsigned long check_base;
|
||||
|
||||
check_base = (pgd_index(initrd_end) + 1) & (PTRS_PER_PGD - 1);
|
||||
decrypted_base = max(decrypted_base, check_base);
|
||||
}
|
||||
decrypted_base <<= PGDIR_SHIFT;
|
||||
|
||||
/* Add encrypted kernel (identity) mappings */
|
||||
ppd.paddr = kernel_start;
|
||||
ppd.vaddr = kernel_start;
|
||||
ppd.vaddr_end = kernel_end;
|
||||
sme_map_range_encrypted(&ppd);
|
||||
|
||||
/* Add decrypted, write-protected kernel (non-identity) mappings */
|
||||
ppd.paddr = kernel_start;
|
||||
ppd.vaddr = kernel_start + decrypted_base;
|
||||
ppd.vaddr_end = kernel_end + decrypted_base;
|
||||
sme_map_range_decrypted_wp(&ppd);
|
||||
|
||||
if (initrd_len) {
|
||||
/* Add encrypted initrd (identity) mappings */
|
||||
ppd.paddr = initrd_start;
|
||||
ppd.vaddr = initrd_start;
|
||||
ppd.vaddr_end = initrd_end;
|
||||
sme_map_range_encrypted(&ppd);
|
||||
/*
|
||||
* Add decrypted, write-protected initrd (non-identity) mappings
|
||||
*/
|
||||
ppd.paddr = initrd_start;
|
||||
ppd.vaddr = initrd_start + decrypted_base;
|
||||
ppd.vaddr_end = initrd_end + decrypted_base;
|
||||
sme_map_range_decrypted_wp(&ppd);
|
||||
}
|
||||
|
||||
/* Add decrypted workarea mappings to both kernel mappings */
|
||||
ppd.paddr = workarea_start;
|
||||
ppd.vaddr = workarea_start;
|
||||
ppd.vaddr_end = workarea_end;
|
||||
sme_map_range_decrypted(&ppd);
|
||||
|
||||
ppd.paddr = workarea_start;
|
||||
ppd.vaddr = workarea_start + decrypted_base;
|
||||
ppd.vaddr_end = workarea_end + decrypted_base;
|
||||
sme_map_range_decrypted(&ppd);
|
||||
|
||||
/* Perform the encryption */
|
||||
sme_encrypt_execute(kernel_start, kernel_start + decrypted_base,
|
||||
kernel_len, workarea_start, (unsigned long)ppd.pgd);
|
||||
|
||||
if (initrd_len)
|
||||
sme_encrypt_execute(initrd_start, initrd_start + decrypted_base,
|
||||
initrd_len, workarea_start,
|
||||
(unsigned long)ppd.pgd);
|
||||
|
||||
/*
|
||||
* At this point we are running encrypted. Remove the mappings for
|
||||
* the decrypted areas - all that is needed for this is to remove
|
||||
* the PGD entry/entries.
|
||||
*/
|
||||
ppd.vaddr = kernel_start + decrypted_base;
|
||||
ppd.vaddr_end = kernel_end + decrypted_base;
|
||||
sme_clear_pgd(&ppd);
|
||||
|
||||
if (initrd_len) {
|
||||
ppd.vaddr = initrd_start + decrypted_base;
|
||||
ppd.vaddr_end = initrd_end + decrypted_base;
|
||||
sme_clear_pgd(&ppd);
|
||||
}
|
||||
|
||||
ppd.vaddr = workarea_start + decrypted_base;
|
||||
ppd.vaddr_end = workarea_end + decrypted_base;
|
||||
sme_clear_pgd(&ppd);
|
||||
|
||||
/* Flush the TLB - no globals so cr3 is enough */
|
||||
native_write_cr3(__native_read_cr3());
|
||||
}
|
||||
|
||||
void __init sme_enable(struct boot_params *bp)
|
||||
{
|
||||
const char *cmdline_ptr, *cmdline_arg, *cmdline_on, *cmdline_off;
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
unsigned long feature_mask;
|
||||
bool active_by_default;
|
||||
unsigned long me_mask;
|
||||
char buffer[16];
|
||||
u64 msr;
|
||||
|
||||
/* Check for the SME/SEV support leaf */
|
||||
eax = 0x80000000;
|
||||
ecx = 0;
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
if (eax < 0x8000001f)
|
||||
return;
|
||||
|
||||
#define AMD_SME_BIT BIT(0)
|
||||
#define AMD_SEV_BIT BIT(1)
|
||||
/*
|
||||
* Set the feature mask (SME or SEV) based on whether we are
|
||||
* running under a hypervisor.
|
||||
*/
|
||||
eax = 1;
|
||||
ecx = 0;
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
feature_mask = (ecx & BIT(31)) ? AMD_SEV_BIT : AMD_SME_BIT;
|
||||
|
||||
/*
|
||||
* Check for the SME/SEV feature:
|
||||
* CPUID Fn8000_001F[EAX]
|
||||
* - Bit 0 - Secure Memory Encryption support
|
||||
* - Bit 1 - Secure Encrypted Virtualization support
|
||||
* CPUID Fn8000_001F[EBX]
|
||||
* - Bits 5:0 - Pagetable bit position used to indicate encryption
|
||||
*/
|
||||
eax = 0x8000001f;
|
||||
ecx = 0;
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
if (!(eax & feature_mask))
|
||||
return;
|
||||
|
||||
me_mask = 1UL << (ebx & 0x3f);
|
||||
|
||||
/* Check if memory encryption is enabled */
|
||||
if (feature_mask == AMD_SME_BIT) {
|
||||
/* For SME, check the SYSCFG MSR */
|
||||
msr = __rdmsr(MSR_K8_SYSCFG);
|
||||
if (!(msr & MSR_K8_SYSCFG_MEM_ENCRYPT))
|
||||
return;
|
||||
} else {
|
||||
/* For SEV, check the SEV MSR */
|
||||
msr = __rdmsr(MSR_AMD64_SEV);
|
||||
if (!(msr & MSR_AMD64_SEV_ENABLED))
|
||||
return;
|
||||
|
||||
/* SEV state cannot be controlled by a command line option */
|
||||
sme_me_mask = me_mask;
|
||||
sev_enabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fixups have not been applied to phys_base yet and we're running
|
||||
* identity mapped, so we must obtain the address to the SME command
|
||||
* line argument data using rip-relative addressing.
|
||||
*/
|
||||
asm ("lea sme_cmdline_arg(%%rip), %0"
|
||||
: "=r" (cmdline_arg)
|
||||
: "p" (sme_cmdline_arg));
|
||||
asm ("lea sme_cmdline_on(%%rip), %0"
|
||||
: "=r" (cmdline_on)
|
||||
: "p" (sme_cmdline_on));
|
||||
asm ("lea sme_cmdline_off(%%rip), %0"
|
||||
: "=r" (cmdline_off)
|
||||
: "p" (sme_cmdline_off));
|
||||
|
||||
if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT))
|
||||
active_by_default = true;
|
||||
else
|
||||
active_by_default = false;
|
||||
|
||||
cmdline_ptr = (const char *)((u64)bp->hdr.cmd_line_ptr |
|
||||
((u64)bp->ext_cmd_line_ptr << 32));
|
||||
|
||||
cmdline_find_option(cmdline_ptr, cmdline_arg, buffer, sizeof(buffer));
|
||||
|
||||
if (!strncmp(buffer, cmdline_on, sizeof(buffer)))
|
||||
sme_me_mask = me_mask;
|
||||
else if (!strncmp(buffer, cmdline_off, sizeof(buffer)))
|
||||
sme_me_mask = 0;
|
||||
else
|
||||
sme_me_mask = active_by_default ? me_mask : 0;
|
||||
}
|
@@ -60,17 +60,6 @@ void memory_present(int nid, unsigned long start, unsigned long end)
|
||||
}
|
||||
printk(KERN_CONT "\n");
|
||||
}
|
||||
|
||||
unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn,
|
||||
unsigned long end_pfn)
|
||||
{
|
||||
unsigned long nr_pages = end_pfn - start_pfn;
|
||||
|
||||
if (!nr_pages)
|
||||
return 0;
|
||||
|
||||
return (nr_pages + 1) * sizeof(struct page);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern unsigned long highend_pfn, highstart_pfn;
|
||||
|
@@ -157,7 +157,7 @@ static void sync_current_stack_to_mm(struct mm_struct *mm)
|
||||
unsigned long sp = current_stack_pointer;
|
||||
pgd_t *pgd = pgd_offset(mm, sp);
|
||||
|
||||
if (CONFIG_PGTABLE_LEVELS > 4) {
|
||||
if (pgtable_l5_enabled) {
|
||||
if (unlikely(pgd_none(*pgd))) {
|
||||
pgd_t *pgd_ref = pgd_offset_k(sp);
|
||||
|
||||
@@ -613,7 +613,7 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
|
||||
{
|
||||
int cpu;
|
||||
|
||||
struct flush_tlb_info info = {
|
||||
struct flush_tlb_info info __aligned(SMP_CACHE_BYTES) = {
|
||||
.mm = mm,
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user