These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / x86 / core / cpuid_settings.c
1 /*
2  * Copyright (C) 2013 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 <byteswap.h>
29 #include <ipxe/init.h>
30 #include <ipxe/settings.h>
31 #include <ipxe/cpuid.h>
32
33 /** @file
34  *
35  * x86 CPUID settings
36  *
37  * CPUID settings are numerically encoded as:
38  *
39  *  Bit  31     Extended function
40  *  Bits 30-28  Unused
41  *  Bits 27-24  Number of consecutive functions to call, minus one
42  *  Bit  23     Return result as little-endian (used for strings)
43  *  Bits 22-18  Unused
44  *  Bits 17-16  Number of registers in register array, minus one
45  *  Bits 15-8   Array of register indices.  First entry in array is in
46  *              bits 9-8.  Indices are 0-%eax, 1-%ebx, 2-%ecx, 3-%edx.
47  *  Bits 7-0    Starting function number (excluding "extended" bit)
48  *
49  * This encoding scheme is designed to allow the common case of
50  * extracting a single register from a single function to be encoded
51  * using "cpuid/<register>.<function>", e.g. "cpuid/2.0x80000001" to
52  * retrieve the value of %ecx from calling CPUID with %eax=0x80000001.
53  */
54
55 /** CPUID setting tag register indices */
56 enum cpuid_registers {
57         CPUID_EAX = 0,
58         CPUID_EBX = 1,
59         CPUID_ECX = 2,
60         CPUID_EDX = 3,
61 };
62
63 /**
64  * Construct CPUID setting tag
65  *
66  * @v function          Starting function number
67  * @v num_functions     Number of consecutive functions
68  * @v little_endian     Return result as little-endian
69  * @v num_registers     Number of registers in register array
70  * @v register1         First register in register array (or zero, if empty)
71  * @v register2         Second register in register array (or zero, if empty)
72  * @v register3         Third register in register array (or zero, if empty)
73  * @v register4         Fourth register in register array (or zero, if empty)
74  * @ret tag             Setting tag
75  */
76 #define CPUID_TAG( function, num_functions, little_endian, num_registers, \
77                    register1, register2, register3, register4 )           \
78         ( (function) | ( ( (num_functions) - 1 ) << 24 ) |                \
79           ( (little_endian) << 23 ) | ( ( (num_registers) - 1) << 16 ) |  \
80           ( (register1) << 8 ) | ( (register2) << 10 ) |                  \
81           ( (register3) << 12 ) | ( (register4) << 14 ) )
82
83 /**
84  * Extract endianness from CPUID setting tag
85  *
86  * @v tag               Setting tag
87  * @ret little_endian   Result should be returned as little-endian
88  */
89 #define CPUID_LITTLE_ENDIAN( tag ) ( (tag) & 0x00800000UL )
90
91 /**
92  * Extract starting function number from CPUID setting tag
93  *
94  * @v tag               Setting tag
95  * @ret function        Starting function number
96  */
97 #define CPUID_FUNCTION( tag ) ( (tag) & 0x800000ffUL )
98
99 /**
100  * Extract number of consecutive functions from CPUID setting tag
101  *
102  * @v tag               Setting tag
103  * @ret num_functions   Number of consecutive functions
104  */
105 #define CPUID_NUM_FUNCTIONS( tag ) ( ( ( (tag) >> 24 ) & 0xf ) + 1 )
106
107 /**
108  * Extract register array from CPUID setting tag
109  *
110  * @v tag               Setting tag
111  * @ret registers       Register array
112  */
113 #define CPUID_REGISTERS( tag ) ( ( (tag) >> 8 ) & 0xff )
114
115 /**
116  * Extract number of registers from CPUID setting tag
117  *
118  * @v tag               Setting tag
119  * @ret num_registers   Number of registers within register array
120  */
121 #define CPUID_NUM_REGISTERS( tag ) ( ( ( (tag) >> 16 ) & 0x3 ) + 1 )
122
123 /** CPUID settings scope */
124 static const struct settings_scope cpuid_settings_scope;
125
126 /**
127  * Check applicability of CPUID setting
128  *
129  * @v settings          Settings block
130  * @v setting           Setting
131  * @ret applies         Setting applies within this settings block
132  */
133 static int cpuid_settings_applies ( struct settings *settings __unused,
134                                     const struct setting *setting ) {
135
136         return ( setting->scope == &cpuid_settings_scope );
137 }
138
139 /**
140  * Fetch value of CPUID setting
141  *
142  * @v settings          Settings block
143  * @v setting           Setting to fetch
144  * @v data              Buffer to fill with setting data
145  * @v len               Length of buffer
146  * @ret len             Length of setting data, or negative error
147  */
148 static int cpuid_settings_fetch ( struct settings *settings,
149                                   struct setting *setting,
150                                   void *data, size_t len ) {
151         uint32_t function;
152         uint32_t max_function;
153         uint32_t num_functions;
154         uint32_t registers;
155         uint32_t num_registers;
156         uint32_t buf[4];
157         uint32_t output;
158         uint32_t discard_b;
159         uint32_t discard_c;
160         uint32_t discard_d;
161         size_t frag_len;
162         size_t result_len = 0;
163
164         /* Fail unless CPUID is supported */
165         if ( ! cpuid_is_supported() ) {
166                 DBGC ( settings, "CPUID not supported\n" );
167                 return -ENOTSUP;
168         }
169
170         /* Find highest supported function number within this set */
171         function = CPUID_FUNCTION ( setting->tag );
172         cpuid ( function & CPUID_EXTENDED, &max_function, &discard_b,
173                 &discard_c, &discard_d );
174
175         /* Fail if maximum function number is meaningless (e.g. if we
176          * are attempting to call an extended function on a CPU which
177          * does not support them).
178          */
179         if ( ( max_function & CPUID_AMD_CHECK_MASK ) !=
180              ( function & CPUID_AMD_CHECK_MASK ) ) {
181                 DBGC ( settings, "CPUID invalid maximum function\n" );
182                 return -ENOTSUP;
183         }
184
185         /* Call each function in turn */
186         num_functions = CPUID_NUM_FUNCTIONS ( setting->tag );
187         for ( ; num_functions-- ; function++ ) {
188
189                 /* Fail if this function is not supported */
190                 if ( function > max_function ) {
191                         DBGC ( settings, "CPUID function %#08x not supported\n",
192                                function );
193                         return -ENOTSUP;
194                 }
195
196                 /* Issue CPUID */
197                 cpuid ( function, &buf[CPUID_EAX], &buf[CPUID_EBX],
198                         &buf[CPUID_ECX], &buf[CPUID_EDX] );
199                 DBGC ( settings, "CPUID %#08x => %#08x:%#08x:%#08x:%#08x\n",
200                        function, buf[0], buf[1], buf[2], buf[3] );
201
202                 /* Copy results to buffer */
203                 registers = CPUID_REGISTERS ( setting->tag );
204                 num_registers = CPUID_NUM_REGISTERS ( setting->tag );
205                 for ( ; num_registers-- ; registers >>= 2 ) {
206                         output = buf[ registers & 0x3 ];
207                         if ( ! CPUID_LITTLE_ENDIAN ( setting->tag ) )
208                                 output = cpu_to_be32 ( output );
209                         frag_len = sizeof ( output );
210                         if ( frag_len > len )
211                                 frag_len = len;
212                         memcpy ( data, &output, frag_len );
213                         data += frag_len;
214                         len -= frag_len;
215                         result_len += sizeof ( output );
216                 }
217         }
218
219         /* Set type if not already specified */
220         if ( ! setting->type )
221                 setting->type = &setting_type_hexraw;
222
223         return result_len;
224 }
225
226 /** CPUID settings operations */
227 static struct settings_operations cpuid_settings_operations = {
228         .applies = cpuid_settings_applies,
229         .fetch = cpuid_settings_fetch,
230 };
231
232 /** CPUID settings */
233 static struct settings cpuid_settings = {
234         .refcnt = NULL,
235         .siblings = LIST_HEAD_INIT ( cpuid_settings.siblings ),
236         .children = LIST_HEAD_INIT ( cpuid_settings.children ),
237         .op = &cpuid_settings_operations,
238         .default_scope = &cpuid_settings_scope,
239 };
240
241 /** Initialise CPUID settings */
242 static void cpuid_settings_init ( void ) {
243         int rc;
244
245         if ( ( rc = register_settings ( &cpuid_settings, NULL,
246                                         "cpuid" ) ) != 0 ) {
247                 DBG ( "CPUID could not register settings: %s\n",
248                       strerror ( rc ) );
249                 return;
250         }
251 }
252
253 /** CPUID settings initialiser */
254 struct init_fn cpuid_settings_init_fn __init_fn ( INIT_NORMAL ) = {
255         .initialise = cpuid_settings_init,
256 };
257
258 /** CPU vendor setting */
259 const struct setting cpuvendor_setting __setting ( SETTING_HOST_EXTRA,
260                                                    cpuvendor ) = {
261         .name = "cpuvendor",
262         .description = "CPU vendor",
263         .tag = CPUID_TAG ( CPUID_VENDOR_ID, 1, 1, 3,
264                            CPUID_EBX, CPUID_EDX, CPUID_ECX, 0 ),
265         .type = &setting_type_string,
266         .scope = &cpuid_settings_scope,
267 };
268
269 /** CPU model setting */
270 const struct setting cpumodel_setting __setting ( SETTING_HOST_EXTRA,
271                                                   cpumodel ) = {
272         .name = "cpumodel",
273         .description = "CPU model",
274         .tag = CPUID_TAG ( CPUID_MODEL, 3, 1, 4,
275                            CPUID_EAX, CPUID_EBX, CPUID_ECX, CPUID_EDX ),
276         .type = &setting_type_string,
277         .scope = &cpuid_settings_scope,
278 };