1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) International Business Machines Corp., 2008 4 * Copyright (c) Paul Mackerras, IBM Corp., 2008 5 * Copyright (c) 2018-2023 Linux Test Project 6 */ 7 8/* 9 * Test little-endian mode switch system call. Requires a 64-bit 10 * processor that supports little-endian mode,such as POWER6. 11 */ 12 13#include <errno.h> 14#include <stdio.h> 15#include <stdlib.h> 16#include <unistd.h> 17#include <elf.h> 18#include <sys/types.h> 19#include <sys/wait.h> 20 21#include "tst_test.h" 22 23#if defined(__powerpc64__) || defined(__powerpc__) 24 25# ifndef PPC_FEATURE_TRUE_LE 26# define PPC_FEATURE_TRUE_LE 0x00000002 27# endif 28 29# ifdef HAVE_GETAUXVAL 30# include <sys/auxv.h> 31 32/* 33 * Make minimal call to 0x1ebe. If we get ENOSYS then syscall is not 34 * available, likely because of: 35 * commit 727f13616c45 ("powerpc: Disable the fast-endian switch syscall by default") 36 * If we get any other outcome, including crashes with various signals, 37 * then we assume syscall is available and carry on with the test. 38 */ 39void check_le_switch_supported(void) 40{ 41 int status; 42 43 if (SAFE_FORK() == 0) { 44 syscall(0x1ebe); 45 exit(errno); 46 } 47 48 if (!(getauxval(AT_HWCAP) & PPC_FEATURE_TRUE_LE)) 49 tst_brk(TCONF, "Processor does not support little-endian mode"); 50 51 SAFE_WAIT(&status); 52 if (WIFSIGNALED(status)) { 53 int sig = WTERMSIG(status); 54 55 tst_res(TINFO, "check exited with sig %d", sig); 56 } else if (WIFEXITED(status)) { 57 int rc = WEXITSTATUS(status); 58 59 tst_res(TINFO, "check exited with %d", rc); 60 if (rc == ENOSYS) 61 tst_brk(TCONF, "fast endian switch (0x1ebe) N/A"); 62 } 63} 64 65void test_le_switch(void) 66{ 67 int status; 68 69 if (SAFE_FORK() == 0) { 70 register int r0 asm("r0") = 0x1ebe; 71 72 asm volatile ("sc; .long 0x02000044" 73 : "=&r" (r0) 74 : "0"(r0) 75 : "cr0", "r9", "r10", "r11", "r12"); 76 exit(0); 77 } 78 79 SAFE_WAIT(&status); 80 if (WIFSIGNALED(status)) { 81 int sig = WTERMSIG(status); 82 83 tst_res(TFAIL, "test exited with sig %d", sig); 84 } else if (WIFEXITED(status)) { 85 int rc = WEXITSTATUS(status); 86 87 if (rc != 0) 88 tst_res(TFAIL, "test exited with %d", rc); 89 else 90 tst_res(TPASS, "endian_switch() syscall tests passed"); 91 } 92} 93 94static void endian_test(void) 95{ 96 check_le_switch_supported(); 97 test_le_switch(); 98} 99 100static struct tst_test test = { 101 .test_all = endian_test, 102 .forks_child = 1, 103}; 104 105# else 106TST_TEST_TCONF("Toolchain does not have <sys/auxv.h>"); 107# endif /* HAVE_GETAUXVAL */ 108 109#else /* defined (__powerpc64__) || (__powerpc__) */ 110TST_TEST_TCONF("This system does not support running of switch() syscall"); 111#endif 112