Commit 0290c9e3 authored by Heiko Carstens's avatar Heiko Carstens
Browse files

s390/mm: use invalid asce instead of kernel asce



Create a region 3 page table which contains only invalid entries, and
use that via "s390_invalid_asce" instead of the kernel ASCE whenever
there is either
- no user address space available, e.g. during early startup
- as an intermediate ASCE when address spaces are switched

This makes sure that user space accesses in such situations are
guaranteed to fail.

Reviewed-by: default avatarSven Schnelle <svens@linux.ibm.com>
Reviewed-by: default avatarAlexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
parent 87d59863
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
	S390_lowcore.user_asce = next->context.asce;
	cpumask_set_cpu(cpu, &next->context.cpu_attach_mask);
	/* Clear previous user-ASCE from CR7 */
	__ctl_load(S390_lowcore.kernel_asce, 7, 7);
	__ctl_load(s390_invalid_asce, 7, 7);
	if (prev != next)
		cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask);
}
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@

extern pgd_t swapper_pg_dir[];
extern void paging_init(void);
extern unsigned long s390_invalid_asce;

enum {
	PG_DIRECT_MAP_4K = 0,
+1 −1
Original line number Diff line number Diff line
@@ -259,7 +259,7 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
	lc->spinlock_index = 0;
	lc->percpu_offset = __per_cpu_offset[cpu];
	lc->kernel_asce = S390_lowcore.kernel_asce;
	lc->user_asce = S390_lowcore.kernel_asce;
	lc->user_asce = s390_invalid_asce;
	lc->machine_flags = S390_lowcore.machine_flags;
	lc->user_timer = lc->system_timer =
		lc->steal_timer = lc->avg_steal_timer = 0;
+2 −1
Original line number Diff line number Diff line
@@ -10,7 +10,8 @@
 * Put .bss..swapper_pg_dir as the first thing in .bss. This will
 * make sure it has 16k alignment.
 */
#define BSS_FIRST_SECTIONS *(.bss..swapper_pg_dir)
#define BSS_FIRST_SECTIONS *(.bss..swapper_pg_dir) \
			   *(.bss..invalid_pg_dir)

/* Handle ro_after_init data on our own. */
#define RO_AFTER_INIT_DATA
+8 −2
Original line number Diff line number Diff line
@@ -49,6 +49,9 @@
#include <linux/virtio_config.h>

pgd_t swapper_pg_dir[PTRS_PER_PGD] __section(".bss..swapper_pg_dir");
static pgd_t invalid_pg_dir[PTRS_PER_PGD] __section(".bss..invalid_pg_dir");

unsigned long s390_invalid_asce;

unsigned long empty_zero_page, zero_page_mask;
EXPORT_SYMBOL(empty_zero_page);
@@ -92,6 +95,9 @@ void __init paging_init(void)
	unsigned long pgd_type, asce_bits;
	psw_t psw;

	s390_invalid_asce  = (unsigned long)invalid_pg_dir;
	s390_invalid_asce |= _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH;
	crst_table_init((unsigned long *)invalid_pg_dir, _REGION3_ENTRY_EMPTY);
	init_mm.pgd = swapper_pg_dir;
	if (VMALLOC_END > _REGION2_SIZE) {
		asce_bits = _ASCE_TYPE_REGION2 | _ASCE_TABLE_LENGTH;
@@ -102,14 +108,14 @@ void __init paging_init(void)
	}
	init_mm.context.asce = (__pa(init_mm.pgd) & PAGE_MASK) | asce_bits;
	S390_lowcore.kernel_asce = init_mm.context.asce;
	S390_lowcore.user_asce = S390_lowcore.kernel_asce;
	S390_lowcore.user_asce = s390_invalid_asce;
	crst_table_init((unsigned long *) init_mm.pgd, pgd_type);
	vmem_map_init();
	kasan_copy_shadow_mapping();

	/* enable virtual mapping in kernel mode */
	__ctl_load(S390_lowcore.kernel_asce, 1, 1);
	__ctl_load(S390_lowcore.kernel_asce, 7, 7);
	__ctl_load(S390_lowcore.user_asce, 7, 7);
	__ctl_load(S390_lowcore.kernel_asce, 13, 13);
	psw.mask = __extract_psw();
	psw_bits(psw).dat = 1;