• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 #include "tst_test.h"
21 
22 #if defined(__powerpc64__) || defined(__powerpc__)
23 # ifndef PPC_FEATURE_TRUE_LE
24 # define PPC_FEATURE_TRUE_LE              0x00000002
25 # endif
26 
27 # define TST_NO_DEFAULT_MAIN
28 
29 /*
30  * Make minimal call to 0x1ebe. If we get ENOSYS then syscall is not
31  * available, likely because of:
32  *   commit 727f13616c45 ("powerpc: Disable the fast-endian switch syscall by default")
33  * If we get any other outcome, including crashes with various signals,
34  * then we assume syscall is available and carry on with the test.
35  */
check_le_switch_supported(void)36 void check_le_switch_supported(void)
37 {
38 	int status;
39 
40 	if (SAFE_FORK() == 0) {
41 		syscall(0x1ebe);
42 		exit(errno);
43 	}
44 
45 	SAFE_WAIT(&status);
46 	if (WIFSIGNALED(status)) {
47 		int sig = WTERMSIG(status);
48 
49 		tst_res(TINFO, "check exited with sig %d", sig);
50 	} else if (WIFEXITED(status)) {
51 		int rc = WEXITSTATUS(status);
52 
53 		tst_res(TINFO, "check exited with %d", rc);
54 		if (rc == ENOSYS)
55 			tst_brk(TCONF, "fast endian switch (0x1ebe) N/A");
56 	}
57 }
58 
test_le_switch(void)59 void test_le_switch(void)
60 {
61 	int status;
62 
63 	if (SAFE_FORK() == 0) {
64 		register int r0 asm("r0") = 0x1ebe;
65 
66 		asm volatile ("sc; .long 0x02000044"
67 				: "=&r" (r0)
68 				: "0"(r0)
69 				: "cr0", "r9", "r10", "r11", "r12");
70 		exit(0);
71 	}
72 
73 	SAFE_WAIT(&status);
74 	if (WIFSIGNALED(status)) {
75 		int sig = WTERMSIG(status);
76 
77 		tst_res(TFAIL, "test exited with sig %d", sig);
78 	} else if (WIFEXITED(status)) {
79 		int rc = WEXITSTATUS(status);
80 
81 		if (rc != 0)
82 			tst_res(TFAIL, "test exited with %d", rc);
83 		else
84 			tst_res(TPASS, "endian_switch() syscall tests passed");
85 	}
86 }
87 
endian_test(void)88 static void endian_test(void)
89 {
90 	check_le_switch_supported();
91 	test_le_switch();
92 }
93 
94 static struct tst_test test = {
95 	.test_all = endian_test,
96 	.min_kver = "2.6.26",
97 	.forks_child = 1,
98 };
99 
main4(int argc,char ** argv,LTP_ATTRIBUTE_UNUSED char ** envp,unsigned long * auxv)100 int main4(int argc, char **argv, LTP_ATTRIBUTE_UNUSED char **envp,
101 	unsigned long *auxv)
102 {
103 	for (; *auxv != AT_NULL && *auxv != AT_HWCAP; auxv += 2)
104 		;
105 
106 	if (!(auxv[0] == AT_HWCAP && (auxv[1] & PPC_FEATURE_TRUE_LE)))
107 		tst_brk(TCONF, "Processor does not support little-endian mode");
108 
109 	tst_run_tcases(argc, argv, &test);
110 	return 0;
111 }
112 
113 #else /* defined (__powerpc64__) || (__powerpc__) */
114 TST_TEST_TCONF("This system does not support running of switch() syscall");
115 #endif
116