1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. 4f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@fujitsu.com> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Basic test to test behaviour of PR_GET_TSC and PR_SET_TSC. 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * Set the state of the flag determining whether the timestamp counter can 13f08c3bdfSopenharmony_ci * be read by the process. 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * - Pass PR_TSC_ENABLE to arg2 to allow it to be read. 16f08c3bdfSopenharmony_ci * - Pass PR_TSC_SIGSEGV to arg2 to generate a SIGSEGV when read. 17f08c3bdfSopenharmony_ci */ 18f08c3bdfSopenharmony_ci 19f08c3bdfSopenharmony_ci#include <sys/prctl.h> 20f08c3bdfSopenharmony_ci#include <string.h> 21f08c3bdfSopenharmony_ci#include <stdio.h> 22f08c3bdfSopenharmony_ci#include <stdlib.h> 23f08c3bdfSopenharmony_ci#include "tst_test.h" 24f08c3bdfSopenharmony_ci#include "lapi/prctl.h" 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_ci#define TCASE_ENTRY(tsc_read_stat) { .name = #tsc_read_stat, .read_stat = tsc_read_stat} 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_cistatic const char * const tsc_read_stat_names[] = { 29f08c3bdfSopenharmony_ci [0] = "[not set]", 30f08c3bdfSopenharmony_ci [PR_TSC_ENABLE] = "PR_TSC_ENABLE", 31f08c3bdfSopenharmony_ci [PR_TSC_SIGSEGV] = "PR_TSC_SIGSEGV", 32f08c3bdfSopenharmony_ci}; 33f08c3bdfSopenharmony_ci 34f08c3bdfSopenharmony_cistatic struct tcase { 35f08c3bdfSopenharmony_ci char *name; 36f08c3bdfSopenharmony_ci int read_stat; 37f08c3bdfSopenharmony_ci} tcases[] = { 38f08c3bdfSopenharmony_ci TCASE_ENTRY(PR_TSC_ENABLE), 39f08c3bdfSopenharmony_ci TCASE_ENTRY(PR_TSC_SIGSEGV) 40f08c3bdfSopenharmony_ci}; 41f08c3bdfSopenharmony_ci 42f08c3bdfSopenharmony_cistatic uint64_t rdtsc(void) 43f08c3bdfSopenharmony_ci{ 44f08c3bdfSopenharmony_ci uint32_t lo = 0, hi = 0; 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_ci#if (defined(__x86_64__) || defined(__i386__)) 47f08c3bdfSopenharmony_ci /* We cannot use "=A", since this would use %rax on x86_64 */ 48f08c3bdfSopenharmony_ci __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); 49f08c3bdfSopenharmony_ci#endif 50f08c3bdfSopenharmony_ci 51f08c3bdfSopenharmony_ci return (uint64_t)hi << 32 | lo; 52f08c3bdfSopenharmony_ci} 53f08c3bdfSopenharmony_ci 54f08c3bdfSopenharmony_ci 55f08c3bdfSopenharmony_cistatic int expected_status(int status, int exp_status) 56f08c3bdfSopenharmony_ci{ 57f08c3bdfSopenharmony_ci if (!exp_status && WIFEXITED(status)) 58f08c3bdfSopenharmony_ci return 0; 59f08c3bdfSopenharmony_ci 60f08c3bdfSopenharmony_ci if (exp_status && WIFSIGNALED(status) && WTERMSIG(status) == exp_status) 61f08c3bdfSopenharmony_ci return 0; 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_ci return 1; 64f08c3bdfSopenharmony_ci} 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_cistatic void verify_prctl(unsigned int n) 67f08c3bdfSopenharmony_ci{ 68f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 69f08c3bdfSopenharmony_ci unsigned long long time1, time2; 70f08c3bdfSopenharmony_ci int tsc_val = 0, pid, status; 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci pid = SAFE_FORK(); 73f08c3bdfSopenharmony_ci if (!pid) { 74f08c3bdfSopenharmony_ci TST_EXP_PASS_SILENT(prctl(PR_SET_TSC, tc->read_stat)); 75f08c3bdfSopenharmony_ci TST_EXP_PASS_SILENT(prctl(PR_GET_TSC, &tsc_val)); 76f08c3bdfSopenharmony_ci if (tsc_val == tc->read_stat) 77f08c3bdfSopenharmony_ci tst_res(TPASS, "current state is %s(%d)", 78f08c3bdfSopenharmony_ci tc->name, tc->read_stat); 79f08c3bdfSopenharmony_ci else 80f08c3bdfSopenharmony_ci tst_res(TFAIL, "current state is %s(%d), expect %s(%d)", 81f08c3bdfSopenharmony_ci tsc_read_stat_names[tsc_val], 82f08c3bdfSopenharmony_ci tsc_val, tc->name, tc->read_stat); 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci time1 = rdtsc(); 85f08c3bdfSopenharmony_ci time2 = rdtsc(); 86f08c3bdfSopenharmony_ci if (time2 > time1) 87f08c3bdfSopenharmony_ci tst_res(TPASS, "rdtsc works correctly, %lld ->%lld", 88f08c3bdfSopenharmony_ci time1, time2); 89f08c3bdfSopenharmony_ci else 90f08c3bdfSopenharmony_ci tst_res(TFAIL, "rdtsc works incorrectly, %lld ->%lld", 91f08c3bdfSopenharmony_ci time1, time2); 92f08c3bdfSopenharmony_ci exit(0); 93f08c3bdfSopenharmony_ci } 94f08c3bdfSopenharmony_ci SAFE_WAITPID(pid, &status, 0); 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_ci if (expected_status(status, tc->read_stat == PR_TSC_SIGSEGV ? SIGSEGV : 0)) 97f08c3bdfSopenharmony_ci tst_res(TFAIL, "Test %s failed", tc->name); 98f08c3bdfSopenharmony_ci else 99f08c3bdfSopenharmony_ci tst_res(TPASS, "Test %s succeeded", tc->name); 100f08c3bdfSopenharmony_ci} 101f08c3bdfSopenharmony_ci 102f08c3bdfSopenharmony_cistatic struct tst_test test = { 103f08c3bdfSopenharmony_ci .forks_child = 1, 104f08c3bdfSopenharmony_ci .test = verify_prctl, 105f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 106f08c3bdfSopenharmony_ci .supported_archs = (const char *const []) { 107f08c3bdfSopenharmony_ci "x86", 108f08c3bdfSopenharmony_ci "x86_64", 109f08c3bdfSopenharmony_ci NULL 110f08c3bdfSopenharmony_ci }, 111f08c3bdfSopenharmony_ci}; 112