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