1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * EPSW Interception Tests 4 * 5 * Copyright IBM Corp. 2022 6 * 7 * Authors: 8 * Nico Boehr <nrb@linux.ibm.com> 9 */ 10 #include <libcflat.h> 11 #include <css.h> 12 #include <hardware.h> 13 14 static uint32_t zero_out_cc_from_epsw_op1(uint32_t epsw_op1) 15 { 16 return epsw_op1 & ~GENMASK(31 - 18, 31 - 20); 17 } 18 19 static void generate_crw(void) 20 { 21 int test_device_sid = css_enumerate(); 22 int cc, ret; 23 24 if (!(test_device_sid & SCHID_ONE)) { 25 report_fail("No I/O device found"); 26 return; 27 } 28 29 cc = css_enable(test_device_sid, IO_SCH_ISC); 30 report(cc == 0, "Enable subchannel %08x", test_device_sid); 31 32 ret = css_generate_crw(test_device_sid); 33 if (ret) 34 report_fail("Couldn't generate CRW"); 35 } 36 37 static void test_epsw(void) 38 { 39 const uint64_t MAGIC1 = 0x1234567890abcdefUL; 40 const uint64_t MAGIC2 = 0xcafedeadbeeffaceUL; 41 42 uint64_t op1 = MAGIC1; 43 uint64_t op2 = MAGIC2; 44 uint32_t prev_epsw_op1; 45 46 /* 47 * having machine check interrupts masked and pending CRW ensures 48 * EPSW is intercepted under KVM 49 */ 50 generate_crw(); 51 52 report_prefix_push("both operands given"); 53 asm volatile( 54 "epsw %0, %1\n" 55 : "+&d" (op1), "+&a" (op2)); 56 report(upper_32_bits(op1) == upper_32_bits(MAGIC1) && 57 upper_32_bits(op2) == upper_32_bits(MAGIC2), 58 "upper 32 bits unmodified"); 59 report(lower_32_bits(op1) != lower_32_bits(MAGIC1) && 60 lower_32_bits(op2) != lower_32_bits(MAGIC2), 61 "lower 32 bits modified"); 62 prev_epsw_op1 = zero_out_cc_from_epsw_op1(lower_32_bits(op1)); 63 report_prefix_pop(); 64 65 report_prefix_push("second operand 0"); 66 op1 = MAGIC1; 67 op2 = MAGIC2; 68 asm volatile( 69 " lgr 0,%[op2]\n" 70 " epsw %[op1], 0\n" 71 " lgr %[op2],0\n" 72 : [op2] "+&d" (op2), [op1] "+&a" (op1) 73 : 74 : "0"); 75 report(upper_32_bits(op1) == upper_32_bits(MAGIC1), 76 "upper 32 bits of first operand unmodified"); 77 report(zero_out_cc_from_epsw_op1(lower_32_bits(op1)) == prev_epsw_op1, 78 "first operand matches previous reading"); 79 report(op2 == MAGIC2, "r0 unmodified"); 80 report_prefix_pop(); 81 82 report_prefix_push("both operands 0"); 83 op1 = MAGIC1; 84 asm volatile( 85 " lgr 0,%[op1]\n" 86 " epsw 0, 0\n" 87 " lgr %[op1],0\n" 88 : [op1] "+&d" (op1) 89 : 90 : "0"); 91 report(upper_32_bits(op1) == upper_32_bits(MAGIC1), 92 "upper 32 bits of first operand unmodified"); 93 report(zero_out_cc_from_epsw_op1(lower_32_bits(op1)) == prev_epsw_op1, 94 "first operand matches previous reading"); 95 report_prefix_pop(); 96 } 97 98 int main(int argc, char **argv) 99 { 100 report_prefix_push("epsw"); 101 102 if (!host_is_kvm() && !host_is_tcg()) { 103 report_skip("Not running under QEMU"); 104 goto done; 105 } 106 107 test_epsw(); 108 109 done: 110 report_prefix_pop(); 111 112 return report_summary(); 113 } 114