2 * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
20 FILE_LICENCE ( GPL2_OR_LATER );
25 #include <ipxe/settings.h>
26 #include <ipxe/init.h>
27 #include <ipxe/uuid.h>
28 #include <ipxe/smbios.h>
30 /** SMBIOS settings scope */
31 static const struct settings_scope smbios_settings_scope;
34 * Construct SMBIOS raw-data tag
36 * @v _type SMBIOS structure type number
37 * @v _structure SMBIOS structure data type
38 * @v _field Field within SMBIOS structure data type
39 * @ret tag SMBIOS setting tag
41 #define SMBIOS_RAW_TAG( _type, _structure, _field ) \
42 ( ( (_type) << 16 ) | \
43 ( offsetof ( _structure, _field ) << 8 ) | \
44 ( sizeof ( ( ( _structure * ) 0 )->_field ) ) )
47 * Construct SMBIOS string tag
49 * @v _type SMBIOS structure type number
50 * @v _structure SMBIOS structure data type
51 * @v _field Field within SMBIOS structure data type
52 * @ret tag SMBIOS setting tag
54 #define SMBIOS_STRING_TAG( _type, _structure, _field ) \
55 ( ( (_type) << 16 ) | \
56 ( offsetof ( _structure, _field ) << 8 ) )
59 * Check applicability of SMBIOS setting
61 * @v settings Settings block
63 * @ret applies Setting applies within this settings block
65 static int smbios_applies ( struct settings *settings __unused,
66 const struct setting *setting ) {
68 return ( setting->scope == &smbios_settings_scope );
72 * Fetch value of SMBIOS setting
74 * @v settings Settings block, or NULL to search all blocks
75 * @v setting Setting to fetch
76 * @v data Buffer to fill with setting data
77 * @v len Length of buffer
78 * @ret len Length of setting data, or negative error
80 static int smbios_fetch ( struct settings *settings __unused,
81 struct setting *setting,
82 void *data, size_t len ) {
83 struct smbios_structure structure;
84 unsigned int tag_instance;
85 unsigned int tag_type;
86 unsigned int tag_offset;
90 /* Split tag into instance, type, offset and length */
91 tag_instance = ( ( setting->tag >> 24 ) & 0xff );
92 tag_type = ( ( setting->tag >> 16 ) & 0xff );
93 tag_offset = ( ( setting->tag >> 8 ) & 0xff );
94 tag_len = ( setting->tag & 0xff );
96 /* Find SMBIOS structure */
97 if ( ( rc = find_smbios_structure ( tag_type, tag_instance,
102 uint8_t buf[structure.header.len];
107 /* Read SMBIOS structure */
108 if ( ( rc = read_smbios_structure ( &structure, buf,
109 sizeof ( buf ) ) ) != 0 )
112 /* A <length> of zero indicates that the byte at
113 * <offset> contains a string index. An <offset> of
114 * zero indicates that the <length> contains a literal
117 if ( ( tag_len == 0 ) || ( tag_offset == 0 ) ) {
118 index = ( ( tag_offset == 0 ) ?
119 tag_len : buf[tag_offset] );
120 if ( ( rc = read_smbios_string ( &structure, index,
121 data, len ) ) < 0 ) {
124 if ( ! setting->type )
125 setting->type = &setting_type_string;
129 /* Mangle UUIDs if necessary. iPXE treats UUIDs as
130 * being in network byte order (big-endian). SMBIOS
131 * specification version 2.6 states that UUIDs are
132 * stored with little-endian values in the first three
133 * fields; earlier versions did not specify an
134 * endianness. dmidecode assumes that the byte order
135 * is little-endian if and only if the SMBIOS version
136 * is 2.6 or higher; we match this behaviour.
138 raw = &buf[tag_offset];
139 if ( ( setting->type == &setting_type_uuid ) &&
140 ( tag_len == sizeof ( uuid ) ) &&
141 ( smbios_version() >= SMBIOS_VERSION ( 2, 6 ) ) ) {
142 DBG ( "SMBIOS detected mangled UUID\n" );
143 memcpy ( &uuid, &buf[tag_offset], sizeof ( uuid ) );
144 uuid_mangle ( &uuid );
151 memcpy ( data, raw, len );
152 if ( ! setting->type )
153 setting->type = &setting_type_hex;
158 /** SMBIOS settings operations */
159 static struct settings_operations smbios_settings_operations = {
160 .applies = smbios_applies,
161 .fetch = smbios_fetch,
164 /** SMBIOS settings */
165 static struct settings smbios_settings = {
167 .siblings = LIST_HEAD_INIT ( smbios_settings.siblings ),
168 .children = LIST_HEAD_INIT ( smbios_settings.children ),
169 .op = &smbios_settings_operations,
170 .default_scope = &smbios_settings_scope,
173 /** Initialise SMBIOS settings */
174 static void smbios_init ( void ) {
177 if ( ( rc = register_settings ( &smbios_settings, NULL,
178 "smbios" ) ) != 0 ) {
179 DBG ( "SMBIOS could not register settings: %s\n",
185 /** SMBIOS settings initialiser */
186 struct init_fn smbios_init_fn __init_fn ( INIT_NORMAL ) = {
187 .initialise = smbios_init,
190 /** UUID setting obtained via SMBIOS */
191 const struct setting uuid_setting __setting ( SETTING_HOST, uuid ) = {
193 .description = "UUID",
194 .tag = SMBIOS_RAW_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
195 struct smbios_system_information, uuid ),
196 .type = &setting_type_uuid,
197 .scope = &smbios_settings_scope,
200 /** Manufacturer name setting */
201 const struct setting manufacturer_setting __setting ( SETTING_HOST_EXTRA,
203 .name = "manufacturer",
204 .description = "Manufacturer",
205 .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
206 struct smbios_system_information,
208 .type = &setting_type_string,
209 .scope = &smbios_settings_scope,
212 /** Product name setting */
213 const struct setting product_setting __setting ( SETTING_HOST_EXTRA, product )={
215 .description = "Product name",
216 .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
217 struct smbios_system_information,
219 .type = &setting_type_string,
220 .scope = &smbios_settings_scope,
223 /** Serial number setting */
224 const struct setting serial_setting __setting ( SETTING_HOST_EXTRA, serial ) = {
226 .description = "Serial number",
227 .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
228 struct smbios_system_information,
230 .type = &setting_type_string,
231 .scope = &smbios_settings_scope,
234 /** Asset tag setting */
235 const struct setting asset_setting __setting ( SETTING_HOST_EXTRA, asset ) = {
237 .description = "Asset tag",
238 .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_ENCLOSURE_INFORMATION,
239 struct smbios_enclosure_information,
241 .type = &setting_type_string,
242 .scope = &smbios_settings_scope,
245 /** Board serial number setting (may differ from chassis serial number) */
246 const struct setting board_serial_setting __setting ( SETTING_HOST_EXTRA,
248 .name = "board-serial",
249 .description = "Base board serial",
250 .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_BASE_BOARD_INFORMATION,
251 struct smbios_base_board_information,
253 .type = &setting_type_string,
254 .scope = &smbios_settings_scope,