1 /*
2 * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 #include <string.h>
27 #include <errno.h>
28 #include <ipxe/cpuid.h>
29
30 /** @file
31 *
32 * x86 CPU feature detection
33 *
34 */
35
36 /** Colour for debug messages */
37 #define colour 0x861d
38
39 /**
40 * Check whether or not CPUID instruction is supported
41 *
42 * @ret rc Return status code
43 */
cpuid_instruction_supported(void)44 static int cpuid_instruction_supported ( void ) {
45 unsigned long original;
46 unsigned long inverted;
47
48 /* Check for instruction existence via flag modifiability */
49 __asm__ ( "pushf\n\t"
50 "pushf\n\t"
51 "pop %0\n\t"
52 "mov %0,%1\n\t"
53 "xor %2,%1\n\t"
54 "push %1\n\t"
55 "popf\n\t"
56 "pushf\n\t"
57 "pop %1\n\t"
58 "popf\n\t"
59 : "=&r" ( original ), "=&r" ( inverted )
60 : "ir" ( 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 */
cpuid_supported(uint32_t function)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 ), 0, &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;
109 }
110
111 /**
112 * Get Intel-defined x86 CPU features
113 *
114 * @v features x86 CPU features to fill in
115 */
x86_intel_features(struct x86_features * features)116 static void x86_intel_features ( struct x86_features *features ) {
117 uint32_t discard_a;
118 uint32_t discard_b;
119 int rc;
120
121 /* Check that features are available via CPUID */
122 if ( ( rc = cpuid_supported ( CPUID_FEATURES ) ) != 0 ) {
123 DBGC ( features, "CPUID has no Intel-defined features\n" );
124 return;
125 }
126
127 /* Get features */
128 cpuid ( CPUID_FEATURES, 0, &discard_a, &discard_b,
129 &features->intel.ecx, &features->intel.edx );
130 DBGC ( features, "CPUID Intel features: %%ecx=%08x, %%edx=%08x\n",
131 features->intel.ecx, features->intel.edx );
132
133 }
134
135 /**
136 * Get AMD-defined x86 CPU features
137 *
138 * @v features x86 CPU features to fill in
139 */
x86_amd_features(struct x86_features * features)140 static void x86_amd_features ( struct x86_features *features ) {
141 uint32_t discard_a;
142 uint32_t discard_b;
143 int rc;
144
145 /* Check that features are available via CPUID */
146 if ( ( rc = cpuid_supported ( CPUID_AMD_FEATURES ) ) != 0 ) {
147 DBGC ( features, "CPUID has no AMD-defined features\n" );
148 return;
149 }
150
151 /* Get features */
152 cpuid ( CPUID_AMD_FEATURES, 0, &discard_a, &discard_b,
153 &features->amd.ecx, &features->amd.edx );
154 DBGC ( features, "CPUID AMD features: %%ecx=%08x, %%edx=%08x\n",
155 features->amd.ecx, features->amd.edx );
156 }
157
158 /**
159 * Get x86 CPU features
160 *
161 * @v features x86 CPU features to fill in
162 */
x86_features(struct x86_features * features)163 void x86_features ( struct x86_features *features ) {
164
165 /* Clear all features */
166 memset ( features, 0, sizeof ( *features ) );
167
168 /* Get Intel-defined features */
169 x86_intel_features ( features );
170
171 /* Get AMD-defined features */
172 x86_amd_features ( features );
173 }
174