| /* |
| * Copyright © 2000 SuSE, Inc. |
| * Copyright © 2007 Red Hat, Inc. |
| * |
| * Permission to use, copy, modify, distribute, and sell this software and its |
| * documentation for any purpose is hereby granted without fee, provided that |
| * the above copyright notice appear in all copies and that both that |
| * copyright notice and this permission notice appear in supporting |
| * documentation, and that the name of SuSE not be used in advertising or |
| * publicity pertaining to distribution of the software without specific, |
| * written prior permission. SuSE makes no representations about the |
| * suitability of this software for any purpose. It is provided "as is" |
| * without express or implied warranty. |
| * |
| * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE |
| * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| */ |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include "pixman-private.h" |
| |
| #ifdef USE_VMX |
| |
| /* The CPU detection code needs to be in a file not compiled with |
| * "-maltivec -mabi=altivec", as gcc would try to save vector register |
| * across function calls causing SIGILL on cpus without Altivec/vmx. |
| */ |
| #ifdef __APPLE__ |
| #include <sys/sysctl.h> |
| |
| static pixman_bool_t |
| pixman_have_vmx (void) |
| { |
| int error, have_vmx; |
| size_t length = sizeof(have_vmx); |
| |
| error = sysctlbyname ("hw.optional.altivec", &have_vmx, &length, NULL, 0); |
| |
| if (error) |
| return FALSE; |
| |
| return have_vmx; |
| } |
| |
| #elif defined (__OpenBSD__) |
| #include <sys/param.h> |
| #include <sys/sysctl.h> |
| #include <machine/cpu.h> |
| |
| static pixman_bool_t |
| pixman_have_vmx (void) |
| { |
| int error, have_vmx; |
| int mib[2] = { CTL_MACHDEP, CPU_ALTIVEC }; |
| size_t length = sizeof(have_vmx); |
| |
| error = sysctl (mib, 2, &have_vmx, &length, NULL, 0); |
| |
| if (error != 0) |
| return FALSE; |
| |
| return have_vmx; |
| } |
| |
| #elif defined (__linux__) |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <linux/auxvec.h> |
| #include <asm/cputable.h> |
| |
| static pixman_bool_t |
| pixman_have_vmx (void) |
| { |
| int have_vmx = FALSE; |
| int fd; |
| struct |
| { |
| unsigned long type; |
| unsigned long value; |
| } aux; |
| |
| fd = open ("/proc/self/auxv", O_RDONLY); |
| if (fd >= 0) |
| { |
| while (read (fd, &aux, sizeof (aux)) == sizeof (aux)) |
| { |
| if (aux.type == AT_HWCAP && (aux.value & PPC_FEATURE_HAS_ALTIVEC)) |
| { |
| have_vmx = TRUE; |
| break; |
| } |
| } |
| |
| close (fd); |
| } |
| |
| return have_vmx; |
| } |
| |
| #else /* !__APPLE__ && !__OpenBSD__ && !__linux__ */ |
| #include <signal.h> |
| #include <setjmp.h> |
| |
| static jmp_buf jump_env; |
| |
| static void |
| vmx_test (int sig, |
| siginfo_t *si, |
| void * unused) |
| { |
| longjmp (jump_env, 1); |
| } |
| |
| static pixman_bool_t |
| pixman_have_vmx (void) |
| { |
| struct sigaction sa, osa; |
| int jmp_result; |
| |
| sa.sa_flags = SA_SIGINFO; |
| sigemptyset (&sa.sa_mask); |
| sa.sa_sigaction = vmx_test; |
| sigaction (SIGILL, &sa, &osa); |
| jmp_result = setjmp (jump_env); |
| if (jmp_result == 0) |
| { |
| asm volatile ( "vor 0, 0, 0" ); |
| } |
| sigaction (SIGILL, &osa, NULL); |
| return (jmp_result == 0); |
| } |
| |
| #endif /* __APPLE__ */ |
| #endif /* USE_VMX */ |
| |
| pixman_implementation_t * |
| _pixman_ppc_get_implementations (pixman_implementation_t *imp) |
| { |
| #ifdef USE_VMX |
| if (!_pixman_disabled ("vmx") && pixman_have_vmx ()) |
| imp = _pixman_implementation_create_vmx (imp); |
| #endif |
| |
| return imp; |
| } |