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