148e9236cSNico Boehr /* SPDX-License-Identifier: GPL-2.0-only */ 248e9236cSNico Boehr /* 348e9236cSNico Boehr * EPSW Interception Tests 448e9236cSNico Boehr * 548e9236cSNico Boehr * Copyright IBM Corp. 2022 648e9236cSNico Boehr * 748e9236cSNico Boehr * Authors: 848e9236cSNico Boehr * Nico Boehr <nrb@linux.ibm.com> 948e9236cSNico Boehr */ 1048e9236cSNico Boehr #include <libcflat.h> 1148e9236cSNico Boehr #include <css.h> 12f489dfa5SClaudio Imbrenda #include <hardware.h> 1348e9236cSNico Boehr 1448e9236cSNico Boehr static uint32_t zero_out_cc_from_epsw_op1(uint32_t epsw_op1) 1548e9236cSNico Boehr { 1648e9236cSNico Boehr return epsw_op1 & ~GENMASK(31 - 18, 31 - 20); 1748e9236cSNico Boehr } 1848e9236cSNico Boehr 1948e9236cSNico Boehr static void generate_crw(void) 2048e9236cSNico Boehr { 2148e9236cSNico Boehr int test_device_sid = css_enumerate(); 2248e9236cSNico Boehr int cc, ret; 2348e9236cSNico Boehr 2448e9236cSNico Boehr if (!(test_device_sid & SCHID_ONE)) { 2548e9236cSNico Boehr report_fail("No I/O device found"); 2648e9236cSNico Boehr return; 2748e9236cSNico Boehr } 2848e9236cSNico Boehr 2948e9236cSNico Boehr cc = css_enable(test_device_sid, IO_SCH_ISC); 3048e9236cSNico Boehr report(cc == 0, "Enable subchannel %08x", test_device_sid); 3148e9236cSNico Boehr 3248e9236cSNico Boehr ret = css_generate_crw(test_device_sid); 3348e9236cSNico Boehr if (ret) 3448e9236cSNico Boehr report_fail("Couldn't generate CRW"); 3548e9236cSNico Boehr } 3648e9236cSNico Boehr 3748e9236cSNico Boehr static void test_epsw(void) 3848e9236cSNico Boehr { 3948e9236cSNico Boehr const uint64_t MAGIC1 = 0x1234567890abcdefUL; 4048e9236cSNico Boehr const uint64_t MAGIC2 = 0xcafedeadbeeffaceUL; 4148e9236cSNico Boehr 4248e9236cSNico Boehr uint64_t op1 = MAGIC1; 4348e9236cSNico Boehr uint64_t op2 = MAGIC2; 4448e9236cSNico Boehr uint32_t prev_epsw_op1; 4548e9236cSNico Boehr 4648e9236cSNico Boehr /* 4748e9236cSNico Boehr * having machine check interrupts masked and pending CRW ensures 4848e9236cSNico Boehr * EPSW is intercepted under KVM 4948e9236cSNico Boehr */ 5048e9236cSNico Boehr generate_crw(); 5148e9236cSNico Boehr 5248e9236cSNico Boehr report_prefix_push("both operands given"); 5348e9236cSNico Boehr asm volatile( 5448e9236cSNico Boehr "epsw %0, %1\n" 5548e9236cSNico Boehr : "+&d" (op1), "+&a" (op2)); 5648e9236cSNico Boehr report(upper_32_bits(op1) == upper_32_bits(MAGIC1) && 5748e9236cSNico Boehr upper_32_bits(op2) == upper_32_bits(MAGIC2), 5848e9236cSNico Boehr "upper 32 bits unmodified"); 5948e9236cSNico Boehr report(lower_32_bits(op1) != lower_32_bits(MAGIC1) && 6048e9236cSNico Boehr lower_32_bits(op2) != lower_32_bits(MAGIC2), 6148e9236cSNico Boehr "lower 32 bits modified"); 6248e9236cSNico Boehr prev_epsw_op1 = zero_out_cc_from_epsw_op1(lower_32_bits(op1)); 6348e9236cSNico Boehr report_prefix_pop(); 6448e9236cSNico Boehr 6548e9236cSNico Boehr report_prefix_push("second operand 0"); 6648e9236cSNico Boehr op1 = MAGIC1; 6748e9236cSNico Boehr op2 = MAGIC2; 6848e9236cSNico Boehr asm volatile( 6948e9236cSNico Boehr " lgr 0,%[op2]\n" 7048e9236cSNico Boehr " epsw %[op1], 0\n" 7148e9236cSNico Boehr " lgr %[op2],0\n" 7248e9236cSNico Boehr : [op2] "+&d" (op2), [op1] "+&a" (op1) 7348e9236cSNico Boehr : 7448e9236cSNico Boehr : "0"); 7548e9236cSNico Boehr report(upper_32_bits(op1) == upper_32_bits(MAGIC1), 7648e9236cSNico Boehr "upper 32 bits of first operand unmodified"); 7748e9236cSNico Boehr report(zero_out_cc_from_epsw_op1(lower_32_bits(op1)) == prev_epsw_op1, 7848e9236cSNico Boehr "first operand matches previous reading"); 7948e9236cSNico Boehr report(op2 == MAGIC2, "r0 unmodified"); 8048e9236cSNico Boehr report_prefix_pop(); 8148e9236cSNico Boehr 8248e9236cSNico Boehr report_prefix_push("both operands 0"); 8348e9236cSNico Boehr op1 = MAGIC1; 8448e9236cSNico Boehr asm volatile( 8548e9236cSNico Boehr " lgr 0,%[op1]\n" 8648e9236cSNico Boehr " epsw 0, 0\n" 8748e9236cSNico Boehr " lgr %[op1],0\n" 8848e9236cSNico Boehr : [op1] "+&d" (op1) 8948e9236cSNico Boehr : 9048e9236cSNico Boehr : "0"); 9148e9236cSNico Boehr report(upper_32_bits(op1) == upper_32_bits(MAGIC1), 9248e9236cSNico Boehr "upper 32 bits of first operand unmodified"); 9348e9236cSNico Boehr report(zero_out_cc_from_epsw_op1(lower_32_bits(op1)) == prev_epsw_op1, 9448e9236cSNico Boehr "first operand matches previous reading"); 9548e9236cSNico Boehr report_prefix_pop(); 9648e9236cSNico Boehr } 9748e9236cSNico Boehr 9848e9236cSNico Boehr int main(int argc, char **argv) 9948e9236cSNico Boehr { 100*fc0d9b41SNico Boehr report_prefix_push("epsw"); 101*fc0d9b41SNico Boehr 102f489dfa5SClaudio Imbrenda if (!host_is_kvm() && !host_is_tcg()) { 10348e9236cSNico Boehr report_skip("Not running under QEMU"); 10448e9236cSNico Boehr goto done; 10548e9236cSNico Boehr } 10648e9236cSNico Boehr 10748e9236cSNico Boehr test_epsw(); 10848e9236cSNico Boehr 10948e9236cSNico Boehr done: 11048e9236cSNico Boehr report_prefix_pop(); 11148e9236cSNico Boehr 11248e9236cSNico Boehr return report_summary(); 11348e9236cSNico Boehr } 114