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
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_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 */
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 ) {
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 */
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 ) )
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 */
230
231/** CPUID settings */
232static 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 */
241static 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 */
253struct init_fn cpuid_settings_init_fn __init_fn ( INIT_NORMAL ) = {
254 .name = "cpuid",
255 .initialise = cpuid_settings_init,
256};
257
258/** CPU vendor setting */
259const 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 */
270const struct setting cpumodel_setting __setting ( SETTING_HOST_EXTRA,
271 cpumodel ) = {
272 .name = "cpumodel",
273 .description = "CPU model",
276 .type = &setting_type_string,
277 .scope = &cpuid_settings_scope,
278};
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned int uint32_t
Definition stdint.h:12
int cpuid_supported(uint32_t function)
Check whether or not CPUID function is supported.
Definition cpuid.c:76
x86 CPU feature detection
#define CPUID_HYPERVISOR
CPUID hypervisor function.
Definition cpuid.h:38
#define CPUID_MODEL
Get CPU model.
Definition cpuid.h:71
static uint32_t subfunction
Definition cpuid.h:90
#define CPUID_VENDOR_ID
Get vendor ID and largest standard function.
Definition cpuid.h:41
cpuid_registers
CPUID setting tag register indices.
@ CPUID_EAX
@ CPUID_EDX
@ CPUID_EBX
@ CPUID_ECX
#define CPUID_NUM_FUNCTIONS(tag)
Extract number of consecutive functions from CPUID setting tag.
static struct settings_operations cpuid_settings_operations
CPUID settings operations.
static const struct settings_scope cpuid_settings_scope
CPUID settings scope.
#define CPUID_TAG(function, subfunction, flags, num_registers, register1, register2, register3, register4)
Construct CPUID setting tag.
static void cpuid_settings_init(void)
Initialise CPUID settings.
#define CPUID_NUM_REGISTERS(tag)
Extract number of registers from CPUID setting tag.
#define CPUID_FUNCTION(tag)
Extract starting function number from CPUID setting tag.
cpuid_flags
CPUID setting tag flags.
@ CPUID_USE_SUBFUNCTION
@ CPUID_LITTLE_ENDIAN
static int cpuid_settings_fetch(struct settings *settings, struct setting *setting, void *data, size_t len)
Fetch value of CPUID setting.
#define CPUID_SUBFUNCTION(tag)
Extract subfunction number from CPUID setting tag.
static int cpuid_settings_applies(struct settings *settings __unused, const struct setting *setting)
Check applicability of CPUID setting.
#define CPUID_REGISTERS(tag)
Extract register array from CPUID setting tag.
static struct settings cpuid_settings
CPUID settings.
ring len
Length.
Definition dwmac.h:226
uint8_t function
Function.
Definition edd.h:5
uint8_t data[48]
Additional event data.
Definition ena.h:11
Error codes.
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBGC(...)
Definition compiler.h:505
#define DBG(...)
Print a debugging message.
Definition compiler.h:498
#define INIT_NORMAL
Normal initialisation.
Definition init.h:32
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
#define SETTING_HOST_EXTRA
Host identity additional settings.
Definition settings.h:77
#define cpu_to_be32(value)
Definition byteswap.h:111
Configuration settings.
#define __setting(setting_order, name)
Declare a configuration setting.
Definition settings.h:57
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
#define __init_fn(init_order)
Declare an initialisation functon.
Definition init.h:24
#define LIST_HEAD_INIT(list)
Initialise a static list head.
Definition list.h:31
int register_settings(struct settings *settings, struct settings *parent, const char *name)
Register settings block.
Definition settings.c:476
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
An initialisation function.
Definition init.h:15
A setting.
Definition settings.h:24
const struct settings_scope * scope
Setting scope (or NULL)
Definition settings.h:50
const struct setting_type * type
Setting type.
Definition settings.h:37
uint64_t tag
Setting tag, if applicable.
Definition settings.h:44
Settings block operations.
Definition settings.h:86
A setting scope.
Definition settings.h:177
A settings block.
Definition settings.h:133