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> 12617f251fSJanosch Frank #include <pv_icptdata.h> 132c96b77eSJanosch Frank #include <sie.h> 14c4082444SJanosch Frank #include <sclp.h> 15c4082444SJanosch Frank #include <asm/facility.h> 162c96b77eSJanosch Frank 172c96b77eSJanosch Frank static struct vm vm; 182c96b77eSJanosch Frank 192c96b77eSJanosch Frank static void test_diag_500(void) 202c96b77eSJanosch Frank { 21*1d0f08f4SJanosch Frank extern const char SNIPPET_NAME_START(asm, pv_diag_500)[]; 22*1d0f08f4SJanosch Frank extern const char SNIPPET_NAME_END(asm, pv_diag_500)[]; 23*1d0f08f4SJanosch Frank extern const char SNIPPET_HDR_START(asm, pv_diag_500)[]; 24*1d0f08f4SJanosch Frank extern const char SNIPPET_HDR_END(asm, pv_diag_500)[]; 25*1d0f08f4SJanosch Frank int size_hdr = SNIPPET_HDR_LEN(asm, pv_diag_500); 26*1d0f08f4SJanosch Frank int size_gbin = SNIPPET_LEN(asm, pv_diag_500); 272c96b77eSJanosch Frank 282c96b77eSJanosch Frank report_prefix_push("diag 0x500"); 292c96b77eSJanosch Frank 30*1d0f08f4SJanosch Frank snippet_pv_init(&vm, SNIPPET_NAME_START(asm, pv_diag_500), 31*1d0f08f4SJanosch Frank SNIPPET_HDR_START(asm, pv_diag_500), 32b36f35a8SJanosch Frank size_gbin, size_hdr, SNIPPET_UNPACK_OFF); 332c96b77eSJanosch Frank 342c96b77eSJanosch Frank sie(&vm); 35617f251fSJanosch Frank report(pv_icptdata_check_diag(&vm, 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); 48617f251fSJanosch Frank report(pv_icptdata_check_diag(&vm, 0x9c) && 49617f251fSJanosch Frank vm.save_area.guest.grs[0] == PGM_INT_CODE_OPERAND, 502c96b77eSJanosch Frank "operand exception"); 512c96b77eSJanosch Frank 522c96b77eSJanosch Frank /* 532c96b77eSJanosch Frank * Check if we can inject a PGM specification which we are always 542c96b77eSJanosch Frank * allowed to do after a diag500 exit. 552c96b77eSJanosch Frank */ 562c96b77eSJanosch Frank sie(&vm); 572c96b77eSJanosch Frank vm.sblk->iictl = IICTL_CODE_SPECIFICATION; 582c96b77eSJanosch Frank /* Inject PGM, next exit should be 9c */ 592c96b77eSJanosch Frank sie(&vm); 60617f251fSJanosch Frank report(pv_icptdata_check_diag(&vm, 0x9c) && 61617f251fSJanosch Frank vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION, 622c96b77eSJanosch Frank "specification exception"); 632c96b77eSJanosch Frank 642c96b77eSJanosch Frank /* No need for cleanup, just tear down the VM */ 652c96b77eSJanosch Frank uv_destroy_guest(&vm); 662c96b77eSJanosch Frank 672c96b77eSJanosch Frank report_prefix_pop(); 682c96b77eSJanosch Frank } 692c96b77eSJanosch Frank 702c96b77eSJanosch Frank 712c96b77eSJanosch Frank static void test_diag_288(void) 722c96b77eSJanosch Frank { 73*1d0f08f4SJanosch Frank extern const char SNIPPET_NAME_START(asm, pv_diag_288)[]; 74*1d0f08f4SJanosch Frank extern const char SNIPPET_NAME_END(asm, pv_diag_288)[]; 75*1d0f08f4SJanosch Frank extern const char SNIPPET_HDR_START(asm, pv_diag_288)[]; 76*1d0f08f4SJanosch Frank extern const char SNIPPET_HDR_END(asm, pv_diag_288)[]; 77*1d0f08f4SJanosch Frank int size_hdr = SNIPPET_HDR_LEN(asm, pv_diag_288); 78*1d0f08f4SJanosch Frank int size_gbin = SNIPPET_LEN(asm, pv_diag_288); 792c96b77eSJanosch Frank 802c96b77eSJanosch Frank report_prefix_push("diag 0x288"); 812c96b77eSJanosch Frank 82*1d0f08f4SJanosch Frank snippet_pv_init(&vm, SNIPPET_NAME_START(asm, pv_diag_288), 83*1d0f08f4SJanosch Frank SNIPPET_HDR_START(asm, pv_diag_288), 84b36f35a8SJanosch Frank size_gbin, size_hdr, SNIPPET_UNPACK_OFF); 852c96b77eSJanosch Frank 862c96b77eSJanosch Frank sie(&vm); 872c96b77eSJanosch Frank report(vm.sblk->icptcode == ICPT_PV_INSTR && vm.sblk->ipa == 0x8302 && 882c96b77eSJanosch Frank vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x288, 892c96b77eSJanosch Frank "intercept values"); 902c96b77eSJanosch Frank report(vm.save_area.guest.grs[0] == 1 && 912c96b77eSJanosch Frank vm.save_area.guest.grs[1] == 2 && 922c96b77eSJanosch Frank vm.save_area.guest.grs[2] == 3, 932c96b77eSJanosch Frank "register values"); 942c96b77eSJanosch Frank 952c96b77eSJanosch Frank /* 962c96b77eSJanosch Frank * Check if we can inject a PGM spec which we are always 972c96b77eSJanosch Frank * allowed to do after a diag288 exit. 982c96b77eSJanosch Frank */ 992c96b77eSJanosch Frank vm.sblk->iictl = IICTL_CODE_SPECIFICATION; 1002c96b77eSJanosch Frank sie(&vm); 1012c96b77eSJanosch Frank report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 && 1022c96b77eSJanosch Frank vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c 1032c96b77eSJanosch Frank && vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION, 1042c96b77eSJanosch Frank "specification exception"); 1052c96b77eSJanosch Frank 1062c96b77eSJanosch Frank /* No need for cleanup, just tear down the VM */ 1072c96b77eSJanosch Frank uv_destroy_guest(&vm); 1082c96b77eSJanosch Frank 1092c96b77eSJanosch Frank report_prefix_pop(); 1102c96b77eSJanosch Frank } 1112c96b77eSJanosch Frank 1122c96b77eSJanosch Frank static void test_diag_yield(void) 1132c96b77eSJanosch Frank { 114*1d0f08f4SJanosch Frank extern const char SNIPPET_NAME_START(asm, pv_diag_yield)[]; 115*1d0f08f4SJanosch Frank extern const char SNIPPET_NAME_END(asm, pv_diag_yield)[]; 116*1d0f08f4SJanosch Frank extern const char SNIPPET_HDR_START(asm, pv_diag_yield)[]; 117*1d0f08f4SJanosch Frank extern const char SNIPPET_HDR_END(asm, pv_diag_yield)[]; 118*1d0f08f4SJanosch Frank int size_hdr = SNIPPET_HDR_LEN(asm, pv_diag_yield); 119*1d0f08f4SJanosch Frank int size_gbin = SNIPPET_LEN(asm, pv_diag_yield); 1202c96b77eSJanosch Frank 1212c96b77eSJanosch Frank report_prefix_push("diag yield"); 1222c96b77eSJanosch Frank 123*1d0f08f4SJanosch Frank snippet_pv_init(&vm, SNIPPET_NAME_START(asm, pv_diag_yield), 124*1d0f08f4SJanosch Frank SNIPPET_HDR_START(asm, pv_diag_yield), 125b36f35a8SJanosch Frank size_gbin, size_hdr, SNIPPET_UNPACK_OFF); 1262c96b77eSJanosch Frank 1272c96b77eSJanosch Frank /* 0x44 */ 1282c96b77eSJanosch Frank report_prefix_push("0x44"); 1292c96b77eSJanosch Frank sie(&vm); 1302c96b77eSJanosch Frank report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 && 1312c96b77eSJanosch Frank vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x44, 1322c96b77eSJanosch Frank "intercept values"); 1332c96b77eSJanosch Frank report_prefix_pop(); 1342c96b77eSJanosch Frank 1352c96b77eSJanosch Frank /* 0x9c */ 1362c96b77eSJanosch Frank report_prefix_push("0x9c"); 1372c96b77eSJanosch Frank sie(&vm); 1382c96b77eSJanosch Frank report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 && 1392c96b77eSJanosch Frank vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c, 1402c96b77eSJanosch Frank "intercept values"); 1412c96b77eSJanosch Frank report(vm.save_area.guest.grs[0] == 42, "r1 correct"); 1422c96b77eSJanosch Frank report_prefix_pop(); 1432c96b77eSJanosch Frank 1442c96b77eSJanosch Frank uv_destroy_guest(&vm); 1452c96b77eSJanosch Frank report_prefix_pop(); 1462c96b77eSJanosch Frank } 1472c96b77eSJanosch Frank 1482c96b77eSJanosch Frank 1492c96b77eSJanosch Frank int main(void) 1502c96b77eSJanosch Frank { 1512c96b77eSJanosch Frank report_prefix_push("pv-diags"); 1522c96b77eSJanosch Frank if (!test_facility(158)) { 1532c96b77eSJanosch Frank report_skip("UV Call facility unavailable"); 1542c96b77eSJanosch Frank goto done; 1552c96b77eSJanosch Frank } 1562c96b77eSJanosch Frank if (!sclp_facilities.has_sief2) { 1572c96b77eSJanosch Frank report_skip("SIEF2 facility unavailable"); 1582c96b77eSJanosch Frank goto done; 1592c96b77eSJanosch Frank } 1602c96b77eSJanosch Frank 1612c96b77eSJanosch Frank uv_setup_asces(); 1622c96b77eSJanosch Frank snippet_setup_guest(&vm, true); 1632c96b77eSJanosch Frank test_diag_yield(); 1642c96b77eSJanosch Frank test_diag_288(); 1652c96b77eSJanosch Frank test_diag_500(); 1662c96b77eSJanosch Frank sie_guest_destroy(&vm); 1672c96b77eSJanosch Frank 1682c96b77eSJanosch Frank done: 1692c96b77eSJanosch Frank report_prefix_pop(); 1702c96b77eSJanosch Frank return report_summary(); 1712c96b77eSJanosch Frank } 172