1/* 2 * Copyright (c) International Business Machines Corp., 2008 3 * Copyright (c) Paul Mackerras, IBM Corp., 2008 4 * Copyright (c) 2018 Linux Test Project 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20/* 21 * Test little-endian mode switch system call. Requires a 64-bit 22 * processor that supports little-endian mode,such as POWER6. 23 */ 24 25#include <errno.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <unistd.h> 29#include <elf.h> 30#include <sys/types.h> 31#include <sys/wait.h> 32#include "tst_test.h" 33 34#if defined (__powerpc64__) || (__powerpc__) 35# ifndef PPC_FEATURE_TRUE_LE 36# define PPC_FEATURE_TRUE_LE 0x00000002 37# endif 38 39# define TST_NO_DEFAULT_MAIN 40 41/* 42 * Make minimal call to 0x1ebe. If we get ENOSYS then syscall is not 43 * available, likely because of: 44 * commit 727f13616c45 ("powerpc: Disable the fast-endian switch syscall by default") 45 * If we get any other outcome, including crashes with various signals, 46 * then we assume syscall is available and carry on with the test. 47 */ 48void check_le_switch_supported(void) 49{ 50 int status; 51 52 if (SAFE_FORK() == 0) { 53 syscall(0x1ebe); 54 exit(errno); 55 } 56 57 SAFE_WAIT(&status); 58 if (WIFSIGNALED(status)) { 59 int sig = WTERMSIG(status); 60 61 tst_res(TINFO, "check exited with sig %d", sig); 62 } else if (WIFEXITED(status)) { 63 int rc = WEXITSTATUS(status); 64 65 tst_res(TINFO, "check exited with %d", rc); 66 if (rc == ENOSYS) 67 tst_brk(TCONF, "fast endian switch (0x1ebe) N/A"); 68 } 69} 70 71void test_le_switch(void) 72{ 73 int status; 74 75 if (SAFE_FORK() == 0) { 76 register int r0 asm("r0") = 0x1ebe; 77 78 asm volatile ("sc; .long 0x02000044" 79 : "=&r" (r0) 80 : "0"(r0) 81 : "cr0", "r9", "r10", "r11", "r12"); 82 exit(0); 83 } 84 85 SAFE_WAIT(&status); 86 if (WIFSIGNALED(status)) { 87 int sig = WTERMSIG(status); 88 89 tst_res(TFAIL, "test exited with sig %d", sig); 90 } else if (WIFEXITED(status)) { 91 int rc = WEXITSTATUS(status); 92 93 if (rc != 0) 94 tst_res(TFAIL, "test exited with %d", rc); 95 else 96 tst_res(TPASS, "endian_switch() syscall tests passed"); 97 } 98} 99 100static void endian_test(void) 101{ 102 check_le_switch_supported(); 103 test_le_switch(); 104} 105 106static struct tst_test test = { 107 .test_all = endian_test, 108 .min_kver = "2.6.26", 109 .forks_child = 1, 110}; 111 112int main4(int argc, char **argv, LTP_ATTRIBUTE_UNUSED char **envp, 113 unsigned long *auxv) 114{ 115 for (; *auxv != AT_NULL && *auxv != AT_HWCAP; auxv += 2) 116 ; 117 118 if (!(auxv[0] == AT_HWCAP && (auxv[1] & PPC_FEATURE_TRUE_LE))) 119 tst_brk(TCONF, "Processor does not support little-endian mode"); 120 121 tst_run_tcases(argc, argv, &test); 122 return 0; 123} 124 125#else /* defined (__powerpc64__) || (__powerpc__) */ 126TST_TEST_TCONF("This system does not support running of switch() syscall"); 127#endif 128