1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * PV virtualization interception tests for diagnose instructions. 4 * 5 * Copyright (c) 2021 IBM Corp 6 * 7 * Authors: 8 * Janosch Frank <frankja@linux.ibm.com> 9 */ 10 #include <libcflat.h> 11 #include <asm/asm-offsets.h> 12 #include <asm-generic/barrier.h> 13 #include <asm/interrupt.h> 14 #include <asm/pgtable.h> 15 #include <mmu.h> 16 #include <asm/page.h> 17 #include <asm/facility.h> 18 #include <asm/mem.h> 19 #include <asm/sigp.h> 20 #include <smp.h> 21 #include <alloc_page.h> 22 #include <vmalloc.h> 23 #include <sclp.h> 24 #include <snippet.h> 25 #include <sie.h> 26 #include <uv.h> 27 #include <asm/uv.h> 28 29 static struct vm vm; 30 31 static void test_diag_500(void) 32 { 33 extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_500)[]; 34 extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_500)[]; 35 extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_500)[]; 36 extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_500)[]; 37 int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_500); 38 int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_500); 39 40 report_prefix_push("diag 0x500"); 41 42 snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_500), 43 SNIPPET_HDR_START(asm, snippet_pv_diag_500), 44 size_gbin, size_hdr, SNIPPET_OFF_ASM); 45 46 sie(&vm); 47 report(vm.sblk->icptcode == ICPT_PV_INSTR && vm.sblk->ipa == 0x8302 && 48 vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x500, 49 "intercept values"); 50 report(vm.save_area.guest.grs[1] == 1 && 51 vm.save_area.guest.grs[2] == 2 && 52 vm.save_area.guest.grs[3] == 3 && 53 vm.save_area.guest.grs[4] == 4, 54 "register values"); 55 /* 56 * Check if we can inject a PGM operand which we are always 57 * allowed to do after a diag500 exit. 58 */ 59 vm.sblk->iictl = IICTL_CODE_OPERAND; 60 sie(&vm); 61 report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 && 62 vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c 63 && vm.save_area.guest.grs[0] == PGM_INT_CODE_OPERAND, 64 "operand exception"); 65 66 /* 67 * Check if we can inject a PGM specification which we are always 68 * allowed to do after a diag500 exit. 69 */ 70 sie(&vm); 71 vm.sblk->iictl = IICTL_CODE_SPECIFICATION; 72 /* Inject PGM, next exit should be 9c */ 73 sie(&vm); 74 report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 && 75 vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c 76 && vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION, 77 "specification exception"); 78 79 /* No need for cleanup, just tear down the VM */ 80 uv_destroy_guest(&vm); 81 82 report_prefix_pop(); 83 } 84 85 86 static void test_diag_288(void) 87 { 88 extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_288)[]; 89 extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_288)[]; 90 extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_288)[]; 91 extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_288)[]; 92 int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_288); 93 int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_288); 94 95 report_prefix_push("diag 0x288"); 96 97 snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_288), 98 SNIPPET_HDR_START(asm, snippet_pv_diag_288), 99 size_gbin, size_hdr, SNIPPET_OFF_ASM); 100 101 sie(&vm); 102 report(vm.sblk->icptcode == ICPT_PV_INSTR && vm.sblk->ipa == 0x8302 && 103 vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x288, 104 "intercept values"); 105 report(vm.save_area.guest.grs[0] == 1 && 106 vm.save_area.guest.grs[1] == 2 && 107 vm.save_area.guest.grs[2] == 3, 108 "register values"); 109 110 /* 111 * Check if we can inject a PGM spec which we are always 112 * allowed to do after a diag288 exit. 113 */ 114 vm.sblk->iictl = IICTL_CODE_SPECIFICATION; 115 sie(&vm); 116 report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 && 117 vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c 118 && vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION, 119 "specification exception"); 120 121 /* No need for cleanup, just tear down the VM */ 122 uv_destroy_guest(&vm); 123 124 report_prefix_pop(); 125 } 126 127 static void test_diag_yield(void) 128 { 129 extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_yield)[]; 130 extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_yield)[]; 131 extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_yield)[]; 132 extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_yield)[]; 133 int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_yield); 134 int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_yield); 135 136 report_prefix_push("diag yield"); 137 138 snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_yield), 139 SNIPPET_HDR_START(asm, snippet_pv_diag_yield), 140 size_gbin, size_hdr, SNIPPET_OFF_ASM); 141 142 /* 0x44 */ 143 report_prefix_push("0x44"); 144 sie(&vm); 145 report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 && 146 vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x44, 147 "intercept values"); 148 report_prefix_pop(); 149 150 /* 0x9c */ 151 report_prefix_push("0x9c"); 152 sie(&vm); 153 report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 && 154 vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c, 155 "intercept values"); 156 report(vm.save_area.guest.grs[0] == 42, "r1 correct"); 157 report_prefix_pop(); 158 159 uv_destroy_guest(&vm); 160 report_prefix_pop(); 161 } 162 163 164 int main(void) 165 { 166 report_prefix_push("pv-diags"); 167 if (!test_facility(158)) { 168 report_skip("UV Call facility unavailable"); 169 goto done; 170 } 171 if (!sclp_facilities.has_sief2) { 172 report_skip("SIEF2 facility unavailable"); 173 goto done; 174 } 175 176 uv_setup_asces(); 177 snippet_setup_guest(&vm, true); 178 test_diag_yield(); 179 test_diag_288(); 180 test_diag_500(); 181 sie_guest_destroy(&vm); 182 183 done: 184 report_prefix_pop(); 185 return report_summary(); 186 } 187