Hi All,
I have run into a problem with pixman's CPU detection code under QEMU ARM.
When trying to run an executable linked with pixman under QEMU, I get a crash
like this:
21553 open("/proc/self/auxv",O_RDONLY) = 3
...
21553 read(3,0x7ffdb0,8) = 8
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
Exit reason and status: signal 11
/proc/self/auxv is from the host x86 kernel, not an ARM kernel, as pixman
expects.
Parsing /proc/self/auxv will only work on Linux with proc mounted, and not
under QEMU.
The attached patch modified pixman/pixman-cpu.c to use a more direct method of
detecting the CPU capabilities (i.e. trying to run a NEON instruction)
This prevents pixman from crashing under QEMU, and detects NEON correctly on
an ARMv7 target.
thanks,
Mike
>From 38f8c4164c440222907284863df762a1a084c598 Mon Sep 17 00:00:00 2001
From: Mike McCormack <[email protected]>
Date: Thu, 9 Dec 2010 13:31:41 +0900
Subject: [PATCH] Check for NEON using a signal handler to catch SIGILL
---
pixman/pixman-cpu.c | 87 ++++++++++++++++++++++++---------------------------
1 files changed, 41 insertions(+), 46 deletions(-)
diff --git a/pixman/pixman-cpu.c b/pixman/pixman-cpu.c
index e4fb1e4..8e0dd15 100644
--- a/pixman/pixman-cpu.c
+++ b/pixman/pixman-cpu.c
@@ -246,60 +246,55 @@ pixman_have_arm_neon (void)
#else /* linux ELF */
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <string.h>
-#include <elf.h>
+#include <signal.h>
+#include <setjmp.h>
-static pixman_bool_t arm_has_v7 = FALSE;
static pixman_bool_t arm_has_v6 = FALSE;
-static pixman_bool_t arm_has_vfp = FALSE;
static pixman_bool_t arm_has_neon = FALSE;
-static pixman_bool_t arm_has_iwmmxt = FALSE;
static pixman_bool_t arm_tests_initialized = FALSE;
+static sigjmp_buf cpu_jmpbuf;
+
static void
-pixman_arm_read_auxv ()
+pixman_catch_sigill(int sig)
{
- int fd;
- Elf32_auxv_t aux;
+ siglongjmp(cpu_jmpbuf, 1);
+}
+
+static void
+pixman_arm_check_neon (void)
+{
+ struct sigaction sa, old_sa;
- fd = open ("/proc/self/auxv", O_RDONLY);
- if (fd >= 0)
+ /* setup the sigaction */
+ sa.sa_handler = pixman_catch_sigill;
+ sa.sa_flags = SA_RESTART;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGILL, &sa, &old_sa);
+
+#if defined(USE_ARM_NEON)
+ if (!sigsetjmp(cpu_jmpbuf, 1))
{
- while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t))
- {
- if (aux.a_type == AT_HWCAP)
- {
- uint32_t hwcap = aux.a_un.a_val;
- /* hardcode these values to avoid depending on specific
- * versions of the hwcap header, e.g. HWCAP_NEON
- */
- arm_has_vfp = (hwcap & 64) != 0;
- arm_has_iwmmxt = (hwcap & 512) != 0;
- /* this flag is only present on kernel 2.6.29 */
- arm_has_neon = (hwcap & 4096) != 0;
- }
- else if (aux.a_type == AT_PLATFORM)
- {
- const char *plat = (const char*) aux.a_un.a_val;
- if (strncmp (plat, "v7l", 3) == 0)
- {
- arm_has_v7 = TRUE;
- arm_has_v6 = TRUE;
- }
- else if (strncmp (plat, "v6l", 3) == 0)
- {
- arm_has_v6 = TRUE;
- }
- }
- }
- close (fd);
+ asm volatile (
+ ".fpu neon\n"
+ "\tvqadd.u8 d0, d1, d0\n"
+ );
+ arm_has_neon = TRUE;
}
+#endif
+
+#if defined(USE_ARM_SIMD)
+ if (!sigsetjmp(cpu_jmpbuf, 1))
+ {
+ asm volatile (
+ ".arch armv6\n"
+ "\tuqadd8 r1, r1, r2\n"
+ : : :"r1", "r2");
+ arm_has_v6 = TRUE;
+ }
+#endif
+
+ sigaction(SIGILL, &old_sa, NULL);
arm_tests_initialized = TRUE;
}
@@ -309,7 +304,7 @@ pixman_bool_t
pixman_have_arm_simd (void)
{
if (!arm_tests_initialized)
- pixman_arm_read_auxv ();
+ pixman_arm_check_neon ();
return arm_has_v6;
}
@@ -321,7 +316,7 @@ pixman_bool_t
pixman_have_arm_neon (void)
{
if (!arm_tests_initialized)
- pixman_arm_read_auxv ();
+ pixman_arm_check_neon ();
return arm_has_neon;
}
--
1.7.0.4
_______________________________________________
Pixman mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/pixman