Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright © 2000 SuSE, Inc.
  3.  * Copyright © 2007 Red Hat, Inc.
  4.  *
  5.  * Permission to use, copy, modify, distribute, and sell this software and its
  6.  * documentation for any purpose is hereby granted without fee, provided that
  7.  * the above copyright notice appear in all copies and that both that
  8.  * copyright notice and this permission notice appear in supporting
  9.  * documentation, and that the name of SuSE not be used in advertising or
  10.  * publicity pertaining to distribution of the software without specific,
  11.  * written prior permission.  SuSE makes no representations about the
  12.  * suitability of this software for any purpose.  It is provided "as is"
  13.  * without express or implied warranty.
  14.  *
  15.  * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  16.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
  17.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  18.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  19.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  20.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21.  */
  22. #ifdef HAVE_CONFIG_H
  23. #include <config.h>
  24. #endif
  25.  
  26. #include "pixman-private.h"
  27.  
  28. #if defined(USE_X86_MMX) || defined (USE_SSE2)
  29.  
  30. /* The CPU detection code needs to be in a file not compiled with
  31.  * "-mmmx -msse", as gcc would generate CMOV instructions otherwise
  32.  * that would lead to SIGILL instructions on old CPUs that don't have
  33.  * it.
  34.  */
  35.  
  36. typedef enum
  37. {
  38.     X86_MMX                     = (1 << 0),
  39.     X86_MMX_EXTENSIONS          = (1 << 1),
  40.     X86_SSE                     = (1 << 2) | X86_MMX_EXTENSIONS,
  41.     X86_SSE2                    = (1 << 3),
  42.     X86_CMOV                    = (1 << 4)
  43. } cpu_features_t;
  44.  
  45. #ifdef HAVE_GETISAX
  46.  
  47. #include <sys/auxv.h>
  48.  
  49. static cpu_features_t
  50. detect_cpu_features (void)
  51. {
  52.     cpu_features_t features = 0;
  53.     unsigned int result = 0;
  54.  
  55.     if (getisax (&result, 1))
  56.     {
  57.         if (result & AV_386_CMOV)
  58.             features |= X86_CMOV;
  59.         if (result & AV_386_MMX)
  60.             features |= X86_MMX;
  61.         if (result & AV_386_AMD_MMX)
  62.             features |= X86_MMX_EXTENSIONS;
  63.         if (result & AV_386_SSE)
  64.             features |= X86_SSE;
  65.         if (result & AV_386_SSE2)
  66.             features |= X86_SSE2;
  67.     }
  68.  
  69.     return features;
  70. }
  71.  
  72. #else
  73.  
  74. #define _PIXMAN_X86_64                                                  \
  75.     (defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64))
  76.  
  77. static pixman_bool_t
  78. have_cpuid (void)
  79. {
  80. #if _PIXMAN_X86_64 || defined (_MSC_VER)
  81.  
  82.     return TRUE;
  83.  
  84. #elif defined (__GNUC__)
  85.     uint32_t result;
  86.  
  87.     __asm__ volatile (
  88.         "pushf"                         "\n\t"
  89.         "pop %%eax"                     "\n\t"
  90.         "mov %%eax, %%ecx"              "\n\t"
  91.         "xor $0x00200000, %%eax"        "\n\t"
  92.         "push %%eax"                    "\n\t"
  93.         "popf"                          "\n\t"
  94.         "pushf"                         "\n\t"
  95.         "pop %%eax"                     "\n\t"
  96.         "xor %%ecx, %%eax"              "\n\t"
  97.         "mov %%eax, %0"                 "\n\t"
  98.         : "=r" (result)
  99.         :
  100.         : "%eax", "%ecx");
  101.  
  102.     return !!result;
  103.  
  104. #else
  105. #error "Unknown compiler"
  106. #endif
  107. }
  108.  
  109. static void
  110. pixman_cpuid (uint32_t feature,
  111.               uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
  112. {
  113. #if defined (__GNUC__)
  114.  
  115. #if _PIXMAN_X86_64
  116.     __asm__ volatile (
  117.         "cpuid"                         "\n\t"
  118.         : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
  119.         : "a" (feature));
  120. #else
  121.     /* On x86-32 we need to be careful about the handling of %ebx
  122.      * and %esp. We can't declare either one as clobbered
  123.      * since they are special registers (%ebx is the "PIC
  124.      * register" holding an offset to global data, %esp the
  125.      * stack pointer), so we need to make sure that %ebx is
  126.      * preserved, and that %esp has its original value when
  127.      * accessing the output operands.
  128.      */
  129.     __asm__ volatile (
  130.         "xchg %%ebx, %1"                "\n\t"
  131.         "cpuid"                         "\n\t"
  132.         "xchg %%ebx, %1"                "\n\t"
  133.         : "=a" (*a), "=r" (*b), "=c" (*c), "=d" (*d)
  134.         : "a" (feature));
  135. #endif
  136.  
  137. #elif defined (_MSC_VER)
  138.     int info[4];
  139.  
  140.     __cpuid (info, feature);
  141.  
  142.     *a = info[0];
  143.     *b = info[1];
  144.     *c = info[2];
  145.     *d = info[3];
  146. #else
  147. #error Unknown compiler
  148. #endif
  149. }
  150.  
  151. static cpu_features_t
  152. detect_cpu_features (void)
  153. {
  154.     uint32_t a, b, c, d;
  155.     cpu_features_t features = 0;
  156.  
  157.     if (!have_cpuid())
  158.         return features;
  159.  
  160.     /* Get feature bits */
  161.     pixman_cpuid (0x01, &a, &b, &c, &d);
  162.     if (d & (1 << 15))
  163.         features |= X86_CMOV;
  164.     if (d & (1 << 23))
  165.         features |= X86_MMX;
  166.     if (d & (1 << 25))
  167.         features |= X86_SSE;
  168.     if (d & (1 << 26))
  169.         features |= X86_SSE2;
  170.  
  171.     /* Check for AMD specific features */
  172.     if ((features & X86_MMX) && !(features & X86_SSE))
  173.     {
  174.         char vendor[13];
  175.  
  176.         /* Get vendor string */
  177.         memset (vendor, 0, sizeof vendor);
  178.  
  179.         pixman_cpuid (0x00, &a, &b, &c, &d);
  180.         memcpy (vendor + 0, &b, 4);
  181.         memcpy (vendor + 4, &d, 4);
  182.         memcpy (vendor + 8, &c, 4);
  183.  
  184.         if (strcmp (vendor, "AuthenticAMD") == 0 ||
  185.             strcmp (vendor, "Geode by NSC") == 0)
  186.         {
  187.             pixman_cpuid (0x80000000, &a, &b, &c, &d);
  188.             if (a >= 0x80000001)
  189.             {
  190.                 pixman_cpuid (0x80000001, &a, &b, &c, &d);
  191.  
  192.                 if (d & (1 << 22))
  193.                     features |= X86_MMX_EXTENSIONS;
  194.             }
  195.         }
  196.     }
  197.  
  198.     return features;
  199. }
  200.  
  201. #endif
  202.  
  203. static pixman_bool_t
  204. have_feature (cpu_features_t feature)
  205. {
  206.     static pixman_bool_t initialized;
  207.     static cpu_features_t features;
  208.  
  209.     if (!initialized)
  210.     {
  211.         features = detect_cpu_features();
  212.         initialized = TRUE;
  213.     }
  214.  
  215.     return (features & feature) == feature;
  216. }
  217.  
  218. #endif
  219.  
  220. pixman_implementation_t *
  221. _pixman_x86_get_implementations (pixman_implementation_t *imp)
  222. {
  223. #define MMX_BITS  (X86_MMX | X86_MMX_EXTENSIONS)
  224. #define SSE2_BITS (X86_MMX | X86_MMX_EXTENSIONS | X86_SSE | X86_SSE2)
  225.  
  226. #ifdef USE_X86_MMX
  227.     if (!_pixman_disabled ("mmx") && have_feature (MMX_BITS))
  228.         imp = _pixman_implementation_create_mmx (imp);
  229. #endif
  230.  
  231. #ifdef USE_SSE2
  232.     if (!_pixman_disabled ("sse2") && have_feature (SSE2_BITS))
  233.         imp = _pixman_implementation_create_sse2 (imp);
  234. #endif
  235.  
  236.     return imp;
  237. }
  238.