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