162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2015, Sam Bobroff, IBM Corp. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Test the kernel's system call code to ensure that a system call 662306a36Sopenharmony_ci * made from within an active HTM transaction is aborted with the 762306a36Sopenharmony_ci * correct failure code. 862306a36Sopenharmony_ci * Conversely, ensure that a system call made from within a 962306a36Sopenharmony_ci * suspended transaction can succeed. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <stdio.h> 1362306a36Sopenharmony_ci#include <unistd.h> 1462306a36Sopenharmony_ci#include <sys/syscall.h> 1562306a36Sopenharmony_ci#include <asm/tm.h> 1662306a36Sopenharmony_ci#include <sys/time.h> 1762306a36Sopenharmony_ci#include <stdlib.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "utils.h" 2062306a36Sopenharmony_ci#include "tm.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#ifndef PPC_FEATURE2_SCV 2362306a36Sopenharmony_ci#define PPC_FEATURE2_SCV 0x00100000 /* scv syscall */ 2462306a36Sopenharmony_ci#endif 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciextern int getppid_tm_active(void); 2762306a36Sopenharmony_ciextern int getppid_tm_suspended(void); 2862306a36Sopenharmony_ciextern int getppid_scv_tm_active(void); 2962306a36Sopenharmony_ciextern int getppid_scv_tm_suspended(void); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciunsigned retries = 0; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define TEST_DURATION 10 /* seconds */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cipid_t getppid_tm(bool scv, bool suspend) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci int i; 3862306a36Sopenharmony_ci pid_t pid; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci for (i = 0; i < TM_RETRIES; i++) { 4162306a36Sopenharmony_ci if (suspend) { 4262306a36Sopenharmony_ci if (scv) 4362306a36Sopenharmony_ci pid = getppid_scv_tm_suspended(); 4462306a36Sopenharmony_ci else 4562306a36Sopenharmony_ci pid = getppid_tm_suspended(); 4662306a36Sopenharmony_ci } else { 4762306a36Sopenharmony_ci if (scv) 4862306a36Sopenharmony_ci pid = getppid_scv_tm_active(); 4962306a36Sopenharmony_ci else 5062306a36Sopenharmony_ci pid = getppid_tm_active(); 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (pid >= 0) 5462306a36Sopenharmony_ci return pid; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (failure_is_persistent()) { 5762306a36Sopenharmony_ci if (failure_is_syscall()) 5862306a36Sopenharmony_ci return -1; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci printf("Unexpected persistent transaction failure.\n"); 6162306a36Sopenharmony_ci printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n", 6262306a36Sopenharmony_ci __builtin_get_texasr(), __builtin_get_tfiar()); 6362306a36Sopenharmony_ci exit(-1); 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci retries++; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci printf("Exceeded limit of %d temporary transaction failures.\n", TM_RETRIES); 7062306a36Sopenharmony_ci printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n", 7162306a36Sopenharmony_ci __builtin_get_texasr(), __builtin_get_tfiar()); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci exit(-1); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciint tm_syscall(void) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci unsigned count = 0; 7962306a36Sopenharmony_ci struct timeval end, now; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci SKIP_IF(!have_htm_nosc()); 8262306a36Sopenharmony_ci SKIP_IF(htm_is_synthetic()); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci setbuf(stdout, NULL); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci printf("Testing transactional syscalls for %d seconds...\n", TEST_DURATION); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci gettimeofday(&end, NULL); 8962306a36Sopenharmony_ci now.tv_sec = TEST_DURATION; 9062306a36Sopenharmony_ci now.tv_usec = 0; 9162306a36Sopenharmony_ci timeradd(&end, &now, &end); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci for (count = 0; timercmp(&now, &end, <); count++) { 9462306a36Sopenharmony_ci /* 9562306a36Sopenharmony_ci * Test a syscall within a suspended transaction and verify 9662306a36Sopenharmony_ci * that it succeeds. 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci FAIL_IF(getppid_tm(false, true) == -1); /* Should succeed. */ 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* 10162306a36Sopenharmony_ci * Test a syscall within an active transaction and verify that 10262306a36Sopenharmony_ci * it fails with the correct failure code. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci FAIL_IF(getppid_tm(false, false) != -1); /* Should fail... */ 10562306a36Sopenharmony_ci FAIL_IF(!failure_is_persistent()); /* ...persistently... */ 10662306a36Sopenharmony_ci FAIL_IF(!failure_is_syscall()); /* ...with code syscall. */ 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* Now do it all again with scv if it is available. */ 10962306a36Sopenharmony_ci if (have_hwcap2(PPC_FEATURE2_SCV)) { 11062306a36Sopenharmony_ci FAIL_IF(getppid_tm(true, true) == -1); /* Should succeed. */ 11162306a36Sopenharmony_ci FAIL_IF(getppid_tm(true, false) != -1); /* Should fail... */ 11262306a36Sopenharmony_ci FAIL_IF(!failure_is_persistent()); /* ...persistently... */ 11362306a36Sopenharmony_ci FAIL_IF(!failure_is_syscall()); /* ...with code syscall. */ 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci gettimeofday(&now, 0); 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci printf("%d active and suspended transactions behaved correctly.\n", count); 12062306a36Sopenharmony_ci printf("(There were %d transaction retries.)\n", retries); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ciint main(void) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci return test_harness(tm_syscall, "tm_syscall"); 12862306a36Sopenharmony_ci} 129