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 26 static void sigill_handler(int signum __attribute__((unused))) 27 { 28 siglongjmp(jmpenv, 1); 29 } 30 31 static int do_sigsetjmp() 32 { 33 return sigsetjmp(jmpenv, 1); 34 } 35 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__ 67 static void cntvct() 68 { 69 asm volatile ( "mrs x0, cntvct_el0" : : : "x0" ); 70 } 71 72 jboolean android_os_cts_CpuInstructions_canReadCntvct(JNIEnv *, jobject) 73 { 74 return test_instruction(cntvct); 75 } 76 #else 77 jboolean android_os_cts_CpuInstructions_canReadCntvct(JNIEnv *, jobject) 78 { 79 return false; 80 } 81 #endif 82 83 #ifdef __arm__ 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 91 static void setend() 92 { 93 asm volatile ( 94 "setend be" "\n" 95 "setend le" "\n" 96 ); 97 } 98 99 static void cp15_dsb() 100 { 101 asm volatile ( "mcr p15, 0, %0, c7, c10, 4" : : "r"(0) ); 102 } 103 104 jboolean android_os_cts_CpuInstructions_hasSwp(JNIEnv *, jobject) 105 { 106 return test_instruction(swp); 107 } 108 109 jboolean android_os_cts_CpuInstructions_hasSetend(JNIEnv *, jobject) 110 { 111 return test_instruction(setend); 112 } 113 114 jboolean android_os_cts_CpuInstructions_hasCp15Barriers(JNIEnv *, jobject) 115 { 116 return test_instruction(cp15_dsb); 117 } 118 #else 119 jboolean android_os_cts_CpuInstructions_hasSwp(JNIEnv *, jobject) 120 { 121 return false; 122 } 123 124 jboolean android_os_cts_CpuInstructions_hasSetend(JNIEnv *, jobject) 125 { 126 return false; 127 } 128 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 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