| # |
| # x86 CPU recognition |
| # |
| # Copyright (C) 2002-2007 Peter Johnson |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met: |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE |
| # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| # POSSIBILITY OF SUCH DAMAGE. |
| %{ |
| #include <util.h> |
| |
| #include <ctype.h> |
| #include <libyasm.h> |
| #include <libyasm/phash.h> |
| |
| #include "modules/arch/x86/x86arch.h" |
| |
| #define PROC_8086 0 |
| #define PROC_186 1 |
| #define PROC_286 2 |
| #define PROC_386 3 |
| #define PROC_486 4 |
| #define PROC_586 5 |
| #define PROC_686 6 |
| #define PROC_p2 7 |
| #define PROC_p3 8 |
| #define PROC_p4 9 |
| #define PROC_prescott 10 |
| #define PROC_conroe 11 |
| #define PROC_penryn 12 |
| #define PROC_nehalem 13 |
| #define PROC_westmere 14 |
| #define PROC_sandybridge 15 |
| |
| static void |
| x86_cpu_intel(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) |
| { |
| BitVector_Empty(cpu); |
| |
| BitVector_Bit_On(cpu, CPU_Priv); |
| if (data >= PROC_286) |
| BitVector_Bit_On(cpu, CPU_Prot); |
| if (data >= PROC_386) |
| BitVector_Bit_On(cpu, CPU_SMM); |
| if (data >= PROC_sandybridge) |
| BitVector_Bit_On(cpu, CPU_AVX); |
| if (data >= PROC_westmere) { |
| BitVector_Bit_On(cpu, CPU_AES); |
| BitVector_Bit_On(cpu, CPU_CLMUL); |
| } |
| if (data >= PROC_nehalem) { |
| BitVector_Bit_On(cpu, CPU_SSE42); |
| BitVector_Bit_On(cpu, CPU_XSAVE); |
| } |
| if (data >= PROC_penryn) |
| BitVector_Bit_On(cpu, CPU_SSE41); |
| if (data >= PROC_conroe) |
| BitVector_Bit_On(cpu, CPU_SSSE3); |
| if (data >= PROC_prescott) |
| BitVector_Bit_On(cpu, CPU_SSE3); |
| if (data >= PROC_p4) |
| BitVector_Bit_On(cpu, CPU_SSE2); |
| if (data >= PROC_p3) |
| BitVector_Bit_On(cpu, CPU_SSE); |
| if (data >= PROC_p2) |
| BitVector_Bit_On(cpu, CPU_MMX); |
| if (data >= PROC_486) |
| BitVector_Bit_On(cpu, CPU_FPU); |
| if (data >= PROC_prescott) |
| BitVector_Bit_On(cpu, CPU_EM64T); |
| |
| if (data >= PROC_p4) |
| BitVector_Bit_On(cpu, CPU_P4); |
| if (data >= PROC_p3) |
| BitVector_Bit_On(cpu, CPU_P3); |
| if (data >= PROC_686) |
| BitVector_Bit_On(cpu, CPU_686); |
| if (data >= PROC_586) |
| BitVector_Bit_On(cpu, CPU_586); |
| if (data >= PROC_486) |
| BitVector_Bit_On(cpu, CPU_486); |
| if (data >= PROC_386) |
| BitVector_Bit_On(cpu, CPU_386); |
| if (data >= PROC_286) |
| BitVector_Bit_On(cpu, CPU_286); |
| if (data >= PROC_186) |
| BitVector_Bit_On(cpu, CPU_186); |
| BitVector_Bit_On(cpu, CPU_086); |
| |
| /* Use Intel long NOPs if 686 or better */ |
| if (data >= PROC_686) |
| arch_x86->nop = X86_NOP_INTEL; |
| else |
| arch_x86->nop = X86_NOP_BASIC; |
| } |
| |
| static void |
| x86_cpu_ia64(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) |
| { |
| BitVector_Empty(cpu); |
| BitVector_Bit_On(cpu, CPU_Priv); |
| BitVector_Bit_On(cpu, CPU_Prot); |
| BitVector_Bit_On(cpu, CPU_SMM); |
| BitVector_Bit_On(cpu, CPU_SSE2); |
| BitVector_Bit_On(cpu, CPU_SSE); |
| BitVector_Bit_On(cpu, CPU_MMX); |
| BitVector_Bit_On(cpu, CPU_FPU); |
| BitVector_Bit_On(cpu, CPU_IA64); |
| BitVector_Bit_On(cpu, CPU_P4); |
| BitVector_Bit_On(cpu, CPU_P3); |
| BitVector_Bit_On(cpu, CPU_686); |
| BitVector_Bit_On(cpu, CPU_586); |
| BitVector_Bit_On(cpu, CPU_486); |
| BitVector_Bit_On(cpu, CPU_386); |
| BitVector_Bit_On(cpu, CPU_286); |
| BitVector_Bit_On(cpu, CPU_186); |
| BitVector_Bit_On(cpu, CPU_086); |
| } |
| |
| #define PROC_bulldozer 11 |
| #define PROC_k10 10 |
| #define PROC_venice 9 |
| #define PROC_hammer 8 |
| #define PROC_k7 7 |
| #define PROC_k6 6 |
| |
| static void |
| x86_cpu_amd(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) |
| { |
| BitVector_Empty(cpu); |
| |
| BitVector_Bit_On(cpu, CPU_Priv); |
| BitVector_Bit_On(cpu, CPU_Prot); |
| BitVector_Bit_On(cpu, CPU_SMM); |
| BitVector_Bit_On(cpu, CPU_3DNow); |
| if (data >= PROC_bulldozer) { |
| BitVector_Bit_On(cpu, CPU_XOP); |
| BitVector_Bit_On(cpu, CPU_FMA4); |
| } |
| if (data >= PROC_k10) |
| BitVector_Bit_On(cpu, CPU_SSE4a); |
| if (data >= PROC_venice) |
| BitVector_Bit_On(cpu, CPU_SSE3); |
| if (data >= PROC_hammer) |
| BitVector_Bit_On(cpu, CPU_SSE2); |
| if (data >= PROC_k7) |
| BitVector_Bit_On(cpu, CPU_SSE); |
| if (data >= PROC_k6) |
| BitVector_Bit_On(cpu, CPU_MMX); |
| BitVector_Bit_On(cpu, CPU_FPU); |
| |
| if (data >= PROC_hammer) |
| BitVector_Bit_On(cpu, CPU_Hammer); |
| if (data >= PROC_k7) |
| BitVector_Bit_On(cpu, CPU_Athlon); |
| if (data >= PROC_k6) |
| BitVector_Bit_On(cpu, CPU_K6); |
| BitVector_Bit_On(cpu, CPU_686); |
| BitVector_Bit_On(cpu, CPU_586); |
| BitVector_Bit_On(cpu, CPU_486); |
| BitVector_Bit_On(cpu, CPU_386); |
| BitVector_Bit_On(cpu, CPU_286); |
| BitVector_Bit_On(cpu, CPU_186); |
| BitVector_Bit_On(cpu, CPU_086); |
| |
| /* Use AMD long NOPs if k6 or better */ |
| if (data >= PROC_k6) |
| arch_x86->nop = X86_NOP_AMD; |
| else |
| arch_x86->nop = X86_NOP_BASIC; |
| } |
| |
| static void |
| x86_cpu_set(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) |
| { |
| BitVector_Bit_On(cpu, data); |
| } |
| |
| static void |
| x86_cpu_clear(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) |
| { |
| BitVector_Bit_Off(cpu, data); |
| } |
| |
| static void |
| x86_cpu_set_sse4(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) |
| { |
| BitVector_Bit_On(cpu, CPU_SSE41); |
| BitVector_Bit_On(cpu, CPU_SSE42); |
| } |
| |
| static void |
| x86_cpu_clear_sse4(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) |
| { |
| BitVector_Bit_Off(cpu, CPU_SSE41); |
| BitVector_Bit_Off(cpu, CPU_SSE42); |
| } |
| |
| static void |
| x86_nop(wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data) |
| { |
| arch_x86->nop = data; |
| } |
| |
| %} |
| %ignore-case |
| %language=ANSI-C |
| %compare-strncmp |
| %readonly-tables |
| %enum |
| %struct-type |
| %define hash-function-name cpu_hash |
| %define lookup-function-name cpu_find |
| struct cpu_parse_data { |
| const char *name; |
| void (*handler) (wordptr cpu, yasm_arch_x86 *arch_x86, unsigned int data); |
| unsigned int data; |
| }; |
| %% |
| 8086, x86_cpu_intel, PROC_8086 |
| 186, x86_cpu_intel, PROC_186 |
| 80186, x86_cpu_intel, PROC_186 |
| i186, x86_cpu_intel, PROC_186 |
| 286, x86_cpu_intel, PROC_286 |
| 80286, x86_cpu_intel, PROC_286 |
| i286, x86_cpu_intel, PROC_286 |
| 386, x86_cpu_intel, PROC_386 |
| 80386, x86_cpu_intel, PROC_386 |
| i386, x86_cpu_intel, PROC_386 |
| 486, x86_cpu_intel, PROC_486 |
| 80486, x86_cpu_intel, PROC_486 |
| i486, x86_cpu_intel, PROC_486 |
| 586, x86_cpu_intel, PROC_586 |
| i586, x86_cpu_intel, PROC_586 |
| pentium, x86_cpu_intel, PROC_586 |
| p5, x86_cpu_intel, PROC_586 |
| 686, x86_cpu_intel, PROC_686 |
| i686, x86_cpu_intel, PROC_686 |
| p6, x86_cpu_intel, PROC_686 |
| ppro, x86_cpu_intel, PROC_686 |
| pentiumpro, x86_cpu_intel, PROC_686 |
| p2, x86_cpu_intel, PROC_p2 |
| pentium2, x86_cpu_intel, PROC_p2 |
| pentium-2, x86_cpu_intel, PROC_p2 |
| pentiumii, x86_cpu_intel, PROC_p2 |
| pentium-ii, x86_cpu_intel, PROC_p2 |
| p3, x86_cpu_intel, PROC_p3 |
| pentium3, x86_cpu_intel, PROC_p3 |
| pentium-3, x86_cpu_intel, PROC_p3 |
| pentiumiii, x86_cpu_intel, PROC_p3 |
| pentium-iii, x86_cpu_intel, PROC_p3 |
| katmai, x86_cpu_intel, PROC_p3 |
| p4, x86_cpu_intel, PROC_p4 |
| pentium4, x86_cpu_intel, PROC_p4 |
| pentium-4, x86_cpu_intel, PROC_p4 |
| pentiumiv, x86_cpu_intel, PROC_p4 |
| pentium-iv, x86_cpu_intel, PROC_p4 |
| williamette, x86_cpu_intel, PROC_p4 |
| ia64, x86_cpu_ia64, 0 |
| ia-64, x86_cpu_ia64, 0 |
| itanium, x86_cpu_ia64, 0 |
| k6, x86_cpu_amd, PROC_k6 |
| k7, x86_cpu_amd, PROC_k7 |
| athlon, x86_cpu_amd, PROC_k7 |
| k8, x86_cpu_amd, PROC_hammer |
| hammer, x86_cpu_amd, PROC_hammer |
| clawhammer, x86_cpu_amd, PROC_hammer |
| opteron, x86_cpu_amd, PROC_hammer |
| athlon64, x86_cpu_amd, PROC_hammer |
| athlon-64, x86_cpu_amd, PROC_hammer |
| venice, x86_cpu_amd, PROC_venice |
| k10, x86_cpu_amd, PROC_k10 |
| phenom, x86_cpu_amd, PROC_k10 |
| family10h, x86_cpu_amd, PROC_k10 |
| bulldozer, x86_cpu_amd, PROC_bulldozer |
| prescott, x86_cpu_intel, PROC_prescott |
| conroe, x86_cpu_intel, PROC_conroe |
| core2, x86_cpu_intel, PROC_conroe |
| penryn, x86_cpu_intel, PROC_penryn |
| nehalem, x86_cpu_intel, PROC_nehalem |
| corei7, x86_cpu_intel, PROC_nehalem |
| westmere, x86_cpu_intel, PROC_westmere |
| sandybridge, x86_cpu_intel, PROC_sandybridge |
| # |
| # Features have "no" versions to disable them, and only set/reset the |
| # specific feature being changed. All other bits are left alone. |
| # |
| fpu, x86_cpu_set, CPU_FPU |
| nofpu, x86_cpu_clear, CPU_FPU |
| mmx, x86_cpu_set, CPU_MMX |
| nommx, x86_cpu_clear, CPU_MMX |
| sse, x86_cpu_set, CPU_SSE |
| nosse, x86_cpu_clear, CPU_SSE |
| sse2, x86_cpu_set, CPU_SSE2 |
| nosse2, x86_cpu_clear, CPU_SSE2 |
| sse3, x86_cpu_set, CPU_SSE3 |
| nosse3, x86_cpu_clear, CPU_SSE3 |
| #pni, x86_cpu_set, CPU_PNI |
| #nopni, x86_cpu_clear, CPU_PNI |
| 3dnow, x86_cpu_set, CPU_3DNow |
| no3dnow, x86_cpu_clear, CPU_3DNow |
| cyrix, x86_cpu_set, CPU_Cyrix |
| nocyrix, x86_cpu_clear, CPU_Cyrix |
| amd, x86_cpu_set, CPU_AMD |
| noamd, x86_cpu_clear, CPU_AMD |
| smm, x86_cpu_set, CPU_SMM |
| nosmm, x86_cpu_clear, CPU_SMM |
| prot, x86_cpu_set, CPU_Prot |
| noprot, x86_cpu_clear, CPU_Prot |
| protected, x86_cpu_set, CPU_Prot |
| noprotected, x86_cpu_clear, CPU_Prot |
| undoc, x86_cpu_set, CPU_Undoc |
| noundoc, x86_cpu_clear, CPU_Undoc |
| undocumented, x86_cpu_set, CPU_Undoc |
| noundocumented, x86_cpu_clear, CPU_Undoc |
| obs, x86_cpu_set, CPU_Obs |
| noobs, x86_cpu_clear, CPU_Obs |
| obsolete, x86_cpu_set, CPU_Obs |
| noobsolete, x86_cpu_clear, CPU_Obs |
| priv, x86_cpu_set, CPU_Priv |
| nopriv, x86_cpu_clear, CPU_Priv |
| privileged, x86_cpu_set, CPU_Priv |
| noprivileged, x86_cpu_clear, CPU_Priv |
| svm, x86_cpu_set, CPU_SVM |
| nosvm, x86_cpu_clear, CPU_SVM |
| padlock, x86_cpu_set, CPU_PadLock |
| nopadlock, x86_cpu_clear, CPU_PadLock |
| em64t, x86_cpu_set, CPU_EM64T |
| noem64t, x86_cpu_clear, CPU_EM64T |
| ssse3, x86_cpu_set, CPU_SSSE3 |
| nossse3, x86_cpu_clear, CPU_SSSE3 |
| sse4.1, x86_cpu_set, CPU_SSE41 |
| nosse4.1, x86_cpu_clear, CPU_SSE41 |
| sse41, x86_cpu_set, CPU_SSE41 |
| nosse41, x86_cpu_clear, CPU_SSE41 |
| sse4.2, x86_cpu_set, CPU_SSE42 |
| nosse4.2, x86_cpu_clear, CPU_SSE42 |
| sse42, x86_cpu_set, CPU_SSE42 |
| nosse42, x86_cpu_clear, CPU_SSE42 |
| sse4a, x86_cpu_set, CPU_SSE4a |
| nosse4a, x86_cpu_clear, CPU_SSE4a |
| sse4, x86_cpu_set_sse4, 0 |
| nosse4, x86_cpu_clear_sse4, 0 |
| xsave, x86_cpu_set, CPU_XSAVE |
| noxsave, x86_cpu_clear, CPU_XSAVE |
| avx, x86_cpu_set, CPU_AVX |
| noavx, x86_cpu_clear, CPU_AVX |
| fma, x86_cpu_set, CPU_FMA |
| nofma, x86_cpu_clear, CPU_FMA |
| aes, x86_cpu_set, CPU_AES |
| noaes, x86_cpu_clear, CPU_AES |
| clmul, x86_cpu_set, CPU_CLMUL |
| noclmul, x86_cpu_clear, CPU_CLMUL |
| pclmulqdq, x86_cpu_set, CPU_CLMUL |
| nopclmulqdq, x86_cpu_clear, CPU_CLMUL |
| movbe, x86_cpu_set, CPU_MOVBE |
| nomovbe, x86_cpu_clear, CPU_MOVBE |
| xop, x86_cpu_set, CPU_XOP |
| noxop, x86_cpu_clear, CPU_XOP |
| fma4, x86_cpu_set, CPU_FMA4 |
| nofma4, x86_cpu_clear, CPU_FMA4 |
| f16c, x86_cpu_set, CPU_F16C |
| nof16c, x86_cpu_clear, CPU_F16C |
| fsgsbase, x86_cpu_set, CPU_FSGSBASE |
| nofsgsbase, x86_cpu_clear, CPU_FSGSBASE |
| rdrand, x86_cpu_set, CPU_RDRAND |
| nordrand, x86_cpu_clear, CPU_RDRAND |
| xsaveopt, x86_cpu_set, CPU_XSAVEOPT |
| noxsaveopt, x86_cpu_clear, CPU_XSAVEOPT |
| eptvpid, x86_cpu_set, CPU_EPTVPID |
| noeptvpid, x86_cpu_clear, CPU_EPTVPID |
| smx, x86_cpu_set, CPU_SMX |
| nosmx, x86_cpu_clear, CPU_SMX |
| avx2, x86_cpu_set, CPU_AVX2 |
| noavx2, x86_cpu_clear, CPU_AVX2 |
| bmi1, x86_cpu_set, CPU_BMI1 |
| nobmi1, x86_cpu_clear, CPU_BMI1 |
| bmi2, x86_cpu_set, CPU_BMI2 |
| nobmi2, x86_cpu_clear, CPU_BMI2 |
| invpcid, x86_cpu_set, CPU_INVPCID |
| noinvpcid, x86_cpu_clear, CPU_INVPCID |
| lzcnt, x86_cpu_set, CPU_LZCNT |
| nolzcnt, x86_cpu_clear, CPU_LZCNT |
| # Change NOP patterns |
| basicnop, x86_nop, X86_NOP_BASIC |
| intelnop, x86_nop, X86_NOP_INTEL |
| amdnop, x86_nop, X86_NOP_AMD |
| %% |
| |
| void |
| yasm_x86__parse_cpu(yasm_arch_x86 *arch_x86, const char *cpuid, |
| size_t cpuid_len) |
| { |
| /*@null@*/ const struct cpu_parse_data *pdata; |
| wordptr new_cpu; |
| size_t i; |
| static char lcaseid[16]; |
| |
| if (cpuid_len > 15) |
| return; |
| for (i=0; i<cpuid_len; i++) |
| lcaseid[i] = tolower(cpuid[i]); |
| lcaseid[cpuid_len] = '\0'; |
| |
| pdata = cpu_find(lcaseid, cpuid_len); |
| if (!pdata) { |
| yasm_warn_set(YASM_WARN_GENERAL, |
| N_("unrecognized CPU identifier `%s'"), cpuid); |
| return; |
| } |
| |
| new_cpu = BitVector_Clone(arch_x86->cpu_enables[arch_x86->active_cpu]); |
| pdata->handler(new_cpu, arch_x86, pdata->data); |
| |
| /* try to find an existing match in the CPU table first */ |
| for (i=0; i<arch_x86->cpu_enables_size; i++) { |
| if (BitVector_equal(arch_x86->cpu_enables[i], new_cpu)) { |
| arch_x86->active_cpu = i; |
| BitVector_Destroy(new_cpu); |
| return; |
| } |
| } |
| |
| /* not found, need to add a new entry */ |
| arch_x86->active_cpu = arch_x86->cpu_enables_size++; |
| arch_x86->cpu_enables = |
| yasm_xrealloc(arch_x86->cpu_enables, |
| arch_x86->cpu_enables_size*sizeof(wordptr)); |
| arch_x86->cpu_enables[arch_x86->active_cpu] = new_cpu; |
| } |