| // 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])" | |
| : [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); | |
| } |