github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-cpuid-x86.c (about)

     1  /*
     2   * jit-cpuid-x86.c - Wrapper for the CPUID instruction.
     3   *
     4   * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
     5   *
     6   * This file is part of the libjit library.
     7   *
     8   * The libjit library is free software: you can redistribute it and/or
     9   * modify it under the terms of the GNU Lesser General Public License
    10   * as published by the Free Software Foundation, either version 2.1 of
    11   * the License, or (at your option) any later version.
    12   *
    13   * The libjit library is distributed in the hope that it will be useful,
    14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    16   * Lesser General Public License for more details.
    17   *
    18   * You should have received a copy of the GNU Lesser General Public
    19   * License along with the libjit library.  If not, see
    20   * <http://www.gnu.org/licenses/>.
    21   */
    22  
    23  #include "jit-cpuid-x86.h"
    24  
    25  #if defined(__i386) || defined(__i386__) || defined(_M_IX86)
    26  
    27  /*
    28   * Determine if the "cpuid" instruction is present by twiddling
    29   * bit 21 of the EFLAGS register.
    30   */
    31  static int cpuid_present(void)
    32  {
    33  #if defined(__GNUC__)
    34  	int result;
    35  	__asm__ __volatile__ (
    36  		"\tpushfl\n"
    37  		"\tpopl %%eax\n"
    38  		"\tmovl %%eax, %%ecx\n"
    39  		"\tandl $0x200000, %%ecx\n"
    40  		"\txorl $0x200000, %%eax\n"
    41  		"\tpushl %%eax\n"
    42  		"\tpopfl\n"
    43  		"\tpushfl\n"
    44  		"\tandl $0x200000, %%eax\n"
    45  		"\txorl %%ecx, %%eax\n"
    46  		"\tmovl %%eax, %0\n"
    47  		: "=m" (result) : : "eax", "ecx"
    48  	);
    49  	return (result != 0);
    50  #else
    51  	return 0;
    52  #endif
    53  }
    54  
    55  /*
    56   * Issue a "cpuid" query and get the result.
    57   */
    58  static void cpuid_query(unsigned int index, jit_cpuid_x86_t *info)
    59  {
    60  #if defined(__GNUC__)
    61  	__asm__ __volatile__ (
    62  		"\tmovl %0, %%eax\n"
    63  		"\tpushl %%ebx\n"
    64  		"\txorl %%ebx, %%ebx\n"
    65  		"\txorl %%ecx, %%ecx\n"
    66  		"\txorl %%edx, %%edx\n"
    67  		"\t.byte 0x0F\n"			/* cpuid, safe against old assemblers */
    68  		"\t.byte 0xA2\n"
    69  		"\tmovl %1, %%esi\n"
    70  		"\tmovl %%eax, (%%esi)\n"
    71  		"\tmovl %%ebx, 4(%%esi)\n"
    72  		"\tmovl %%ecx, 8(%%esi)\n"
    73  		"\tmovl %%edx, 12(%%esi)\n"
    74  		"\tpopl %%ebx\n"
    75  		: : "m"(index), "m"(info) : "eax", "ecx", "edx", "esi"
    76  	);
    77  #endif
    78  }
    79  
    80  int _jit_cpuid_x86_get(unsigned int index, jit_cpuid_x86_t *info)
    81  {
    82  	/* Determine if this cpu has the "cpuid" instruction */
    83  	if(!cpuid_present())
    84  	{
    85  		return 0;
    86  	}
    87  
    88  	/* Validate the index */
    89  	if((index & 0x80000000) == 0)
    90  	{
    91  		cpuid_query(0, info);
    92  	}
    93  	else
    94  	{
    95  		cpuid_query(0x80000000, info);
    96  	}
    97  	if(index > info->eax)
    98  	{
    99  		return 0;
   100  	}
   101  
   102  	/* Execute the actual requested query */
   103  	cpuid_query(index, info);
   104  	return 1;
   105  }
   106  
   107  int _jit_cpuid_x86_has_feature(unsigned int feature)
   108  {
   109  	jit_cpuid_x86_t info;
   110  	if(!_jit_cpuid_x86_get(JIT_X86CPUID_FEATURES, &info))
   111  	{
   112  		return 0;
   113  	}
   114  	return ((info.edx & feature) != 0);
   115  }
   116  
   117  unsigned int _jit_cpuid_x86_line_size(void)
   118  {
   119  	jit_cpuid_x86_t info;
   120  	if(!_jit_cpuid_x86_get(JIT_X86CPUID_FEATURES, &info))
   121  	{
   122  		return 0;
   123  	}
   124  	if((info.edx & JIT_X86FEATURE_CLFSH) == 0)
   125  	{
   126  		return 0;
   127  	}
   128  	return ((info.ebx & 0x0000FF00) >> 5);
   129  }
   130  
   131  #endif /* i386 */