12c96b77eSJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */ 22c96b77eSJanosch Frank /* 32c96b77eSJanosch Frank * PV virtualization interception tests for diagnose instructions. 42c96b77eSJanosch Frank * 52c96b77eSJanosch Frank * Copyright (c) 2021 IBM Corp 62c96b77eSJanosch Frank * 72c96b77eSJanosch Frank * Authors: 82c96b77eSJanosch Frank * Janosch Frank <frankja@linux.ibm.com> 92c96b77eSJanosch Frank */ 102c96b77eSJanosch Frank #include <libcflat.h> 112c96b77eSJanosch Frank #include <snippet.h> 122c96b77eSJanosch Frank #include <sie.h> 13c4082444SJanosch Frank #include <sclp.h> 14c4082444SJanosch Frank #include <asm/facility.h> 152c96b77eSJanosch Frank 162c96b77eSJanosch Frank static struct vm vm; 172c96b77eSJanosch Frank 182c96b77eSJanosch Frank static void test_diag_500(void) 192c96b77eSJanosch Frank { 202c96b77eSJanosch Frank extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_500)[]; 212c96b77eSJanosch Frank extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_500)[]; 222c96b77eSJanosch Frank extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_500)[]; 232c96b77eSJanosch Frank extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_500)[]; 242c96b77eSJanosch Frank int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_500); 252c96b77eSJanosch Frank int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_500); 262c96b77eSJanosch Frank 272c96b77eSJanosch Frank report_prefix_push("diag 0x500"); 282c96b77eSJanosch Frank 292c96b77eSJanosch Frank snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_500), 302c96b77eSJanosch Frank SNIPPET_HDR_START(asm, snippet_pv_diag_500), 31*b36f35a8SJanosch Frank size_gbin, size_hdr, SNIPPET_UNPACK_OFF); 322c96b77eSJanosch Frank 332c96b77eSJanosch Frank sie(&vm); 342c96b77eSJanosch Frank report(vm.sblk->icptcode == ICPT_PV_INSTR && vm.sblk->ipa == 0x8302 && 352c96b77eSJanosch Frank vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x500, 362c96b77eSJanosch Frank "intercept values"); 372c96b77eSJanosch Frank report(vm.save_area.guest.grs[1] == 1 && 382c96b77eSJanosch Frank vm.save_area.guest.grs[2] == 2 && 392c96b77eSJanosch Frank vm.save_area.guest.grs[3] == 3 && 402c96b77eSJanosch Frank vm.save_area.guest.grs[4] == 4, 412c96b77eSJanosch Frank "register values"); 422c96b77eSJanosch Frank /* 432c96b77eSJanosch Frank * Check if we can inject a PGM operand which we are always 442c96b77eSJanosch Frank * allowed to do after a diag500 exit. 452c96b77eSJanosch Frank */ 462c96b77eSJanosch Frank vm.sblk->iictl = IICTL_CODE_OPERAND; 472c96b77eSJanosch Frank sie(&vm); 482c96b77eSJanosch Frank report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 && 492c96b77eSJanosch Frank vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c 502c96b77eSJanosch Frank && vm.save_area.guest.grs[0] == PGM_INT_CODE_OPERAND, 512c96b77eSJanosch Frank "operand exception"); 522c96b77eSJanosch Frank 532c96b77eSJanosch Frank /* 542c96b77eSJanosch Frank * Check if we can inject a PGM specification which we are always 552c96b77eSJanosch Frank * allowed to do after a diag500 exit. 562c96b77eSJanosch Frank */ 572c96b77eSJanosch Frank sie(&vm); 582c96b77eSJanosch Frank vm.sblk->iictl = IICTL_CODE_SPECIFICATION; 592c96b77eSJanosch Frank /* Inject PGM, next exit should be 9c */ 602c96b77eSJanosch Frank sie(&vm); 612c96b77eSJanosch Frank report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 && 622c96b77eSJanosch Frank vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c 632c96b77eSJanosch Frank && vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION, 642c96b77eSJanosch Frank "specification exception"); 652c96b77eSJanosch Frank 662c96b77eSJanosch Frank /* No need for cleanup, just tear down the VM */ 672c96b77eSJanosch Frank uv_destroy_guest(&vm); 682c96b77eSJanosch Frank 692c96b77eSJanosch Frank report_prefix_pop(); 702c96b77eSJanosch Frank } 712c96b77eSJanosch Frank 722c96b77eSJanosch Frank 732c96b77eSJanosch Frank static void test_diag_288(void) 742c96b77eSJanosch Frank { 752c96b77eSJanosch Frank extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_288)[]; 762c96b77eSJanosch Frank extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_288)[]; 772c96b77eSJanosch Frank extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_288)[]; 782c96b77eSJanosch Frank extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_288)[]; 792c96b77eSJanosch Frank int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_288); 802c96b77eSJanosch Frank int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_288); 812c96b77eSJanosch Frank 822c96b77eSJanosch Frank report_prefix_push("diag 0x288"); 832c96b77eSJanosch Frank 842c96b77eSJanosch Frank snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_288), 852c96b77eSJanosch Frank SNIPPET_HDR_START(asm, snippet_pv_diag_288), 86*b36f35a8SJanosch Frank size_gbin, size_hdr, SNIPPET_UNPACK_OFF); 872c96b77eSJanosch Frank 882c96b77eSJanosch Frank sie(&vm); 892c96b77eSJanosch Frank report(vm.sblk->icptcode == ICPT_PV_INSTR && vm.sblk->ipa == 0x8302 && 902c96b77eSJanosch Frank vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x288, 912c96b77eSJanosch Frank "intercept values"); 922c96b77eSJanosch Frank report(vm.save_area.guest.grs[0] == 1 && 932c96b77eSJanosch Frank vm.save_area.guest.grs[1] == 2 && 942c96b77eSJanosch Frank vm.save_area.guest.grs[2] == 3, 952c96b77eSJanosch Frank "register values"); 962c96b77eSJanosch Frank 972c96b77eSJanosch Frank /* 982c96b77eSJanosch Frank * Check if we can inject a PGM spec which we are always 992c96b77eSJanosch Frank * allowed to do after a diag288 exit. 1002c96b77eSJanosch Frank */ 1012c96b77eSJanosch Frank vm.sblk->iictl = IICTL_CODE_SPECIFICATION; 1022c96b77eSJanosch Frank sie(&vm); 1032c96b77eSJanosch Frank report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 && 1042c96b77eSJanosch Frank vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c 1052c96b77eSJanosch Frank && vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION, 1062c96b77eSJanosch Frank "specification exception"); 1072c96b77eSJanosch Frank 1082c96b77eSJanosch Frank /* No need for cleanup, just tear down the VM */ 1092c96b77eSJanosch Frank uv_destroy_guest(&vm); 1102c96b77eSJanosch Frank 1112c96b77eSJanosch Frank report_prefix_pop(); 1122c96b77eSJanosch Frank } 1132c96b77eSJanosch Frank 1142c96b77eSJanosch Frank static void test_diag_yield(void) 1152c96b77eSJanosch Frank { 1162c96b77eSJanosch Frank extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_yield)[]; 1172c96b77eSJanosch Frank extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_yield)[]; 1182c96b77eSJanosch Frank extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_yield)[]; 1192c96b77eSJanosch Frank extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_yield)[]; 1202c96b77eSJanosch Frank int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_yield); 1212c96b77eSJanosch Frank int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_yield); 1222c96b77eSJanosch Frank 1232c96b77eSJanosch Frank report_prefix_push("diag yield"); 1242c96b77eSJanosch Frank 1252c96b77eSJanosch Frank snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_yield), 1262c96b77eSJanosch Frank SNIPPET_HDR_START(asm, snippet_pv_diag_yield), 127*b36f35a8SJanosch Frank size_gbin, size_hdr, SNIPPET_UNPACK_OFF); 1282c96b77eSJanosch Frank 1292c96b77eSJanosch Frank /* 0x44 */ 1302c96b77eSJanosch Frank report_prefix_push("0x44"); 1312c96b77eSJanosch Frank sie(&vm); 1322c96b77eSJanosch Frank report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 && 1332c96b77eSJanosch Frank vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x44, 1342c96b77eSJanosch Frank "intercept values"); 1352c96b77eSJanosch Frank report_prefix_pop(); 1362c96b77eSJanosch Frank 1372c96b77eSJanosch Frank /* 0x9c */ 1382c96b77eSJanosch Frank report_prefix_push("0x9c"); 1392c96b77eSJanosch Frank sie(&vm); 1402c96b77eSJanosch Frank report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 && 1412c96b77eSJanosch Frank vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c, 1422c96b77eSJanosch Frank "intercept values"); 1432c96b77eSJanosch Frank report(vm.save_area.guest.grs[0] == 42, "r1 correct"); 1442c96b77eSJanosch Frank report_prefix_pop(); 1452c96b77eSJanosch Frank 1462c96b77eSJanosch Frank uv_destroy_guest(&vm); 1472c96b77eSJanosch Frank report_prefix_pop(); 1482c96b77eSJanosch Frank } 1492c96b77eSJanosch Frank 1502c96b77eSJanosch Frank 1512c96b77eSJanosch Frank int main(void) 1522c96b77eSJanosch Frank { 1532c96b77eSJanosch Frank report_prefix_push("pv-diags"); 1542c96b77eSJanosch Frank if (!test_facility(158)) { 1552c96b77eSJanosch Frank report_skip("UV Call facility unavailable"); 1562c96b77eSJanosch Frank goto done; 1572c96b77eSJanosch Frank } 1582c96b77eSJanosch Frank if (!sclp_facilities.has_sief2) { 1592c96b77eSJanosch Frank report_skip("SIEF2 facility unavailable"); 1602c96b77eSJanosch Frank goto done; 1612c96b77eSJanosch Frank } 1622c96b77eSJanosch Frank 1632c96b77eSJanosch Frank uv_setup_asces(); 1642c96b77eSJanosch Frank snippet_setup_guest(&vm, true); 1652c96b77eSJanosch Frank test_diag_yield(); 1662c96b77eSJanosch Frank test_diag_288(); 1672c96b77eSJanosch Frank test_diag_500(); 1682c96b77eSJanosch Frank sie_guest_destroy(&vm); 1692c96b77eSJanosch Frank 1702c96b77eSJanosch Frank done: 1712c96b77eSJanosch Frank report_prefix_pop(); 1722c96b77eSJanosch Frank return report_summary(); 1732c96b77eSJanosch Frank } 174