• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
check_le_switch_supported(void)48 void 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 
test_le_switch(void)71 void 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 
endian_test(void)100 static void endian_test(void)
101 {
102 	check_le_switch_supported();
103 	test_le_switch();
104 }
105 
106 static struct tst_test test = {
107 	.test_all = endian_test,
108 	.min_kver = "2.6.26",
109 	.forks_child = 1,
110 };
111 
main4(int argc,char ** argv,LTP_ATTRIBUTE_UNUSED char ** envp,unsigned long * auxv)112 int 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__) */
126 TST_TEST_TCONF("This system does not support running of switch() syscall");
127 #endif
128