1 /* 2 * Copyright (C) 2010 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 #include <cpu-features.h> 17 #include <setjmp.h> 18 #include <stdio.h> 19 #include <signal.h> 20 21 #ifndef __arm__ 22 #error "Only compile this file for an ARM target" 23 #endif 24 25 static int volatile g_signal_raised; 26 static sigjmp_buf g_jumper; 27 28 static void my_signal_handler(int signum) { 29 g_signal_raised = 1; 30 siglongjmp(g_jumper, 1); 31 } 32 33 static int32_t do_idiv(int32_t a, int32_t b) { 34 __asm__ __volatile__( 35 "sdiv %0, %0, %1\n\t" 36 : "=&r"(a) 37 : "r"(b) 38 : "cc"); 39 return a; 40 } 41 42 // Check that the ARM idiv instruction is supported. 43 // Returns 1 on success, 0 otherwise. 44 static int check_idiv(void) { 45 // Setup SIGILL signal handler. 46 struct sigaction old_handler, new_handler; 47 memset(&new_handler, 0, sizeof(new_handler)); 48 new_handler.sa_handler = my_signal_handler; 49 sigaction(SIGILL, &new_handler, &old_handler); 50 51 // Do the division. 52 g_signal_raised = 0; 53 if (sigsetjmp(g_jumper, 0) == 0) 54 do_idiv(12345, 17); 55 56 // Restore SIGILL handler. 57 sigaction(SIGILL, &old_handler, NULL); 58 59 return g_signal_raised == 0; 60 } 61 62 int main(void) 63 { 64 uint32_t cpu_id = android_getCpuIdArm(); 65 printf("cpu-features reports the following CPUID: 0x%08x\n", 66 cpu_id); 67 68 uint64_t features = android_getCpuFeatures(); 69 #ifdef __thumb2__ 70 const uint64_t idiv_flag = ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2; 71 const char* variant = "thumb"; 72 #else 73 const uint64_t idiv_flag = ANDROID_CPU_ARM_FEATURE_IDIV_ARM; 74 const char* variant = "arm"; 75 #endif 76 77 printf("status of %s idiv instruction:\n", variant); 78 int idiv_reported = (features & idiv_flag) != 0; 79 printf(" reported : %s\n", 80 idiv_reported ? "supported" : "unsupported"); 81 82 int idiv_checked = check_idiv(); 83 printf(" runtime check : %s\n", 84 idiv_checked ? "supported" : "unsupported"); 85 86 return (idiv_reported != idiv_checked); 87 } 88