iPXE
smbios_settings.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdint.h>
00027 #include <string.h>
00028 #include <errno.h>
00029 #include <ipxe/settings.h>
00030 #include <ipxe/init.h>
00031 #include <ipxe/uuid.h>
00032 #include <ipxe/smbios.h>
00033 
00034 /** SMBIOS settings scope */
00035 static const struct settings_scope smbios_settings_scope;
00036 
00037 /**
00038  * Construct SMBIOS raw-data tag
00039  *
00040  * @v _type             SMBIOS structure type number
00041  * @v _structure        SMBIOS structure data type
00042  * @v _field            Field within SMBIOS structure data type
00043  * @ret tag             SMBIOS setting tag
00044  */
00045 #define SMBIOS_RAW_TAG( _type, _structure, _field )             \
00046         ( ( (_type) << 16 ) |                                   \
00047           ( offsetof ( _structure, _field ) << 8 ) |            \
00048           ( sizeof ( ( ( _structure * ) 0 )->_field ) ) )
00049 
00050 /**
00051  * Construct SMBIOS string tag
00052  *
00053  * @v _type             SMBIOS structure type number
00054  * @v _structure        SMBIOS structure data type
00055  * @v _field            Field within SMBIOS structure data type
00056  * @ret tag             SMBIOS setting tag
00057  */
00058 #define SMBIOS_STRING_TAG( _type, _structure, _field )          \
00059         ( ( (_type) << 16 ) |                                   \
00060           ( offsetof ( _structure, _field ) << 8 ) )
00061 
00062 /**
00063  * Check applicability of SMBIOS setting
00064  *
00065  * @v settings          Settings block
00066  * @v setting           Setting
00067  * @ret applies         Setting applies within this settings block
00068  */
00069 static int smbios_applies ( struct settings *settings __unused,
00070                             const struct setting *setting ) {
00071 
00072         return ( setting->scope == &smbios_settings_scope );
00073 }
00074 
00075 /**
00076  * Fetch value of SMBIOS setting
00077  *
00078  * @v settings          Settings block, or NULL to search all blocks
00079  * @v setting           Setting to fetch
00080  * @v data              Buffer to fill with setting data
00081  * @v len               Length of buffer
00082  * @ret len             Length of setting data, or negative error
00083  */
00084 static int smbios_fetch ( struct settings *settings __unused,
00085                           struct setting *setting,
00086                           void *data, size_t len ) {
00087         struct smbios_structure structure;
00088         unsigned int tag_instance;
00089         unsigned int tag_type;
00090         unsigned int tag_offset;
00091         unsigned int tag_len;
00092         int rc;
00093 
00094         /* Split tag into instance, type, offset and length */
00095         tag_instance = ( ( setting->tag >> 24 ) & 0xff );
00096         tag_type = ( ( setting->tag >> 16 ) & 0xff );
00097         tag_offset = ( ( setting->tag >> 8 ) & 0xff );
00098         tag_len = ( setting->tag & 0xff );
00099 
00100         /* Find SMBIOS structure */
00101         if ( ( rc = find_smbios_structure ( tag_type, tag_instance,
00102                                             &structure ) ) != 0 )
00103                 return rc;
00104 
00105         {
00106                 uint8_t buf[structure.header.len];
00107                 const void *raw;
00108                 union uuid uuid;
00109                 unsigned int index;
00110 
00111                 /* Read SMBIOS structure */
00112                 if ( ( rc = read_smbios_structure ( &structure, buf,
00113                                                     sizeof ( buf ) ) ) != 0 )
00114                         return rc;
00115 
00116                 /* A <length> of zero indicates that the byte at
00117                  * <offset> contains a string index.  An <offset> of
00118                  * zero indicates that the <length> contains a literal
00119                  * string index.
00120                  */
00121                 if ( ( tag_len == 0 ) || ( tag_offset == 0 ) ) {
00122                         index = ( ( tag_offset == 0 ) ?
00123                                   tag_len : buf[tag_offset] );
00124                         if ( ( rc = read_smbios_string ( &structure, index,
00125                                                          data, len ) ) < 0 ) {
00126                                 return rc;
00127                         }
00128                         if ( ! setting->type )
00129                                 setting->type = &setting_type_string;
00130                         return rc;
00131                 }
00132 
00133                 /* Mangle UUIDs if necessary.  iPXE treats UUIDs as
00134                  * being in network byte order (big-endian).  SMBIOS
00135                  * specification version 2.6 states that UUIDs are
00136                  * stored with little-endian values in the first three
00137                  * fields; earlier versions did not specify an
00138                  * endianness.  dmidecode assumes that the byte order
00139                  * is little-endian if and only if the SMBIOS version
00140                  * is 2.6 or higher; we match this behaviour.
00141                  */
00142                 raw = &buf[tag_offset];
00143                 if ( ( setting->type == &setting_type_uuid ) &&
00144                      ( tag_len == sizeof ( uuid ) ) &&
00145                      ( smbios_version() >= SMBIOS_VERSION ( 2, 6 ) ) ) {
00146                         DBG ( "SMBIOS detected mangled UUID\n" );
00147                         memcpy ( &uuid, &buf[tag_offset], sizeof ( uuid ) );
00148                         uuid_mangle ( &uuid );
00149                         raw = &uuid;
00150                 }
00151 
00152                 /* Return data */
00153                 if ( len > tag_len )
00154                         len = tag_len;
00155                 memcpy ( data, raw, len );
00156                 if ( ! setting->type )
00157                         setting->type = &setting_type_hex;
00158                 return tag_len;
00159         }
00160 }
00161 
00162 /** SMBIOS settings operations */
00163 static struct settings_operations smbios_settings_operations = {
00164         .applies = smbios_applies,
00165         .fetch = smbios_fetch,
00166 };
00167 
00168 /** SMBIOS settings */
00169 static struct settings smbios_settings = {
00170         .refcnt = NULL,
00171         .siblings = LIST_HEAD_INIT ( smbios_settings.siblings ),
00172         .children = LIST_HEAD_INIT ( smbios_settings.children ),
00173         .op = &smbios_settings_operations,
00174         .default_scope = &smbios_settings_scope,
00175 };
00176 
00177 /** Initialise SMBIOS settings */
00178 static void smbios_init ( void ) {
00179         int rc;
00180 
00181         if ( ( rc = register_settings ( &smbios_settings, NULL,
00182                                         "smbios" ) ) != 0 ) {
00183                 DBG ( "SMBIOS could not register settings: %s\n",
00184                       strerror ( rc ) );
00185                 return;
00186         }
00187 }
00188 
00189 /** SMBIOS settings initialiser */
00190 struct init_fn smbios_init_fn __init_fn ( INIT_NORMAL ) = {
00191         .initialise = smbios_init,
00192 };
00193 
00194 /** UUID setting obtained via SMBIOS */
00195 const struct setting uuid_setting __setting ( SETTING_HOST, uuid ) = {
00196         .name = "uuid",
00197         .description = "UUID",
00198         .tag = SMBIOS_RAW_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
00199                                 struct smbios_system_information, uuid ),
00200         .type = &setting_type_uuid,
00201         .scope = &smbios_settings_scope,
00202 };
00203 
00204 /** Manufacturer name setting */
00205 const struct setting manufacturer_setting __setting ( SETTING_HOST_EXTRA,
00206                                                       manufacturer ) = {
00207         .name = "manufacturer",
00208         .description = "Manufacturer",
00209         .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
00210                                    struct smbios_system_information,
00211                                    manufacturer ),
00212         .type = &setting_type_string,
00213         .scope = &smbios_settings_scope,
00214 };
00215 
00216 /** Product name setting */
00217 const struct setting product_setting __setting ( SETTING_HOST_EXTRA, product )={
00218         .name = "product",
00219         .description = "Product name",
00220         .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
00221                                    struct smbios_system_information,
00222                                    product ),
00223         .type = &setting_type_string,
00224         .scope = &smbios_settings_scope,
00225 };
00226 
00227 /** Serial number setting */
00228 const struct setting serial_setting __setting ( SETTING_HOST_EXTRA, serial ) = {
00229         .name = "serial",
00230         .description = "Serial number",
00231         .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
00232                                    struct smbios_system_information,
00233                                    serial ),
00234         .type = &setting_type_string,
00235         .scope = &smbios_settings_scope,
00236 };
00237 
00238 /** Asset tag setting */
00239 const struct setting asset_setting __setting ( SETTING_HOST_EXTRA, asset ) = {
00240         .name = "asset",
00241         .description = "Asset tag",
00242         .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_ENCLOSURE_INFORMATION,
00243                                    struct smbios_enclosure_information,
00244                                    asset_tag ),
00245         .type = &setting_type_string,
00246         .scope = &smbios_settings_scope,
00247 };
00248 
00249 /** Board serial number setting (may differ from chassis serial number) */
00250 const struct setting board_serial_setting __setting ( SETTING_HOST_EXTRA,
00251                                                       board-serial ) = {
00252         .name = "board-serial",
00253         .description = "Base board serial",
00254         .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_BASE_BOARD_INFORMATION,
00255                                    struct smbios_base_board_information,
00256                                    serial ),
00257         .type = &setting_type_string,
00258         .scope = &smbios_settings_scope,
00259 };