| 
				
			 | 
			
			
				
				@@ -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
			 | 
			
			
				
				  
			 |