diff options
| -rw-r--r-- | arch/s390/include/asm/skey.h | 32 | ||||
| -rw-r--r-- | arch/s390/kernel/Makefile | 2 | ||||
| -rw-r--r-- | arch/s390/kernel/skey.c | 48 | ||||
| -rw-r--r-- | arch/s390/kernel/vmlinux.lds.S | 7 | 
4 files changed, 88 insertions, 1 deletions
| diff --git a/arch/s390/include/asm/skey.h b/arch/s390/include/asm/skey.h new file mode 100644 index 000000000000..84e7cf28b712 --- /dev/null +++ b/arch/s390/include/asm/skey.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_SKEY_H +#define __ASM_SKEY_H + +#include <asm/rwonce.h> + +struct skey_region { +	unsigned long start; +	unsigned long end; +}; + +#define SKEY_REGION(_start, _end)			\ +	stringify_in_c(.section .skey_region,"a";)	\ +	stringify_in_c(.balign 8;)			\ +	stringify_in_c(.quad (_start);)			\ +	stringify_in_c(.quad (_end);)			\ +	stringify_in_c(.previous) + +extern int skey_regions_initialized; +extern struct skey_region __skey_region_start[]; +extern struct skey_region __skey_region_end[]; + +void __skey_regions_initialize(void); + +static inline void skey_regions_initialize(void) +{ +	if (READ_ONCE(skey_regions_initialized)) +		return; +	__skey_regions_initialize(); +} + +#endif /* __ASM_SKEY_H */ diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index ea5ed6654050..eb06ff888314 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -41,7 +41,7 @@ obj-y	+= processor.o syscall.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o  obj-y	+= debug.o irq.o ipl.o dis.o vdso.o cpufeature.o  obj-y	+= sysinfo.o lgr.o os_info.o ctlreg.o  obj-y	+= runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o -obj-y	+= entry.o reipl.o kdebugfs.o alternative.o +obj-y	+= entry.o reipl.o kdebugfs.o alternative.o skey.o  obj-y	+= nospec-branch.o ipl_vmparm.o machine_kexec_reloc.o unwind_bc.o  obj-y	+= smp.o text_amode31.o stacktrace.o abs_lowcore.o facility.o uv.o wti.o  obj-y	+= diag/ diff --git a/arch/s390/kernel/skey.c b/arch/s390/kernel/skey.c new file mode 100644 index 000000000000..ba049fd103c2 --- /dev/null +++ b/arch/s390/kernel/skey.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <asm/rwonce.h> +#include <asm/page.h> +#include <asm/skey.h> + +int skey_regions_initialized; + +static inline unsigned long load_real_address(unsigned long address) +{ +	unsigned long real; + +	asm volatile( +		"	lra	%[real],0(%[address])\n" +		: [real] "=d" (real) +		: [address] "a" (address) +		: "cc"); +	return real; +} + +/* + * Initialize storage keys of registered memory regions with the + * default key. This is useful for code which is executed with a + * non-default access key. + */ +void __skey_regions_initialize(void) +{ +	unsigned long address, real; +	struct skey_region *r, *end; + +	r = __skey_region_start; +	end = __skey_region_end; +	while (r < end) { +		address = r->start & PAGE_MASK; +		do { +			real = load_real_address(address); +			page_set_storage_key(real, PAGE_DEFAULT_KEY, 1); +			address += PAGE_SIZE; +		} while (address < r->end); +		r++; +	} +	/* +	 * Make sure storage keys are initialized before +	 * skey_regions_initialized is changed. +	 */ +	barrier(); +	WRITE_ONCE(skey_regions_initialized, 1); +} diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index ff1ddba96352..1c606dfa595d 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -71,6 +71,13 @@ SECTIONS  	. = ALIGN(PAGE_SIZE);  	__end_ro_after_init = .; +	. = ALIGN(8); +	.skey_region_table : { +		__skey_region_start = .; +		KEEP(*(.skey_region)) +		__skey_region_end = .; +	} +  	.data.rel.ro : {  		*(.data.rel.ro .data.rel.ro.*)  	} | 
