|  | @@ -24,6 +24,7 @@
 | 
		
	
		
			
			| 24 | 24 |  FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
		
	
		
			
			| 25 | 25 |  
 | 
		
	
		
			
			| 26 | 26 |  #include <string.h>
 | 
		
	
		
			
			|  | 27 | +#include <errno.h>
 | 
		
	
		
			
			| 27 | 28 |  #include <ipxe/cpuid.h>
 | 
		
	
		
			
			| 28 | 29 |  
 | 
		
	
		
			
			| 29 | 30 |  /** @file
 | 
		
	
	
		
			
			|  | @@ -32,15 +33,19 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
		
	
		
			
			| 32 | 33 |   *
 | 
		
	
		
			
			| 33 | 34 |   */
 | 
		
	
		
			
			| 34 | 35 |  
 | 
		
	
		
			
			|  | 36 | +/** Colour for debug messages */
 | 
		
	
		
			
			|  | 37 | +#define colour 0x861d
 | 
		
	
		
			
			|  | 38 | +
 | 
		
	
		
			
			| 35 | 39 |  /**
 | 
		
	
		
			
			| 36 | 40 |   * Check whether or not CPUID instruction is supported
 | 
		
	
		
			
			| 37 | 41 |   *
 | 
		
	
		
			
			| 38 |  | - * @ret is_supported	CPUID instruction is supported
 | 
		
	
		
			
			|  | 42 | + * @ret rc		Return status code
 | 
		
	
		
			
			| 39 | 43 |   */
 | 
		
	
		
			
			| 40 |  | -int cpuid_is_supported ( void ) {
 | 
		
	
		
			
			|  | 44 | +static int cpuid_instruction_supported ( void ) {
 | 
		
	
		
			
			| 41 | 45 |  	unsigned long original;
 | 
		
	
		
			
			| 42 | 46 |  	unsigned long inverted;
 | 
		
	
		
			
			| 43 | 47 |  
 | 
		
	
		
			
			|  | 48 | +	/* Check for instruction existence via flag modifiability */
 | 
		
	
		
			
			| 44 | 49 |  	__asm__ ( "pushf\n\t"
 | 
		
	
		
			
			| 45 | 50 |  		  "pushf\n\t"
 | 
		
	
		
			
			| 46 | 51 |  		  "pop %0\n\t"
 | 
		
	
	
		
			
			|  | @@ -53,7 +58,54 @@ int cpuid_is_supported ( void ) {
 | 
		
	
		
			
			| 53 | 58 |  		  "popf\n\t"
 | 
		
	
		
			
			| 54 | 59 |  		  : "=&r" ( original ), "=&r" ( inverted )
 | 
		
	
		
			
			| 55 | 60 |  		  : "ir" ( CPUID_FLAG ) );
 | 
		
	
		
			
			| 56 |  | -	return ( ( original ^ inverted ) & CPUID_FLAG );
 | 
		
	
		
			
			|  | 61 | +	if ( ! ( ( original ^ inverted ) & CPUID_FLAG ) ) {
 | 
		
	
		
			
			|  | 62 | +		DBGC ( colour, "CPUID instruction is not supported\n" );
 | 
		
	
		
			
			|  | 63 | +		return -ENOTSUP;
 | 
		
	
		
			
			|  | 64 | +	}
 | 
		
	
		
			
			|  | 65 | +
 | 
		
	
		
			
			|  | 66 | +	return 0;
 | 
		
	
		
			
			|  | 67 | +}
 | 
		
	
		
			
			|  | 68 | +
 | 
		
	
		
			
			|  | 69 | +/**
 | 
		
	
		
			
			|  | 70 | + * Check whether or not CPUID function is supported
 | 
		
	
		
			
			|  | 71 | + *
 | 
		
	
		
			
			|  | 72 | + * @v function		CPUID function
 | 
		
	
		
			
			|  | 73 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 74 | + */
 | 
		
	
		
			
			|  | 75 | +int cpuid_supported ( uint32_t function ) {
 | 
		
	
		
			
			|  | 76 | +	uint32_t max_function;
 | 
		
	
		
			
			|  | 77 | +	uint32_t discard_b;
 | 
		
	
		
			
			|  | 78 | +	uint32_t discard_c;
 | 
		
	
		
			
			|  | 79 | +	uint32_t discard_d;
 | 
		
	
		
			
			|  | 80 | +	int rc;
 | 
		
	
		
			
			|  | 81 | +
 | 
		
	
		
			
			|  | 82 | +	/* Check that CPUID instruction is available */
 | 
		
	
		
			
			|  | 83 | +	if ( ( rc = cpuid_instruction_supported() ) != 0 )
 | 
		
	
		
			
			|  | 84 | +		return rc;
 | 
		
	
		
			
			|  | 85 | +
 | 
		
	
		
			
			|  | 86 | +	/* Find highest supported function number within this family */
 | 
		
	
		
			
			|  | 87 | +	cpuid ( ( function & CPUID_EXTENDED ), &max_function, &discard_b,
 | 
		
	
		
			
			|  | 88 | +		&discard_c, &discard_d );
 | 
		
	
		
			
			|  | 89 | +
 | 
		
	
		
			
			|  | 90 | +	/* Fail if maximum function number is meaningless (e.g. if we
 | 
		
	
		
			
			|  | 91 | +	 * are attempting to call an extended function on a CPU which
 | 
		
	
		
			
			|  | 92 | +	 * does not support them).
 | 
		
	
		
			
			|  | 93 | +	 */
 | 
		
	
		
			
			|  | 94 | +	if ( ( max_function & CPUID_AMD_CHECK_MASK ) !=
 | 
		
	
		
			
			|  | 95 | +	     ( function & CPUID_AMD_CHECK_MASK ) ) {
 | 
		
	
		
			
			|  | 96 | +		DBGC ( colour, "CPUID invalid maximum function %#08x\n",
 | 
		
	
		
			
			|  | 97 | +		       max_function );
 | 
		
	
		
			
			|  | 98 | +		return -EINVAL;
 | 
		
	
		
			
			|  | 99 | +	}
 | 
		
	
		
			
			|  | 100 | +
 | 
		
	
		
			
			|  | 101 | +	/* Fail if this function is not supported */
 | 
		
	
		
			
			|  | 102 | +	if ( function > max_function ) {
 | 
		
	
		
			
			|  | 103 | +		DBGC ( colour, "CPUID function %#08x not supported\n",
 | 
		
	
		
			
			|  | 104 | +		       function );
 | 
		
	
		
			
			|  | 105 | +		return -ENOTTY;
 | 
		
	
		
			
			|  | 106 | +	}
 | 
		
	
		
			
			|  | 107 | +
 | 
		
	
		
			
			|  | 108 | +	return 0;
 | 
		
	
		
			
			| 57 | 109 |  }
 | 
		
	
		
			
			| 58 | 110 |  
 | 
		
	
		
			
			| 59 | 111 |  /**
 | 
		
	
	
		
			
			|  | @@ -62,18 +114,13 @@ int cpuid_is_supported ( void ) {
 | 
		
	
		
			
			| 62 | 114 |   * @v features		x86 CPU features to fill in
 | 
		
	
		
			
			| 63 | 115 |   */
 | 
		
	
		
			
			| 64 | 116 |  static void x86_intel_features ( struct x86_features *features ) {
 | 
		
	
		
			
			| 65 |  | -	uint32_t max_level;
 | 
		
	
		
			
			| 66 | 117 |  	uint32_t discard_a;
 | 
		
	
		
			
			| 67 | 118 |  	uint32_t discard_b;
 | 
		
	
		
			
			| 68 |  | -	uint32_t discard_c;
 | 
		
	
		
			
			| 69 |  | -	uint32_t discard_d;
 | 
		
	
		
			
			|  | 119 | +	int rc;
 | 
		
	
		
			
			| 70 | 120 |  
 | 
		
	
		
			
			| 71 | 121 |  	/* Check that features are available via CPUID */
 | 
		
	
		
			
			| 72 |  | -	cpuid ( CPUID_VENDOR_ID, &max_level, &discard_b, &discard_c,
 | 
		
	
		
			
			| 73 |  | -		&discard_d );
 | 
		
	
		
			
			| 74 |  | -	if ( max_level < CPUID_FEATURES ) {
 | 
		
	
		
			
			| 75 |  | -		DBGC ( features, "CPUID has no Intel-defined features (max "
 | 
		
	
		
			
			| 76 |  | -		       "level %08x)\n", max_level );
 | 
		
	
		
			
			|  | 122 | +	if ( ( rc = cpuid_supported ( CPUID_FEATURES ) ) != 0 ) {
 | 
		
	
		
			
			|  | 123 | +		DBGC ( features, "CPUID has no Intel-defined features\n" );
 | 
		
	
		
			
			| 77 | 124 |  		return;
 | 
		
	
		
			
			| 78 | 125 |  	}
 | 
		
	
		
			
			| 79 | 126 |  
 | 
		
	
	
		
			
			|  | @@ -91,22 +138,13 @@ static void x86_intel_features ( struct x86_features *features ) {
 | 
		
	
		
			
			| 91 | 138 |   * @v features		x86 CPU features to fill in
 | 
		
	
		
			
			| 92 | 139 |   */
 | 
		
	
		
			
			| 93 | 140 |  static void x86_amd_features ( struct x86_features *features ) {
 | 
		
	
		
			
			| 94 |  | -	uint32_t max_level;
 | 
		
	
		
			
			| 95 | 141 |  	uint32_t discard_a;
 | 
		
	
		
			
			| 96 | 142 |  	uint32_t discard_b;
 | 
		
	
		
			
			| 97 |  | -	uint32_t discard_c;
 | 
		
	
		
			
			| 98 |  | -	uint32_t discard_d;
 | 
		
	
		
			
			|  | 143 | +	int rc;
 | 
		
	
		
			
			| 99 | 144 |  
 | 
		
	
		
			
			| 100 | 145 |  	/* Check that features are available via CPUID */
 | 
		
	
		
			
			| 101 |  | -	cpuid ( CPUID_AMD_MAX_FN, &max_level, &discard_b, &discard_c,
 | 
		
	
		
			
			| 102 |  | -		&discard_d );
 | 
		
	
		
			
			| 103 |  | -	if ( ( max_level & CPUID_AMD_CHECK_MASK ) != CPUID_AMD_CHECK ) {
 | 
		
	
		
			
			| 104 |  | -		DBGC ( features, "CPUID has no extended functions\n" );
 | 
		
	
		
			
			| 105 |  | -		return;
 | 
		
	
		
			
			| 106 |  | -	}
 | 
		
	
		
			
			| 107 |  | -	if ( max_level < CPUID_AMD_FEATURES ) {
 | 
		
	
		
			
			| 108 |  | -		DBGC ( features, "CPUID has no AMD-defined features (max "
 | 
		
	
		
			
			| 109 |  | -		       "level %08x)\n", max_level );
 | 
		
	
		
			
			|  | 146 | +	if ( ( rc = cpuid_supported ( CPUID_AMD_FEATURES ) ) != 0 ) {
 | 
		
	
		
			
			|  | 147 | +		DBGC ( features, "CPUID has no AMD-defined features\n" );
 | 
		
	
		
			
			| 110 | 148 |  		return;
 | 
		
	
		
			
			| 111 | 149 |  	}
 | 
		
	
		
			
			| 112 | 150 |  
 | 
		
	
	
		
			
			|  | @@ -127,12 +165,6 @@ void x86_features ( struct x86_features *features ) {
 | 
		
	
		
			
			| 127 | 165 |  	/* Clear all features */
 | 
		
	
		
			
			| 128 | 166 |  	memset ( features, 0, sizeof ( *features ) );
 | 
		
	
		
			
			| 129 | 167 |  
 | 
		
	
		
			
			| 130 |  | -	/* Check that CPUID instruction is available */
 | 
		
	
		
			
			| 131 |  | -	if ( ! cpuid_is_supported() ) {
 | 
		
	
		
			
			| 132 |  | -		DBGC ( features, "CPUID instruction is not supported\n" );
 | 
		
	
		
			
			| 133 |  | -		return;
 | 
		
	
		
			
			| 134 |  | -	}
 | 
		
	
		
			
			| 135 |  | -
 | 
		
	
		
			
			| 136 | 168 |  	/* Get Intel-defined features */
 | 
		
	
		
			
			| 137 | 169 |  	x86_intel_features ( features );
 | 
		
	
		
			
			| 138 | 170 |  
 |