1f6b354fbSJanosch Frank /* 2f6b354fbSJanosch Frank * Storage key tests 3f6b354fbSJanosch Frank * 4f6b354fbSJanosch Frank * Copyright (c) 2018 IBM Corp 5f6b354fbSJanosch Frank * 6f6b354fbSJanosch Frank * Authors: 7f6b354fbSJanosch Frank * Janosch Frank <frankja@linux.vnet.ibm.com> 8f6b354fbSJanosch Frank * 9f6b354fbSJanosch Frank * This code is free software; you can redistribute it and/or modify it 10f6b354fbSJanosch Frank * under the terms of the GNU Library General Public License version 2. 11f6b354fbSJanosch Frank */ 12f6b354fbSJanosch Frank #include <libcflat.h> 13f6b354fbSJanosch Frank #include <asm/asm-offsets.h> 14f6b354fbSJanosch Frank #include <asm/interrupt.h> 15f6b354fbSJanosch Frank #include <asm/page.h> 16f6b354fbSJanosch Frank #include <asm/facility.h> 17f6b354fbSJanosch Frank #include <asm/mem.h> 18f6b354fbSJanosch Frank 19f6b354fbSJanosch Frank 20f6b354fbSJanosch Frank static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); 21f6b354fbSJanosch Frank 22f6b354fbSJanosch Frank static void test_set_mb(void) 23f6b354fbSJanosch Frank { 24f6b354fbSJanosch Frank union skey skey, ret1, ret2; 257b9ca995SJanosch Frank void *addr = (void *)0x10000 - 2 * PAGE_SIZE; 267b9ca995SJanosch Frank void *end = (void *)0x10000; 27f6b354fbSJanosch Frank 28f6b354fbSJanosch Frank /* Multi block support came with EDAT 1 */ 29f6b354fbSJanosch Frank if (!test_facility(8)) 30f6b354fbSJanosch Frank return; 31f6b354fbSJanosch Frank 32f6b354fbSJanosch Frank skey.val = 0x30; 33f6b354fbSJanosch Frank while (addr < end) 34f6b354fbSJanosch Frank addr = set_storage_key_mb(addr, skey.val); 35f6b354fbSJanosch Frank 36d0bfafdfSJanosch Frank ret1.val = get_storage_key(end - PAGE_SIZE) & (SKEY_ACC | SKEY_FP); 37d0bfafdfSJanosch Frank ret2.val = get_storage_key(end - PAGE_SIZE * 2) & (SKEY_ACC | SKEY_FP); 38*a299895bSThomas Huth report(ret1.val == ret2.val && ret1.val == skey.val, "multi block"); 39f6b354fbSJanosch Frank } 40f6b354fbSJanosch Frank 41f6b354fbSJanosch Frank static void test_chg(void) 42f6b354fbSJanosch Frank { 43f6b354fbSJanosch Frank union skey skey1, skey2; 44f6b354fbSJanosch Frank 45f6b354fbSJanosch Frank skey1.val = 0x30; 467b9ca995SJanosch Frank set_storage_key(pagebuf, skey1.val, 0); 477b9ca995SJanosch Frank skey1.val = get_storage_key(pagebuf); 48f6b354fbSJanosch Frank pagebuf[0] = 3; 497b9ca995SJanosch Frank skey2.val = get_storage_key(pagebuf); 50*a299895bSThomas Huth report(!skey1.str.ch && skey2.str.ch, "chg bit test"); 51f6b354fbSJanosch Frank } 52f6b354fbSJanosch Frank 53f6b354fbSJanosch Frank static void test_set(void) 54f6b354fbSJanosch Frank { 55f6b354fbSJanosch Frank union skey skey, ret; 56f6b354fbSJanosch Frank 57f6b354fbSJanosch Frank skey.val = 0x30; 587b9ca995SJanosch Frank ret.val = get_storage_key(pagebuf); 597b9ca995SJanosch Frank set_storage_key(pagebuf, skey.val, 0); 607b9ca995SJanosch Frank ret.val = get_storage_key(pagebuf); 61d0bfafdfSJanosch Frank /* 62d0bfafdfSJanosch Frank * For all set tests we only test the ACC and FP bits. RF and 63d0bfafdfSJanosch Frank * CH are set by the machine for memory references and changes 64d0bfafdfSJanosch Frank * and hence might change between a set and a get. 65d0bfafdfSJanosch Frank */ 66*a299895bSThomas Huth report(skey.str.acc == ret.str.acc && skey.str.fp == ret.str.fp, 67*a299895bSThomas Huth "set key test"); 68f6b354fbSJanosch Frank } 69f6b354fbSJanosch Frank 701018ec15SThomas Huth /* Returns true if we are running under z/VM 6.x */ 711018ec15SThomas Huth static bool check_for_zvm6(void) 721018ec15SThomas Huth { 731018ec15SThomas Huth int dcbt; /* Descriptor block count */ 741018ec15SThomas Huth int nr; 751018ec15SThomas Huth static const unsigned char zvm6[] = { 761018ec15SThomas Huth /* This is "z/VM 6" in EBCDIC */ 771018ec15SThomas Huth 0xa9, 0x61, 0xe5, 0xd4, 0x40, 0x40, 0x40, 0x40, 0xf6 781018ec15SThomas Huth }; 791018ec15SThomas Huth 801018ec15SThomas Huth if (stsi(pagebuf, 3, 2, 2)) 811018ec15SThomas Huth return false; 821018ec15SThomas Huth 831018ec15SThomas Huth dcbt = pagebuf[31] & 0xf; 841018ec15SThomas Huth 851018ec15SThomas Huth for (nr = 0; nr < dcbt; nr++) { 861018ec15SThomas Huth if (!memcmp(&pagebuf[32 + nr * 64 + 24], zvm6, sizeof(zvm6))) 871018ec15SThomas Huth return true; 881018ec15SThomas Huth } 891018ec15SThomas Huth 901018ec15SThomas Huth return false; 911018ec15SThomas Huth } 921018ec15SThomas Huth 93f6b354fbSJanosch Frank static void test_priv(void) 94f6b354fbSJanosch Frank { 95f6b354fbSJanosch Frank union skey skey; 961018ec15SThomas Huth bool is_zvm6 = check_for_zvm6(); 97f6b354fbSJanosch Frank 98f6b354fbSJanosch Frank memset(pagebuf, 0, PAGE_SIZE * 2); 99e4654a1bSJanosch Frank report_prefix_push("privileged"); 100e4654a1bSJanosch Frank report_prefix_push("sske"); 101f6b354fbSJanosch Frank expect_pgm_int(); 102f6b354fbSJanosch Frank enter_pstate(); 1037b9ca995SJanosch Frank set_storage_key(pagebuf, 0x30, 0); 104f6b354fbSJanosch Frank check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 105e4654a1bSJanosch Frank report_prefix_pop(); 106f6b354fbSJanosch Frank 1077b9ca995SJanosch Frank skey.val = get_storage_key(pagebuf); 108*a299895bSThomas Huth report(skey.str.acc != 3, "skey did not change on exception"); 109f6b354fbSJanosch Frank 110e4654a1bSJanosch Frank report_prefix_push("iske"); 1111018ec15SThomas Huth if (is_zvm6) { 1121018ec15SThomas Huth /* There is a known bug with z/VM 6, so skip the test there */ 1131018ec15SThomas Huth report_skip("not working on z/VM 6"); 1141018ec15SThomas Huth } else { 115f6b354fbSJanosch Frank expect_pgm_int(); 116f6b354fbSJanosch Frank enter_pstate(); 1177b9ca995SJanosch Frank get_storage_key(pagebuf); 118f6b354fbSJanosch Frank check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 1191018ec15SThomas Huth } 120e4654a1bSJanosch Frank report_prefix_pop(); 121e4654a1bSJanosch Frank 122e4654a1bSJanosch Frank report_prefix_pop(); 123f6b354fbSJanosch Frank } 124f6b354fbSJanosch Frank 125f6b354fbSJanosch Frank int main(void) 126f6b354fbSJanosch Frank { 127f6b354fbSJanosch Frank report_prefix_push("skey"); 12847df95c7SJanosch Frank if (test_facility(169)) { 12947df95c7SJanosch Frank report_skip("storage key removal facility is active"); 13047df95c7SJanosch Frank goto done; 13147df95c7SJanosch Frank } 132f6b354fbSJanosch Frank test_priv(); 133f6b354fbSJanosch Frank test_set(); 134f6b354fbSJanosch Frank test_set_mb(); 135f6b354fbSJanosch Frank test_chg(); 13647df95c7SJanosch Frank done: 137f6b354fbSJanosch Frank report_prefix_pop(); 138f6b354fbSJanosch Frank return report_summary(); 139f6b354fbSJanosch Frank } 140