1 /* 2 * Perform Frame Management Function (pfmf) tests 3 * 4 * Copyright (c) 2018 IBM 5 * 6 * Authors: 7 * Janosch Frank <frankja@linux.vnet.ibm.com> 8 * 9 * This code is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU Library General Public License version 2. 11 */ 12 #include <libcflat.h> 13 #include <asm/asm-offsets.h> 14 #include <asm/interrupt.h> 15 #include <asm/page.h> 16 #include <asm/facility.h> 17 #include <asm/mem.h> 18 19 #define FSC_4K 0 20 #define FSC_1M 1 21 #define FSC_2G 2 22 23 union r1 { 24 struct { 25 unsigned long pad0 : 32; 26 unsigned long pad1 : 12; 27 unsigned long pad_fmfi : 2; 28 unsigned long sk : 1; /* set key*/ 29 unsigned long cf : 1; /* clear frame */ 30 unsigned long ui : 1; /* usage indication */ 31 unsigned long fsc : 3; 32 unsigned long pad2 : 1; 33 unsigned long mr : 1; 34 unsigned long mc : 1; 35 unsigned long pad3 : 1; 36 unsigned long key : 8; /* storage keys */ 37 } reg; 38 unsigned long val; 39 }; 40 41 static uint8_t pagebuf[PAGE_SIZE * 256] __attribute__((aligned(PAGE_SIZE * 256))); 42 43 static inline unsigned long pfmf(unsigned long r1, unsigned long paddr) 44 { 45 register uint64_t addr asm("1") = paddr; 46 47 asm volatile(".insn rre,0xb9af0000,%[r1],%[addr]" 48 : [addr] "+a" (addr) : [r1] "d" (r1) : "memory"); 49 return addr; 50 } 51 52 static void test_priv(void) 53 { 54 report_prefix_push("privileged"); 55 expect_pgm_int(); 56 enter_pstate(); 57 pfmf(0, (unsigned long) pagebuf); 58 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 59 report_prefix_pop(); 60 } 61 62 static void test_4k_key(void) 63 { 64 union r1 r1; 65 union skey skey; 66 67 report_prefix_push("4K"); 68 r1.val = 0; 69 r1.reg.sk = 1; 70 r1.reg.fsc = FSC_4K; 71 r1.reg.key = 0x30; 72 pfmf(r1.val, (unsigned long) pagebuf); 73 skey.val = get_storage_key((unsigned long) pagebuf); 74 skey.val &= SKEY_ACC | SKEY_FP; 75 report("set storage keys", skey.val == 0x30); 76 report_prefix_pop(); 77 } 78 79 static void test_1m_key(void) 80 { 81 int i; 82 bool rp = true; 83 union r1 r1; 84 union skey skey; 85 86 report_prefix_push("1M"); 87 r1.val = 0; 88 r1.reg.sk = 1; 89 r1.reg.fsc = FSC_1M; 90 r1.reg.key = 0x30; 91 pfmf(r1.val, (unsigned long) pagebuf); 92 for (i = 0; i < 256; i++) { 93 skey.val = get_storage_key((unsigned long) pagebuf + i * PAGE_SIZE); 94 skey.val &= SKEY_ACC | SKEY_FP; 95 if (skey.val != 0x30) { 96 rp = false; 97 break; 98 } 99 } 100 report("set storage keys", rp); 101 report_prefix_pop(); 102 } 103 104 static void test_4k_clear(void) 105 { 106 union r1 r1; 107 108 r1.val = 0; 109 r1.reg.cf = 1; 110 r1.reg.fsc = FSC_4K; 111 112 report_prefix_push("4K"); 113 memset(pagebuf, 42, PAGE_SIZE); 114 pfmf(r1.val, (unsigned long) pagebuf); 115 report("clear memory", !memcmp(pagebuf, pagebuf + PAGE_SIZE, PAGE_SIZE)); 116 report_prefix_pop(); 117 } 118 119 static void test_1m_clear(void) 120 { 121 int i; 122 union r1 r1; 123 unsigned long sum = 0; 124 125 r1.val = 0; 126 r1.reg.cf = 1; 127 r1.reg.fsc = FSC_1M; 128 129 report_prefix_push("1M"); 130 memset(pagebuf, 42, PAGE_SIZE * 256); 131 pfmf(r1.val, (unsigned long) pagebuf); 132 for (i = 0; i < PAGE_SIZE * 256; i++) 133 sum |= pagebuf[i]; 134 report("clear memory", !sum); 135 report_prefix_pop(); 136 } 137 138 int main(void) 139 { 140 bool has_edat = test_facility(8); 141 142 report_prefix_push("pfmf"); 143 if (!has_edat) { 144 report_skip("PFMF is not available"); 145 goto done; 146 } 147 148 test_priv(); 149 /* Force the buffer pages in */ 150 memset(pagebuf, 0, PAGE_SIZE * 256); 151 152 test_4k_key(); 153 test_4k_clear(); 154 test_1m_key(); 155 test_1m_clear(); 156 157 done: 158 report_prefix_pop(); 159 return report_summary(); 160 } 161