iPXE
cpuid_settings.c
Go to the documentation of this file.
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 FILE_SECBOOT ( PERMITTED );
26 
27 #include <string.h>
28 #include <errno.h>
29 #include <byteswap.h>
30 #include <ipxe/init.h>
31 #include <ipxe/settings.h>
32 #include <ipxe/cpuid.h>
33 
34 /** @file
35  *
36  * x86 CPUID settings
37  *
38  * CPUID settings are numerically encoded as:
39  *
40  * Bit 31 Extended function
41  * Bits 30-24 (bit 22 = 1) Subfunction number
42  * Bit 30 (bit 22 = 0) Hypervisor function
43  * Bits 29-24 (bit 22 = 0) Number of consecutive functions to call, minus one
44  * Bit 23 Return result as little-endian (used for strings)
45  * Bit 22 Interpret bits 30-24 as a subfunction number
46  * Bits 21-18 Unused
47  * Bits 17-16 Number of registers in register array, minus one
48  * Bits 15-8 Array of register indices. First entry in array is in
49  * bits 9-8. Indices are 0-%eax, 1-%ebx, 2-%ecx, 3-%edx.
50  * Bits 7-0 Starting function number (excluding "extended" bit)
51  *
52  * This encoding scheme is designed to allow the common case of
53  * extracting a single register from a single function to be encoded
54  * using "cpuid/<register>.<function>", e.g. "cpuid/2.0x80000001" to
55  * retrieve the value of %ecx from calling CPUID with %eax=0x80000001.
56  *
57  * A subfunction (i.e. an input value for %ecx) may be specified using
58  * "cpuid/<subfunction>.0x40.<register>.<function>". This slightly
59  * cumbersome syntax is required in order to maintain backwards
60  * compatibility with older scripts.
61  */
62 
63 /** CPUID setting tag register indices */
65  CPUID_EAX = 0,
66  CPUID_EBX = 1,
67  CPUID_ECX = 2,
68  CPUID_EDX = 3,
69 };
70 
71 /** CPUID setting tag flags */
73  CPUID_LITTLE_ENDIAN = 0x00800000UL,
74  CPUID_USE_SUBFUNCTION = 0x00400000UL,
75 };
76 
77 /**
78  * Construct CPUID setting tag
79  *
80  * @v function Starting function number
81  * @v subfunction Subfunction, or number of consecutive functions minus 1
82  * @v flags Flags
83  * @v num_registers Number of registers in register array
84  * @v register1 First register in register array (or zero, if empty)
85  * @v register2 Second register in register array (or zero, if empty)
86  * @v register3 Third register in register array (or zero, if empty)
87  * @v register4 Fourth register in register array (or zero, if empty)
88  * @ret tag Setting tag
89  */
90 #define CPUID_TAG( function, subfunction, flags, num_registers, \
91  register1, register2, register3, register4 ) \
92  ( (function) | ( (subfunction) << 24 ) | (flags) | \
93  ( ( (num_registers) - 1 ) << 16 ) | \
94  ( (register1) << 8 ) | ( (register2) << 10 ) | \
95  ( (register3) << 12 ) | ( (register4) << 14 ) )
96 
97 /**
98  * Extract starting function number from CPUID setting tag
99  *
100  * @v tag Setting tag
101  * @ret function Starting function number
102  */
103 #define CPUID_FUNCTION( tag ) ( (tag) & 0xc00000ffUL )
104 
105 /**
106  * Extract subfunction number from CPUID setting tag
107  *
108  * @v tag Setting tag
109  * @ret subfunction Subfunction number
110  */
111 #define CPUID_SUBFUNCTION( tag ) ( ( (tag) >> 24 ) & 0x7f )
112 
113 /**
114  * Extract number of consecutive functions from CPUID setting tag
115  *
116  * @v tag Setting tag
117  * @ret num_functions Number of consecutive functions
118  */
119 #define CPUID_NUM_FUNCTIONS( tag ) ( ( ( (tag) >> 24 ) & 0x3f ) + 1 )
120 
121 /**
122  * Extract register array from CPUID setting tag
123  *
124  * @v tag Setting tag
125  * @ret registers Register array
126  */
127 #define CPUID_REGISTERS( tag ) ( ( (tag) >> 8 ) & 0xff )
128 
129 /**
130  * Extract number of registers from CPUID setting tag
131  *
132  * @v tag Setting tag
133  * @ret num_registers Number of registers within register array
134  */
135 #define CPUID_NUM_REGISTERS( tag ) ( ( ( (tag) >> 16 ) & 0x3 ) + 1 )
136 
137 /** CPUID settings scope */
139 
140 /**
141  * Check applicability of CPUID setting
142  *
143  * @v settings Settings block
144  * @v setting Setting
145  * @ret applies Setting applies within this settings block
146  */
148  const struct setting *setting ) {
149 
150  return ( setting->scope == &cpuid_settings_scope );
151 }
152 
153 /**
154  * Fetch value of CPUID setting
155  *
156  * @v settings Settings block
157  * @v setting Setting to fetch
158  * @v data Buffer to fill with setting data
159  * @v len Length of buffer
160  * @ret len Length of setting data, or negative error
161  */
163  struct setting *setting,
164  void *data, size_t len ) {
165  uint32_t function;
167  uint32_t num_functions;
168  uint32_t registers;
169  uint32_t num_registers;
170  uint32_t buf[4];
172  size_t frag_len;
173  size_t result_len = 0;
174  int rc;
175 
176  /* Call each function in turn */
177  function = CPUID_FUNCTION ( setting->tag );
178  if ( setting->tag & CPUID_USE_SUBFUNCTION ) {
179  function &= ~CPUID_HYPERVISOR;
181  num_functions = 1;
182  } else {
183  subfunction = 0;
184  num_functions = CPUID_NUM_FUNCTIONS ( setting->tag );
185  }
186  for ( ; num_functions-- ; function++ ) {
187 
188  /* Fail if this function is not supported */
189  if ( ( rc = cpuid_supported ( function ) ) != 0 ) {
190  DBGC ( settings, "CPUID function %#08x not supported: "
191  "%s\n", function, strerror ( rc ) );
192  return rc;
193  }
194 
195  /* Issue CPUID */
196  cpuid ( function, subfunction, &buf[CPUID_EAX],
197  &buf[CPUID_EBX], &buf[CPUID_ECX], &buf[CPUID_EDX] );
198  DBGC ( settings, "CPUID %#08x:%x => %#08x:%#08x:%#08x:%#08x\n",
199  function, subfunction, buf[0], buf[1], buf[2], buf[3] );
200 
201  /* Copy results to buffer */
202  registers = CPUID_REGISTERS ( setting->tag );
203  num_registers = CPUID_NUM_REGISTERS ( setting->tag );
204  for ( ; num_registers-- ; registers >>= 2 ) {
205  output = buf[ registers & 0x3 ];
206  if ( ! ( setting->tag & CPUID_LITTLE_ENDIAN ) )
207  output = cpu_to_be32 ( output );
208  frag_len = sizeof ( output );
209  if ( frag_len > len )
210  frag_len = len;
211  memcpy ( data, &output, frag_len );
212  data += frag_len;
213  len -= frag_len;
214  result_len += sizeof ( output );
215  }
216  }
217 
218  /* Set type if not already specified */
219  if ( ! setting->type )
220  setting->type = &setting_type_hexraw;
221 
222  return result_len;
223 }
224 
225 /** CPUID settings operations */
228  .fetch = cpuid_settings_fetch,
229 };
230 
231 /** CPUID settings */
232 static struct settings cpuid_settings = {
233  .refcnt = NULL,
234  .siblings = LIST_HEAD_INIT ( cpuid_settings.siblings ),
235  .children = LIST_HEAD_INIT ( cpuid_settings.children ),
237  .default_scope = &cpuid_settings_scope,
238 };
239 
240 /** Initialise CPUID settings */
241 static void cpuid_settings_init ( void ) {
242  int rc;
243 
245  "cpuid" ) ) != 0 ) {
246  DBG ( "CPUID could not register settings: %s\n",
247  strerror ( rc ) );
248  return;
249  }
250 }
251 
252 /** CPUID settings initialiser */
253 struct init_fn cpuid_settings_init_fn __init_fn ( INIT_NORMAL ) = {
254  .name = "cpuid",
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",
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, 2, CPUID_LITTLE_ENDIAN, 4,
276  .type = &setting_type_string,
277  .scope = &cpuid_settings_scope,
278 };
int cpuid_supported(uint32_t function)
Check whether or not CPUID function is supported.
Definition: cpuid.c:76
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define CPUID_HYPERVISOR
CPUID hypervisor function.
Definition: cpuid.h:38
static int cpuid_settings_applies(struct settings *settings __unused, const struct setting *setting)
Check applicability of CPUID setting.
static int cpuid_settings_fetch(struct settings *settings, struct setting *setting, void *data, size_t len)
Fetch value of CPUID setting.
Error codes.
#define CPUID_FUNCTION(tag)
Extract starting function number from CPUID setting tag.
#define CPUID_SUBFUNCTION(tag)
Extract subfunction number from CPUID setting tag.
FILE_SECBOOT(PERMITTED)
#define CPUID_VENDOR_ID
Get vendor ID and largest standard function.
Definition: cpuid.h:41
#define DBGC(...)
Definition: compiler.h:505
#define SETTING_HOST_EXTRA
Host identity additional settings.
Definition: settings.h:77
#define CPUID_MODEL
Get CPU model.
Definition: cpuid.h:71
const char * name
Name.
Definition: settings.h:29
static uint32_t subfunction
Definition: cpuid.h:90
uint64_t tag
Setting tag, if applicable.
Definition: settings.h:44
#define INIT_NORMAL
Normal initialisation.
Definition: init.h:32
void * memcpy(void *dest, const void *src, size_t len) __nonnull
An initialisation function.
Definition: init.h:15
static const struct settings_scope cpuid_settings_scope
CPUID settings scope.
#define CPUID_REGISTERS(tag)
Extract register array from CPUID setting tag.
static struct settings_operations cpuid_settings_operations
CPUID settings operations.
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
#define CPUID_NUM_REGISTERS(tag)
Extract number of registers from CPUID setting tag.
ring len
Length.
Definition: dwmac.h:231
const char * name
Definition: init.h:16
#define CPUID_TAG(function, subfunction, flags, num_registers, register1, register2, register3, register4)
Construct CPUID setting tag.
const struct setting_type * type
Setting type.
Definition: settings.h:37
Configuration settings.
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
x86 CPU feature detection
Settings block operations.
Definition: settings.h:86
A settings block.
Definition: settings.h:133
A setting scope.
Definition: settings.h:177
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
struct init_fn cpuid_settings_init_fn __init_fn(INIT_NORMAL)
CPUID settings initialiser.
unsigned int uint32_t
Definition: stdint.h:12
struct list_head siblings
Sibling settings blocks.
Definition: settings.h:141
A setting.
Definition: settings.h:24
#define cpu_to_be32(value)
Definition: byteswap.h:111
const struct setting cpuvendor_setting __setting(SETTING_HOST_EXTRA, cpuvendor)
CPU vendor setting.
static void cpuid_settings_init(void)
Initialise CPUID settings.
uint8_t data[48]
Additional event data.
Definition: ena.h:22
int(* applies)(struct settings *settings, const struct setting *setting)
Check applicability of setting.
Definition: settings.h:99
struct list_head children
Child settings blocks.
Definition: settings.h:143
int register_settings(struct settings *settings, struct settings *parent, const char *name)
Register settings block.
Definition: settings.c:476
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define LIST_HEAD_INIT(list)
Initialise a static list head.
Definition: list.h:31
const struct settings_scope * scope
Setting scope (or NULL)
Definition: settings.h:50
static struct settings cpuid_settings
CPUID settings.
cpuid_flags
CPUID setting tag flags.
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
String functions.
cpuid_registers
CPUID setting tag register indices.
struct refcnt * refcnt
Reference counter.
Definition: settings.h:135
#define CPUID_NUM_FUNCTIONS(tag)
Extract number of consecutive functions from CPUID setting tag.