1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <jni.h>
18 
19 #if defined(__arm__) || defined(__aarch64__)
20 #include <setjmp.h>
21 #include <signal.h>
22 #include <string.h>
23 
24 static sigjmp_buf jmpenv;
25 
sigill_handler(int signum)26 static void sigill_handler(int signum __attribute__((unused)))
27 {
28     siglongjmp(jmpenv, 1);
29 }
30 
do_sigsetjmp()31 static int do_sigsetjmp()
32 {
33     return sigsetjmp(jmpenv, 1);
34 }
35 
test_instruction(void (* func)())36 static jboolean test_instruction(void (*func)())
37 {
38     struct sigaction sigill_act;
39     struct sigaction oldact;
40     int err;
41     jboolean ret = true;
42 
43     memset(&sigill_act, 0, sizeof(sigill_act));
44     sigill_act.sa_handler = sigill_handler;
45 
46     err = sigaction(SIGILL, &sigill_act, &oldact);
47     if (err) {
48         ret = false;
49         goto err_sigaction;
50     }
51 
52     if (do_sigsetjmp()) {
53         ret = false;
54         goto err_segill;
55     }
56 
57     func();
58 
59 err_segill:
60     sigaction(SIGILL, &oldact, NULL);
61 err_sigaction:
62     return ret;
63 }
64 #endif
65 
66 #ifdef __aarch64__
cntvct()67 static void cntvct()
68 {
69     asm volatile ( "mrs x0, cntvct_el0" : : : "x0" );
70 }
71 
android_os_cts_CpuInstructions_canReadCntvct(JNIEnv *,jobject)72 jboolean android_os_cts_CpuInstructions_canReadCntvct(JNIEnv *, jobject)
73 {
74     return test_instruction(cntvct);
75 }
76 #else
android_os_cts_CpuInstructions_canReadCntvct(JNIEnv *,jobject)77 jboolean android_os_cts_CpuInstructions_canReadCntvct(JNIEnv *, jobject)
78 {
79     return false;
80 }
81 #endif
82 
83 #ifdef __arm__
swp()84 static void swp()
85 {
86     uint32_t dummy = 0;
87     uint32_t *ptr = &dummy;
88     asm volatile ( "swp r0, r0, [%0]" : "+r"(ptr) : : "r0" );
89 }
90 
setend()91 static void setend()
92 {
93     asm volatile (
94         "setend be" "\n"
95         "setend le" "\n"
96     );
97 }
98 
cp15_dsb()99 static void cp15_dsb()
100 {
101     asm volatile ( "mcr p15, 0, %0, c7, c10, 4" : : "r"(0) );
102 }
103 
android_os_cts_CpuInstructions_hasSwp(JNIEnv *,jobject)104 jboolean android_os_cts_CpuInstructions_hasSwp(JNIEnv *, jobject)
105 {
106     return test_instruction(swp);
107 }
108 
android_os_cts_CpuInstructions_hasSetend(JNIEnv *,jobject)109 jboolean android_os_cts_CpuInstructions_hasSetend(JNIEnv *, jobject)
110 {
111     return test_instruction(setend);
112 }
113 
android_os_cts_CpuInstructions_hasCp15Barriers(JNIEnv *,jobject)114 jboolean android_os_cts_CpuInstructions_hasCp15Barriers(JNIEnv *, jobject)
115 {
116     return test_instruction(cp15_dsb);
117 }
118 #else
android_os_cts_CpuInstructions_hasSwp(JNIEnv *,jobject)119 jboolean android_os_cts_CpuInstructions_hasSwp(JNIEnv *, jobject)
120 {
121     return false;
122 }
123 
android_os_cts_CpuInstructions_hasSetend(JNIEnv *,jobject)124 jboolean android_os_cts_CpuInstructions_hasSetend(JNIEnv *, jobject)
125 {
126     return false;
127 }
128 
android_os_cts_CpuInstructions_hasCp15Barriers(JNIEnv *,jobject)129 jboolean android_os_cts_CpuInstructions_hasCp15Barriers(JNIEnv *, jobject)
130 {
131     return false;
132 }
133 #endif
134 
135 static JNINativeMethod gMethods[] = {
136     { "canReadCntvct", "()Z", (void *)android_os_cts_CpuInstructions_canReadCntvct },
137     { "hasSwp", "()Z", (void *)android_os_cts_CpuInstructions_hasSwp },
138     { "hasSetend", "()Z", (void *)android_os_cts_CpuInstructions_hasSetend },
139     { "hasCp15Barriers", "()Z",
140             (void *)android_os_cts_CpuInstructions_hasCp15Barriers },
141 };
142 
register_android_os_cts_CpuInstructions(JNIEnv * env)143 int register_android_os_cts_CpuInstructions(JNIEnv *env)
144 {
145     jclass clazz = env->FindClass("android/os/cts/CpuInstructions");
146 
147     return env->RegisterNatives(clazz, gMethods,
148             sizeof(gMethods) / sizeof(JNINativeMethod));
149 }
150