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