Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /******************************************************************** |
michael@0 | 2 | * * |
michael@0 | 3 | * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. * |
michael@0 | 4 | * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * |
michael@0 | 5 | * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * |
michael@0 | 6 | * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * |
michael@0 | 7 | * * |
michael@0 | 8 | * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 * |
michael@0 | 9 | * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * |
michael@0 | 10 | * * |
michael@0 | 11 | ******************************************************************** |
michael@0 | 12 | |
michael@0 | 13 | CPU capability detection for x86 processors. |
michael@0 | 14 | Originally written by Rudolf Marek. |
michael@0 | 15 | |
michael@0 | 16 | function: |
michael@0 | 17 | last mod: $Id: x86cpu.c 17410 2010-09-21 21:53:48Z tterribe $ |
michael@0 | 18 | |
michael@0 | 19 | ********************************************************************/ |
michael@0 | 20 | |
michael@0 | 21 | #include "x86cpu.h" |
michael@0 | 22 | |
michael@0 | 23 | #if !defined(OC_X86_ASM) |
michael@0 | 24 | ogg_uint32_t oc_cpu_flags_get(void){ |
michael@0 | 25 | return 0; |
michael@0 | 26 | } |
michael@0 | 27 | #else |
michael@0 | 28 | /*Why does MSVC need this complicated rigamarole? |
michael@0 | 29 | At this point I honestly do not care.*/ |
michael@0 | 30 | |
michael@0 | 31 | /*Visual C cpuid helper function. |
michael@0 | 32 | For VS2005 we could as well use the _cpuid builtin, but that wouldn't work |
michael@0 | 33 | for VS2003 users, so we do it in inline assembler.*/ |
michael@0 | 34 | static void oc_cpuid_helper(ogg_uint32_t _cpu_info[4],ogg_uint32_t _op){ |
michael@0 | 35 | _asm{ |
michael@0 | 36 | mov eax,[_op] |
michael@0 | 37 | mov esi,_cpu_info |
michael@0 | 38 | cpuid |
michael@0 | 39 | mov [esi+0],eax |
michael@0 | 40 | mov [esi+4],ebx |
michael@0 | 41 | mov [esi+8],ecx |
michael@0 | 42 | mov [esi+12],edx |
michael@0 | 43 | } |
michael@0 | 44 | } |
michael@0 | 45 | |
michael@0 | 46 | # define cpuid(_op,_eax,_ebx,_ecx,_edx) \ |
michael@0 | 47 | do{ \ |
michael@0 | 48 | ogg_uint32_t cpu_info[4]; \ |
michael@0 | 49 | oc_cpuid_helper(cpu_info,_op); \ |
michael@0 | 50 | (_eax)=cpu_info[0]; \ |
michael@0 | 51 | (_ebx)=cpu_info[1]; \ |
michael@0 | 52 | (_ecx)=cpu_info[2]; \ |
michael@0 | 53 | (_edx)=cpu_info[3]; \ |
michael@0 | 54 | }while(0) |
michael@0 | 55 | |
michael@0 | 56 | static void oc_detect_cpuid_helper(ogg_uint32_t *_eax,ogg_uint32_t *_ebx){ |
michael@0 | 57 | _asm{ |
michael@0 | 58 | pushfd |
michael@0 | 59 | pushfd |
michael@0 | 60 | pop eax |
michael@0 | 61 | mov ebx,eax |
michael@0 | 62 | xor eax,200000h |
michael@0 | 63 | push eax |
michael@0 | 64 | popfd |
michael@0 | 65 | pushfd |
michael@0 | 66 | pop eax |
michael@0 | 67 | popfd |
michael@0 | 68 | mov ecx,_eax |
michael@0 | 69 | mov [ecx],eax |
michael@0 | 70 | mov ecx,_ebx |
michael@0 | 71 | mov [ecx],ebx |
michael@0 | 72 | } |
michael@0 | 73 | } |
michael@0 | 74 | |
michael@0 | 75 | static ogg_uint32_t oc_parse_intel_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){ |
michael@0 | 76 | ogg_uint32_t flags; |
michael@0 | 77 | /*If there isn't even MMX, give up.*/ |
michael@0 | 78 | if(!(_edx&0x00800000))return 0; |
michael@0 | 79 | flags=OC_CPU_X86_MMX; |
michael@0 | 80 | if(_edx&0x02000000)flags|=OC_CPU_X86_MMXEXT|OC_CPU_X86_SSE; |
michael@0 | 81 | if(_edx&0x04000000)flags|=OC_CPU_X86_SSE2; |
michael@0 | 82 | if(_ecx&0x00000001)flags|=OC_CPU_X86_PNI; |
michael@0 | 83 | if(_ecx&0x00000100)flags|=OC_CPU_X86_SSSE3; |
michael@0 | 84 | if(_ecx&0x00080000)flags|=OC_CPU_X86_SSE4_1; |
michael@0 | 85 | if(_ecx&0x00100000)flags|=OC_CPU_X86_SSE4_2; |
michael@0 | 86 | return flags; |
michael@0 | 87 | } |
michael@0 | 88 | |
michael@0 | 89 | static ogg_uint32_t oc_parse_amd_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){ |
michael@0 | 90 | ogg_uint32_t flags; |
michael@0 | 91 | /*If there isn't even MMX, give up.*/ |
michael@0 | 92 | if(!(_edx&0x00800000))return 0; |
michael@0 | 93 | flags=OC_CPU_X86_MMX; |
michael@0 | 94 | if(_edx&0x00400000)flags|=OC_CPU_X86_MMXEXT; |
michael@0 | 95 | if(_edx&0x80000000)flags|=OC_CPU_X86_3DNOW; |
michael@0 | 96 | if(_edx&0x40000000)flags|=OC_CPU_X86_3DNOWEXT; |
michael@0 | 97 | if(_ecx&0x00000040)flags|=OC_CPU_X86_SSE4A; |
michael@0 | 98 | if(_ecx&0x00000800)flags|=OC_CPU_X86_SSE5; |
michael@0 | 99 | return flags; |
michael@0 | 100 | } |
michael@0 | 101 | |
michael@0 | 102 | ogg_uint32_t oc_cpu_flags_get(void){ |
michael@0 | 103 | ogg_uint32_t flags; |
michael@0 | 104 | ogg_uint32_t eax; |
michael@0 | 105 | ogg_uint32_t ebx; |
michael@0 | 106 | ogg_uint32_t ecx; |
michael@0 | 107 | ogg_uint32_t edx; |
michael@0 | 108 | # if !defined(__amd64__)&&!defined(__x86_64__) |
michael@0 | 109 | /*Not all x86-32 chips support cpuid, so we have to check.*/ |
michael@0 | 110 | oc_detect_cpuid_helper(&eax,&ebx); |
michael@0 | 111 | /*No cpuid.*/ |
michael@0 | 112 | if(eax==ebx)return 0; |
michael@0 | 113 | # endif |
michael@0 | 114 | cpuid(0,eax,ebx,ecx,edx); |
michael@0 | 115 | /* l e t n I e n i u n e G*/ |
michael@0 | 116 | if(ecx==0x6C65746E&&edx==0x49656E69&&ebx==0x756E6547|| |
michael@0 | 117 | /* 6 8 x M T e n i u n e G*/ |
michael@0 | 118 | ecx==0x3638784D&&edx==0x54656E69&&ebx==0x756E6547){ |
michael@0 | 119 | int family; |
michael@0 | 120 | int model; |
michael@0 | 121 | /*Intel, Transmeta (tested with Crusoe TM5800):*/ |
michael@0 | 122 | cpuid(1,eax,ebx,ecx,edx); |
michael@0 | 123 | flags=oc_parse_intel_flags(edx,ecx); |
michael@0 | 124 | family=(eax>>8)&0xF; |
michael@0 | 125 | model=(eax>>4)&0xF; |
michael@0 | 126 | /*The SSE unit on the Pentium M and Core Duo is much slower than the MMX |
michael@0 | 127 | unit, so don't use it.*/ |
michael@0 | 128 | if(family==6&&(model==9||model==13||model==14)){ |
michael@0 | 129 | flags&=~(OC_CPU_X86_SSE2|OC_CPU_X86_PNI); |
michael@0 | 130 | } |
michael@0 | 131 | } |
michael@0 | 132 | /* D M A c i t n e h t u A*/ |
michael@0 | 133 | else if(ecx==0x444D4163&&edx==0x69746E65&&ebx==0x68747541|| |
michael@0 | 134 | /* C S N y b e d o e G*/ |
michael@0 | 135 | ecx==0x43534e20&&edx==0x79622065&&ebx==0x646f6547){ |
michael@0 | 136 | /*AMD, Geode:*/ |
michael@0 | 137 | cpuid(0x80000000,eax,ebx,ecx,edx); |
michael@0 | 138 | if(eax<0x80000001)flags=0; |
michael@0 | 139 | else{ |
michael@0 | 140 | cpuid(0x80000001,eax,ebx,ecx,edx); |
michael@0 | 141 | flags=oc_parse_amd_flags(edx,ecx); |
michael@0 | 142 | } |
michael@0 | 143 | /*Also check for SSE.*/ |
michael@0 | 144 | cpuid(1,eax,ebx,ecx,edx); |
michael@0 | 145 | flags|=oc_parse_intel_flags(edx,ecx); |
michael@0 | 146 | } |
michael@0 | 147 | /*Technically some VIA chips can be configured in the BIOS to return any |
michael@0 | 148 | string here the user wants. |
michael@0 | 149 | There is a special detection method that can be used to identify such |
michael@0 | 150 | processors, but in my opinion, if the user really wants to change it, they |
michael@0 | 151 | deserve what they get.*/ |
michael@0 | 152 | /* s l u a H r u a t n e C*/ |
michael@0 | 153 | else if(ecx==0x736C7561&&edx==0x48727561&&ebx==0x746E6543){ |
michael@0 | 154 | /*VIA:*/ |
michael@0 | 155 | /*I only have documentation for the C7 (Esther) and Isaiah (forthcoming) |
michael@0 | 156 | chips (thanks to the engineers from Centaur Technology who provided it). |
michael@0 | 157 | These chips support Intel-like cpuid info. |
michael@0 | 158 | The C3-2 (Nehemiah) cores appear to, as well.*/ |
michael@0 | 159 | cpuid(1,eax,ebx,ecx,edx); |
michael@0 | 160 | flags=oc_parse_intel_flags(edx,ecx); |
michael@0 | 161 | if(eax>=0x80000001){ |
michael@0 | 162 | /*The (non-Nehemiah) C3 processors support AMD-like cpuid info. |
michael@0 | 163 | We need to check this even if the Intel test succeeds to pick up 3DNow! |
michael@0 | 164 | support on these processors. |
michael@0 | 165 | Unlike actual AMD processors, we cannot _rely_ on this info, since |
michael@0 | 166 | some cores (e.g., the 693 stepping of the Nehemiah) claim to support |
michael@0 | 167 | this function, yet return edx=0, despite the Intel test indicating |
michael@0 | 168 | MMX support. |
michael@0 | 169 | Therefore the features detected here are strictly added to those |
michael@0 | 170 | detected by the Intel test.*/ |
michael@0 | 171 | /*TODO: How about earlier chips?*/ |
michael@0 | 172 | cpuid(0x80000001,eax,ebx,ecx,edx); |
michael@0 | 173 | /*Note: As of the C7, this function returns Intel-style extended feature |
michael@0 | 174 | flags, not AMD-style. |
michael@0 | 175 | Currently, this only defines bits 11, 20, and 29 (0x20100800), which |
michael@0 | 176 | do not conflict with any of the AMD flags we inspect. |
michael@0 | 177 | For the remaining bits, Intel tells us, "Do not count on their value", |
michael@0 | 178 | but VIA assures us that they will all be zero (at least on the C7 and |
michael@0 | 179 | Isaiah chips). |
michael@0 | 180 | In the (unlikely) event a future processor uses bits 18, 19, 30, or 31 |
michael@0 | 181 | (0xC0C00000) for something else, we will have to add code to detect |
michael@0 | 182 | the model to decide when it is appropriate to inspect them.*/ |
michael@0 | 183 | flags|=oc_parse_amd_flags(edx,ecx); |
michael@0 | 184 | } |
michael@0 | 185 | } |
michael@0 | 186 | else{ |
michael@0 | 187 | /*Implement me.*/ |
michael@0 | 188 | flags=0; |
michael@0 | 189 | } |
michael@0 | 190 | return flags; |
michael@0 | 191 | } |
michael@0 | 192 | #endif |