18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Ptrace test TM SPR registers 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include "ptrace.h" 88c2ecf20Sopenharmony_ci#include "tm.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* Tracee and tracer shared data */ 118c2ecf20Sopenharmony_cistruct shared { 128c2ecf20Sopenharmony_ci int flag; 138c2ecf20Sopenharmony_ci struct tm_spr_regs regs; 148c2ecf20Sopenharmony_ci}; 158c2ecf20Sopenharmony_ciunsigned long tfhar; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ciint shm_id; 188c2ecf20Sopenharmony_cistruct shared *cptr, *pptr; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciint shm_id1; 218c2ecf20Sopenharmony_ciint *cptr1, *pptr1; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define TM_KVM_SCHED 0xe0000001ac000001 248c2ecf20Sopenharmony_ciint validate_tm_spr(struct tm_spr_regs *regs) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci FAIL_IF(regs->tm_tfhar != tfhar); 278c2ecf20Sopenharmony_ci FAIL_IF((regs->tm_texasr == TM_KVM_SCHED) && (regs->tm_tfiar != 0)); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci return TEST_PASS; 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_civoid tm_spr(void) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci unsigned long result, texasr; 358c2ecf20Sopenharmony_ci int ret; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci cptr = (struct shared *)shmat(shm_id, NULL, 0); 388c2ecf20Sopenharmony_ci cptr1 = (int *)shmat(shm_id1, NULL, 0); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_citrans: 418c2ecf20Sopenharmony_ci cptr1[0] = 0; 428c2ecf20Sopenharmony_ci asm __volatile__( 438c2ecf20Sopenharmony_ci "1: ;" 448c2ecf20Sopenharmony_ci /* TM failover handler should follow "tbegin.;" */ 458c2ecf20Sopenharmony_ci "mflr 31;" 468c2ecf20Sopenharmony_ci "bl 4f;" /* $ = TFHAR - 12 */ 478c2ecf20Sopenharmony_ci "4: ;" 488c2ecf20Sopenharmony_ci "mflr %[tfhar];" 498c2ecf20Sopenharmony_ci "mtlr 31;" 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci "tbegin.;" 528c2ecf20Sopenharmony_ci "beq 2f;" 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci "tsuspend.;" 558c2ecf20Sopenharmony_ci "li 8, 1;" 568c2ecf20Sopenharmony_ci "sth 8, 0(%[cptr1]);" 578c2ecf20Sopenharmony_ci "tresume.;" 588c2ecf20Sopenharmony_ci "b .;" 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci "tend.;" 618c2ecf20Sopenharmony_ci "li 0, 0;" 628c2ecf20Sopenharmony_ci "ori %[res], 0, 0;" 638c2ecf20Sopenharmony_ci "b 3f;" 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci "2: ;" 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci "li 0, 1;" 688c2ecf20Sopenharmony_ci "ori %[res], 0, 0;" 698c2ecf20Sopenharmony_ci "mfspr %[texasr], %[sprn_texasr];" 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci "3: ;" 728c2ecf20Sopenharmony_ci : [tfhar] "=r" (tfhar), [res] "=r" (result), 738c2ecf20Sopenharmony_ci [texasr] "=r" (texasr), [cptr1] "=b" (cptr1) 748c2ecf20Sopenharmony_ci : [sprn_texasr] "i" (SPRN_TEXASR) 758c2ecf20Sopenharmony_ci : "memory", "r0", "r8", "r31" 768c2ecf20Sopenharmony_ci ); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* There are 2 32bit instructions before tbegin. */ 798c2ecf20Sopenharmony_ci tfhar += 12; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (result) { 828c2ecf20Sopenharmony_ci if (!cptr->flag) 838c2ecf20Sopenharmony_ci goto trans; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci ret = validate_tm_spr((struct tm_spr_regs *)&cptr->regs); 868c2ecf20Sopenharmony_ci shmdt((void *)cptr); 878c2ecf20Sopenharmony_ci shmdt((void *)cptr1); 888c2ecf20Sopenharmony_ci if (ret) 898c2ecf20Sopenharmony_ci exit(1); 908c2ecf20Sopenharmony_ci exit(0); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci shmdt((void *)cptr); 938c2ecf20Sopenharmony_ci shmdt((void *)cptr1); 948c2ecf20Sopenharmony_ci exit(1); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciint trace_tm_spr(pid_t child) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci FAIL_IF(start_trace(child)); 1008c2ecf20Sopenharmony_ci FAIL_IF(show_tm_spr(child, (struct tm_spr_regs *)&pptr->regs)); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci printf("TFHAR: %lx TEXASR: %lx TFIAR: %lx\n", pptr->regs.tm_tfhar, 1038c2ecf20Sopenharmony_ci pptr->regs.tm_texasr, pptr->regs.tm_tfiar); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci pptr->flag = 1; 1068c2ecf20Sopenharmony_ci FAIL_IF(stop_trace(child)); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return TEST_PASS; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ciint ptrace_tm_spr(void) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci pid_t pid; 1148c2ecf20Sopenharmony_ci int ret, status; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci SKIP_IF(!have_htm()); 1178c2ecf20Sopenharmony_ci shm_id = shmget(IPC_PRIVATE, sizeof(struct shared), 0777|IPC_CREAT); 1188c2ecf20Sopenharmony_ci shm_id1 = shmget(IPC_PRIVATE, sizeof(int), 0777|IPC_CREAT); 1198c2ecf20Sopenharmony_ci pid = fork(); 1208c2ecf20Sopenharmony_ci if (pid < 0) { 1218c2ecf20Sopenharmony_ci perror("fork() failed"); 1228c2ecf20Sopenharmony_ci return TEST_FAIL; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (pid == 0) 1268c2ecf20Sopenharmony_ci tm_spr(); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (pid) { 1298c2ecf20Sopenharmony_ci pptr = (struct shared *)shmat(shm_id, NULL, 0); 1308c2ecf20Sopenharmony_ci pptr1 = (int *)shmat(shm_id1, NULL, 0); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci while (!pptr1[0]) 1338c2ecf20Sopenharmony_ci asm volatile("" : : : "memory"); 1348c2ecf20Sopenharmony_ci ret = trace_tm_spr(pid); 1358c2ecf20Sopenharmony_ci if (ret) { 1368c2ecf20Sopenharmony_ci kill(pid, SIGKILL); 1378c2ecf20Sopenharmony_ci shmdt((void *)pptr); 1388c2ecf20Sopenharmony_ci shmdt((void *)pptr1); 1398c2ecf20Sopenharmony_ci shmctl(shm_id, IPC_RMID, NULL); 1408c2ecf20Sopenharmony_ci shmctl(shm_id1, IPC_RMID, NULL); 1418c2ecf20Sopenharmony_ci return TEST_FAIL; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci shmdt((void *)pptr); 1458c2ecf20Sopenharmony_ci shmdt((void *)pptr1); 1468c2ecf20Sopenharmony_ci ret = wait(&status); 1478c2ecf20Sopenharmony_ci shmctl(shm_id, IPC_RMID, NULL); 1488c2ecf20Sopenharmony_ci shmctl(shm_id1, IPC_RMID, NULL); 1498c2ecf20Sopenharmony_ci if (ret != pid) { 1508c2ecf20Sopenharmony_ci printf("Child's exit status not captured\n"); 1518c2ecf20Sopenharmony_ci return TEST_FAIL; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : 1558c2ecf20Sopenharmony_ci TEST_PASS; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci return TEST_PASS; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ciint main(int argc, char *argv[]) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci return test_harness(ptrace_tm_spr, "ptrace_tm_spr"); 1638c2ecf20Sopenharmony_ci} 164