From d37e025b81cb6fd0e7833b927ed138b42a628bc8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 25 Jan 2017 20:57:18 +0000 Subject: [PATCH] [cpuid] Provide cpuid_supported() to test for supported functions Signed-off-by: Michael Brown --- src/arch/x86/core/cpuid.c | 90 +++++++++++++++++++---------- src/arch/x86/core/cpuid_settings.c | 35 ++--------- src/arch/x86/include/bits/errfile.h | 1 + src/arch/x86/include/ipxe/cpuid.h | 8 +-- 4 files changed, 72 insertions(+), 62 deletions(-) diff --git a/src/arch/x86/core/cpuid.c b/src/arch/x86/core/cpuid.c index bc5a6c68..864c1035 100644 --- a/src/arch/x86/core/cpuid.c +++ b/src/arch/x86/core/cpuid.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include /** @file @@ -32,15 +33,19 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +/** Colour for debug messages */ +#define colour 0x861d + /** * Check whether or not CPUID instruction is supported * - * @ret is_supported CPUID instruction is supported + * @ret rc Return status code */ -int cpuid_is_supported ( void ) { +static int cpuid_instruction_supported ( void ) { unsigned long original; unsigned long inverted; + /* Check for instruction existence via flag modifiability */ __asm__ ( "pushf\n\t" "pushf\n\t" "pop %0\n\t" @@ -53,7 +58,54 @@ int cpuid_is_supported ( void ) { "popf\n\t" : "=&r" ( original ), "=&r" ( inverted ) : "ir" ( CPUID_FLAG ) ); - return ( ( original ^ inverted ) & CPUID_FLAG ); + if ( ! ( ( original ^ inverted ) & CPUID_FLAG ) ) { + DBGC ( colour, "CPUID instruction is not supported\n" ); + return -ENOTSUP; + } + + return 0; +} + +/** + * Check whether or not CPUID function is supported + * + * @v function CPUID function + * @ret rc Return status code + */ +int cpuid_supported ( uint32_t function ) { + uint32_t max_function; + uint32_t discard_b; + uint32_t discard_c; + uint32_t discard_d; + int rc; + + /* Check that CPUID instruction is available */ + if ( ( rc = cpuid_instruction_supported() ) != 0 ) + return rc; + + /* Find highest supported function number within this family */ + cpuid ( ( function & CPUID_EXTENDED ), &max_function, &discard_b, + &discard_c, &discard_d ); + + /* Fail if maximum function number is meaningless (e.g. if we + * are attempting to call an extended function on a CPU which + * does not support them). + */ + if ( ( max_function & CPUID_AMD_CHECK_MASK ) != + ( function & CPUID_AMD_CHECK_MASK ) ) { + DBGC ( colour, "CPUID invalid maximum function %#08x\n", + max_function ); + return -EINVAL; + } + + /* Fail if this function is not supported */ + if ( function > max_function ) { + DBGC ( colour, "CPUID function %#08x not supported\n", + function ); + return -ENOTTY; + } + + return 0; } /** @@ -62,18 +114,13 @@ int cpuid_is_supported ( void ) { * @v features x86 CPU features to fill in */ static void x86_intel_features ( struct x86_features *features ) { - uint32_t max_level; uint32_t discard_a; uint32_t discard_b; - uint32_t discard_c; - uint32_t discard_d; + int rc; /* Check that features are available via CPUID */ - cpuid ( CPUID_VENDOR_ID, &max_level, &discard_b, &discard_c, - &discard_d ); - if ( max_level < CPUID_FEATURES ) { - DBGC ( features, "CPUID has no Intel-defined features (max " - "level %08x)\n", max_level ); + if ( ( rc = cpuid_supported ( CPUID_FEATURES ) ) != 0 ) { + DBGC ( features, "CPUID has no Intel-defined features\n" ); return; } @@ -91,22 +138,13 @@ static void x86_intel_features ( struct x86_features *features ) { * @v features x86 CPU features to fill in */ static void x86_amd_features ( struct x86_features *features ) { - uint32_t max_level; uint32_t discard_a; uint32_t discard_b; - uint32_t discard_c; - uint32_t discard_d; + int rc; /* Check that features are available via CPUID */ - cpuid ( CPUID_AMD_MAX_FN, &max_level, &discard_b, &discard_c, - &discard_d ); - if ( ( max_level & CPUID_AMD_CHECK_MASK ) != CPUID_AMD_CHECK ) { - DBGC ( features, "CPUID has no extended functions\n" ); - return; - } - if ( max_level < CPUID_AMD_FEATURES ) { - DBGC ( features, "CPUID has no AMD-defined features (max " - "level %08x)\n", max_level ); + if ( ( rc = cpuid_supported ( CPUID_AMD_FEATURES ) ) != 0 ) { + DBGC ( features, "CPUID has no AMD-defined features\n" ); return; } @@ -127,12 +165,6 @@ void x86_features ( struct x86_features *features ) { /* Clear all features */ memset ( features, 0, sizeof ( *features ) ); - /* Check that CPUID instruction is available */ - if ( ! cpuid_is_supported() ) { - DBGC ( features, "CPUID instruction is not supported\n" ); - return; - } - /* Get Intel-defined features */ x86_intel_features ( features ); diff --git a/src/arch/x86/core/cpuid_settings.c b/src/arch/x86/core/cpuid_settings.c index 08bd3918..306dbefb 100644 --- a/src/arch/x86/core/cpuid_settings.c +++ b/src/arch/x86/core/cpuid_settings.c @@ -149,48 +149,25 @@ static int cpuid_settings_fetch ( struct settings *settings, struct setting *setting, void *data, size_t len ) { uint32_t function; - uint32_t max_function; uint32_t num_functions; uint32_t registers; uint32_t num_registers; uint32_t buf[4]; uint32_t output; - uint32_t discard_b; - uint32_t discard_c; - uint32_t discard_d; size_t frag_len; size_t result_len = 0; - - /* Fail unless CPUID is supported */ - if ( ! cpuid_is_supported() ) { - DBGC ( settings, "CPUID not supported\n" ); - return -ENOTSUP; - } - - /* Find highest supported function number within this set */ - function = CPUID_FUNCTION ( setting->tag ); - cpuid ( function & CPUID_EXTENDED, &max_function, &discard_b, - &discard_c, &discard_d ); - - /* Fail if maximum function number is meaningless (e.g. if we - * are attempting to call an extended function on a CPU which - * does not support them). - */ - if ( ( max_function & CPUID_AMD_CHECK_MASK ) != - ( function & CPUID_AMD_CHECK_MASK ) ) { - DBGC ( settings, "CPUID invalid maximum function\n" ); - return -ENOTSUP; - } + int rc; /* Call each function in turn */ + function = CPUID_FUNCTION ( setting->tag ); num_functions = CPUID_NUM_FUNCTIONS ( setting->tag ); for ( ; num_functions-- ; function++ ) { /* Fail if this function is not supported */ - if ( function > max_function ) { - DBGC ( settings, "CPUID function %#08x not supported\n", - function ); - return -ENOTSUP; + if ( ( rc = cpuid_supported ( function ) ) != 0 ) { + DBGC ( settings, "CPUID function %#08x not supported: " + "%s\n", function, strerror ( rc ) ); + return rc; } /* Issue CPUID */ diff --git a/src/arch/x86/include/bits/errfile.h b/src/arch/x86/include/bits/errfile.h index f4816e62..105cdf5d 100644 --- a/src/arch/x86/include/bits/errfile.h +++ b/src/arch/x86/include/bits/errfile.h @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_gdbmach ( ERRFILE_ARCH | ERRFILE_CORE | 0x000e0000 ) #define ERRFILE_rtc_entropy ( ERRFILE_ARCH | ERRFILE_CORE | 0x000f0000 ) #define ERRFILE_acpipwr ( ERRFILE_ARCH | ERRFILE_CORE | 0x00100000 ) +#define ERRFILE_cpuid ( ERRFILE_ARCH | ERRFILE_CORE | 0x00110000 ) #define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 ) diff --git a/src/arch/x86/include/ipxe/cpuid.h b/src/arch/x86/include/ipxe/cpuid.h index da85d0b8..2e2cc7c1 100644 --- a/src/arch/x86/include/ipxe/cpuid.h +++ b/src/arch/x86/include/ipxe/cpuid.h @@ -60,22 +60,22 @@ struct x86_features { /** * Issue CPUID instruction * - * @v operation CPUID operation + * @v function CPUID function * @v eax Output via %eax * @v ebx Output via %ebx * @v ecx Output via %ecx * @v edx Output via %edx */ static inline __attribute__ (( always_inline )) void -cpuid ( uint32_t operation, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, +cpuid ( uint32_t function, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx ) { __asm__ ( "cpuid" : "=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx ) - : "0" ( operation ) ); + : "0" ( function ) ); } -extern int cpuid_is_supported ( void ); +extern int cpuid_supported ( uint32_t function ); extern void x86_features ( struct x86_features *features ); #endif /* _IPXE_CPUID_H */