xref: /linux/arch/s390/kernel/skey.c (revision bc46b7cbc58c4cb562b6a45a1fbc7b8e7b23df58)
1*ee417a84SHeiko Carstens // SPDX-License-Identifier: GPL-2.0
2*ee417a84SHeiko Carstens 
3*ee417a84SHeiko Carstens #include <asm/rwonce.h>
4*ee417a84SHeiko Carstens #include <asm/page.h>
5*ee417a84SHeiko Carstens #include <asm/skey.h>
6*ee417a84SHeiko Carstens 
7*ee417a84SHeiko Carstens int skey_regions_initialized;
8*ee417a84SHeiko Carstens 
load_real_address(unsigned long address)9*ee417a84SHeiko Carstens static inline unsigned long load_real_address(unsigned long address)
10*ee417a84SHeiko Carstens {
11*ee417a84SHeiko Carstens 	unsigned long real;
12*ee417a84SHeiko Carstens 
13*ee417a84SHeiko Carstens 	asm volatile(
14*ee417a84SHeiko Carstens 		"	lra	%[real],0(%[address])\n"
15*ee417a84SHeiko Carstens 		: [real] "=d" (real)
16*ee417a84SHeiko Carstens 		: [address] "a" (address)
17*ee417a84SHeiko Carstens 		: "cc");
18*ee417a84SHeiko Carstens 	return real;
19*ee417a84SHeiko Carstens }
20*ee417a84SHeiko Carstens 
21*ee417a84SHeiko Carstens /*
22*ee417a84SHeiko Carstens  * Initialize storage keys of registered memory regions with the
23*ee417a84SHeiko Carstens  * default key. This is useful for code which is executed with a
24*ee417a84SHeiko Carstens  * non-default access key.
25*ee417a84SHeiko Carstens  */
__skey_regions_initialize(void)26*ee417a84SHeiko Carstens void __skey_regions_initialize(void)
27*ee417a84SHeiko Carstens {
28*ee417a84SHeiko Carstens 	unsigned long address, real;
29*ee417a84SHeiko Carstens 	struct skey_region *r, *end;
30*ee417a84SHeiko Carstens 
31*ee417a84SHeiko Carstens 	r = __skey_region_start;
32*ee417a84SHeiko Carstens 	end = __skey_region_end;
33*ee417a84SHeiko Carstens 	while (r < end) {
34*ee417a84SHeiko Carstens 		address = r->start & PAGE_MASK;
35*ee417a84SHeiko Carstens 		do {
36*ee417a84SHeiko Carstens 			real = load_real_address(address);
37*ee417a84SHeiko Carstens 			page_set_storage_key(real, PAGE_DEFAULT_KEY, 1);
38*ee417a84SHeiko Carstens 			address += PAGE_SIZE;
39*ee417a84SHeiko Carstens 		} while (address < r->end);
40*ee417a84SHeiko Carstens 		r++;
41*ee417a84SHeiko Carstens 	}
42*ee417a84SHeiko Carstens 	/*
43*ee417a84SHeiko Carstens 	 * Make sure storage keys are initialized before
44*ee417a84SHeiko Carstens 	 * skey_regions_initialized is changed.
45*ee417a84SHeiko Carstens 	 */
46*ee417a84SHeiko Carstens 	barrier();
47*ee417a84SHeiko Carstens 	WRITE_ONCE(skey_regions_initialized, 1);
48*ee417a84SHeiko Carstens }
49