1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Perform Frame Management Function (pfmf) tests 4 * 5 * Copyright (c) 2018 IBM 6 * 7 * Authors: 8 * Janosch Frank <frankja@linux.vnet.ibm.com> 9 */ 10 #include <libcflat.h> 11 #include <asm/asm-offsets.h> 12 #include <asm/interrupt.h> 13 #include <asm/page.h> 14 #include <asm/facility.h> 15 #include <asm/mem.h> 16 17 static uint8_t pagebuf[PAGE_SIZE * 256] __attribute__((aligned(PAGE_SIZE * 256))); 18 19 static void test_priv(void) 20 { 21 report_prefix_push("privileged"); 22 expect_pgm_int(); 23 enter_pstate(); 24 pfmf(0, pagebuf); 25 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 26 report_prefix_pop(); 27 } 28 29 static void test_4k_key(void) 30 { 31 union pfmf_r1 r1 = { 32 .reg.sk = 1, 33 .reg.fsc = PFMF_FSC_4K, 34 .reg.key = 0x30, 35 }; 36 union skey skey; 37 38 report_prefix_push("4K"); 39 if (test_facility(169)) { 40 report_skip("storage key removal facility is active"); 41 goto out; 42 } 43 pfmf(r1.val, pagebuf); 44 skey.val = get_storage_key(pagebuf); 45 skey.val &= SKEY_ACC | SKEY_FP; 46 report(skey.val == 0x30, "set storage keys"); 47 out: 48 report_prefix_pop(); 49 } 50 51 static void test_1m_key(void) 52 { 53 int i; 54 bool rp = true; 55 union skey skey; 56 union pfmf_r1 r1 = { 57 .reg.fsc = PFMF_FSC_1M, 58 .reg.key = 0x30, 59 .reg.sk = 1, 60 }; 61 62 report_prefix_push("1M"); 63 if (test_facility(169)) { 64 report_skip("storage key removal facility is active"); 65 goto out; 66 } 67 68 pfmf(r1.val, pagebuf); 69 for (i = 0; i < 256; i++) { 70 skey.val = get_storage_key(pagebuf + i * PAGE_SIZE); 71 skey.val &= SKEY_ACC | SKEY_FP; 72 if (skey.val != 0x30) { 73 rp = false; 74 break; 75 } 76 } 77 report(rp, "set storage keys"); 78 out: 79 report_prefix_pop(); 80 } 81 82 static void test_4k_clear(void) 83 { 84 union pfmf_r1 r1 = { 85 .reg.cf = 1, 86 .reg.fsc = PFMF_FSC_4K, 87 }; 88 89 report_prefix_push("4K"); 90 memset(pagebuf, 42, PAGE_SIZE); 91 pfmf(r1.val, pagebuf); 92 report(!memcmp(pagebuf, pagebuf + PAGE_SIZE, PAGE_SIZE), 93 "clear memory"); 94 report_prefix_pop(); 95 } 96 97 static void test_1m_clear(void) 98 { 99 int i; 100 union pfmf_r1 r1 = { 101 .reg.cf = 1, 102 .reg.fsc = PFMF_FSC_1M, 103 }; 104 unsigned long sum = 0; 105 106 report_prefix_push("1M"); 107 memset(pagebuf, 42, PAGE_SIZE * 256); 108 pfmf(r1.val, pagebuf); 109 for (i = 0; i < PAGE_SIZE * 256; i++) 110 sum |= pagebuf[i]; 111 report(!sum, "clear memory"); 112 report_prefix_pop(); 113 } 114 115 static void test_low_addr_prot(void) 116 { 117 union pfmf_r1 r1 = { 118 .reg.cf = 1, 119 .reg.fsc = PFMF_FSC_4K 120 }; 121 122 report_prefix_push("low-address protection"); 123 124 report_prefix_push("0x1000"); 125 expect_pgm_int(); 126 low_prot_enable(); 127 pfmf(r1.val, (void *)0x1000); 128 low_prot_disable(); 129 check_pgm_int_code(PGM_INT_CODE_PROTECTION); 130 report_prefix_pop(); 131 132 report_prefix_push("0x0"); 133 expect_pgm_int(); 134 low_prot_enable(); 135 pfmf(r1.val, 0); 136 low_prot_disable(); 137 check_pgm_int_code(PGM_INT_CODE_PROTECTION); 138 report_prefix_pop(); 139 140 report_prefix_pop(); 141 } 142 143 int main(void) 144 { 145 bool has_edat = test_facility(8); 146 147 report_prefix_push("pfmf"); 148 if (!has_edat) { 149 report_skip("PFMF is not available"); 150 goto done; 151 } 152 153 test_priv(); 154 test_low_addr_prot(); 155 /* Force the buffer pages in */ 156 memset(pagebuf, 0, PAGE_SIZE * 256); 157 158 test_4k_key(); 159 test_4k_clear(); 160 test_1m_key(); 161 test_1m_clear(); 162 163 done: 164 report_prefix_pop(); 165 return report_summary(); 166 } 167