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 r1.val = 0; 68 r1.reg.sk = 1; 69 r1.reg.fsc = FSC_4K; 70 r1.reg.key = 0x30; 71 pfmf(r1.val, (unsigned long) pagebuf); 72 skey.val = get_storage_key((unsigned long) pagebuf); 73 report("set 4k", skey.val == 0x30); 74 } 75 76 static void test_1m_key(void) 77 { 78 int i; 79 union r1 r1; 80 81 r1.val = 0; 82 r1.reg.sk = 1; 83 r1.reg.fsc = FSC_1M; 84 r1.reg.key = 0x30; 85 pfmf(r1.val, (unsigned long) pagebuf); 86 for (i = 0; i < 256; i++) { 87 if (get_storage_key((unsigned long) pagebuf + i * PAGE_SIZE) != 0x30) { 88 report("set 1M", false); 89 return; 90 } 91 } 92 report("set 1M", true); 93 } 94 95 static void test_4k_clear(void) 96 { 97 union r1 r1; 98 99 r1.val = 0; 100 r1.reg.cf = 1; 101 r1.reg.fsc = FSC_4K; 102 103 memset(pagebuf, 42, PAGE_SIZE); 104 pfmf(r1.val, (unsigned long) pagebuf); 105 report("clear 4k", !memcmp(pagebuf, pagebuf + PAGE_SIZE, PAGE_SIZE)); 106 } 107 108 static void test_1m_clear(void) 109 { 110 int i; 111 union r1 r1; 112 unsigned long sum = 0; 113 114 r1.val = 0; 115 r1.reg.cf = 1; 116 r1.reg.fsc = FSC_1M; 117 118 memset(pagebuf, 42, PAGE_SIZE * 256); 119 pfmf(r1.val, (unsigned long) pagebuf); 120 for (i = 0; i < PAGE_SIZE * 256; i++) 121 sum |= pagebuf[i]; 122 report("clear 1m", !sum); 123 } 124 125 int main(void) 126 { 127 bool has_edat = test_facility(8); 128 129 report_prefix_push("pfmf"); 130 if (!has_edat) { 131 report_skip("PFMF is not available"); 132 goto done; 133 } 134 135 test_priv(); 136 /* Force the buffer pages in */ 137 memset(pagebuf, 0, PAGE_SIZE * 256); 138 139 test_4k_key(); 140 test_1m_key(); 141 test_4k_clear(); 142 test_1m_clear(); 143 144 done: 145 report_prefix_pop(); 146 return report_summary(); 147 } 148