1 /*
2  * Copyright (C) 2008 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 <stdint.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <ipxe/settings.h>
30 #include <ipxe/init.h>
31 #include <ipxe/uuid.h>
32 #include <ipxe/smbios.h>
33 
34 /** SMBIOS settings scope */
35 static const struct settings_scope smbios_settings_scope;
36 
37 /**
38  * Construct SMBIOS raw-data tag
39  *
40  * @v _type		SMBIOS structure type number
41  * @v _structure	SMBIOS structure data type
42  * @v _field		Field within SMBIOS structure data type
43  * @ret tag		SMBIOS setting tag
44  */
45 #define SMBIOS_RAW_TAG( _type, _structure, _field )		\
46 	( ( (_type) << 16 ) |					\
47 	  ( offsetof ( _structure, _field ) << 8 ) |		\
48 	  ( sizeof ( ( ( _structure * ) 0 )->_field ) ) )
49 
50 /**
51  * Construct SMBIOS string tag
52  *
53  * @v _type		SMBIOS structure type number
54  * @v _structure	SMBIOS structure data type
55  * @v _field		Field within SMBIOS structure data type
56  * @ret tag		SMBIOS setting tag
57  */
58 #define SMBIOS_STRING_TAG( _type, _structure, _field )		\
59 	( ( (_type) << 16 ) |					\
60 	  ( offsetof ( _structure, _field ) << 8 ) )
61 
62 /**
63  * Check applicability of SMBIOS setting
64  *
65  * @v settings		Settings block
66  * @v setting		Setting
67  * @ret applies		Setting applies within this settings block
68  */
smbios_applies(struct settings * settings __unused,const struct setting * setting)69 static int smbios_applies ( struct settings *settings __unused,
70 			    const struct setting *setting ) {
71 
72 	return ( setting->scope == &smbios_settings_scope );
73 }
74 
75 /**
76  * Fetch value of SMBIOS setting
77  *
78  * @v settings		Settings block, or NULL to search all blocks
79  * @v setting		Setting to fetch
80  * @v data		Buffer to fill with setting data
81  * @v len		Length of buffer
82  * @ret len		Length of setting data, or negative error
83  */
smbios_fetch(struct settings * settings __unused,struct setting * setting,void * data,size_t len)84 static int smbios_fetch ( struct settings *settings __unused,
85 			  struct setting *setting,
86 			  void *data, size_t len ) {
87 	struct smbios_structure structure;
88 	unsigned int tag_instance;
89 	unsigned int tag_type;
90 	unsigned int tag_offset;
91 	unsigned int tag_len;
92 	int rc;
93 
94 	/* Split tag into instance, type, offset and length */
95 	tag_instance = ( ( setting->tag >> 24 ) & 0xff );
96 	tag_type = ( ( setting->tag >> 16 ) & 0xff );
97 	tag_offset = ( ( setting->tag >> 8 ) & 0xff );
98 	tag_len = ( setting->tag & 0xff );
99 
100 	/* Find SMBIOS structure */
101 	if ( ( rc = find_smbios_structure ( tag_type, tag_instance,
102 					    &structure ) ) != 0 )
103 		return rc;
104 
105 	{
106 		uint8_t buf[structure.header.len];
107 		const void *raw;
108 		union uuid uuid;
109 		unsigned int index;
110 
111 		/* Read SMBIOS structure */
112 		if ( ( rc = read_smbios_structure ( &structure, buf,
113 						    sizeof ( buf ) ) ) != 0 )
114 			return rc;
115 
116 		/* A <length> of zero indicates that the byte at
117 		 * <offset> contains a string index.  An <offset> of
118 		 * zero indicates that the <length> contains a literal
119 		 * string index.
120 		 */
121 		if ( ( tag_len == 0 ) || ( tag_offset == 0 ) ) {
122 			index = ( ( tag_offset == 0 ) ?
123 				  tag_len : buf[tag_offset] );
124 			if ( ( rc = read_smbios_string ( &structure, index,
125 							 data, len ) ) < 0 ) {
126 				return rc;
127 			}
128 			if ( ! setting->type )
129 				setting->type = &setting_type_string;
130 			return rc;
131 		}
132 
133 		/* Mangle UUIDs if necessary.  iPXE treats UUIDs as
134 		 * being in network byte order (big-endian).  SMBIOS
135 		 * specification version 2.6 states that UUIDs are
136 		 * stored with little-endian values in the first three
137 		 * fields; earlier versions did not specify an
138 		 * endianness.  dmidecode assumes that the byte order
139 		 * is little-endian if and only if the SMBIOS version
140 		 * is 2.6 or higher; we match this behaviour.
141 		 */
142 		raw = &buf[tag_offset];
143 		if ( ( setting->type == &setting_type_uuid ) &&
144 		     ( tag_len == sizeof ( uuid ) ) &&
145 		     ( smbios_version() >= SMBIOS_VERSION ( 2, 6 ) ) ) {
146 			DBG ( "SMBIOS detected mangled UUID\n" );
147 			memcpy ( &uuid, &buf[tag_offset], sizeof ( uuid ) );
148 			uuid_mangle ( &uuid );
149 			raw = &uuid;
150 		}
151 
152 		/* Return data */
153 		if ( len > tag_len )
154 			len = tag_len;
155 		memcpy ( data, raw, len );
156 		if ( ! setting->type )
157 			setting->type = &setting_type_hex;
158 		return tag_len;
159 	}
160 }
161 
162 /** SMBIOS settings operations */
163 static struct settings_operations smbios_settings_operations = {
164 	.applies = smbios_applies,
165 	.fetch = smbios_fetch,
166 };
167 
168 /** SMBIOS settings */
169 static struct settings smbios_settings = {
170 	.refcnt = NULL,
171 	.siblings = LIST_HEAD_INIT ( smbios_settings.siblings ),
172 	.children = LIST_HEAD_INIT ( smbios_settings.children ),
173 	.op = &smbios_settings_operations,
174 	.default_scope = &smbios_settings_scope,
175 };
176 
177 /** Initialise SMBIOS settings */
smbios_init(void)178 static void smbios_init ( void ) {
179 	int rc;
180 
181 	if ( ( rc = register_settings ( &smbios_settings, NULL,
182 					"smbios" ) ) != 0 ) {
183 		DBG ( "SMBIOS could not register settings: %s\n",
184 		      strerror ( rc ) );
185 		return;
186 	}
187 }
188 
189 /** SMBIOS settings initialiser */
190 struct init_fn smbios_init_fn __init_fn ( INIT_NORMAL ) = {
191 	.initialise = smbios_init,
192 };
193 
194 /** UUID setting obtained via SMBIOS */
195 const struct setting uuid_setting __setting ( SETTING_HOST, uuid ) = {
196 	.name = "uuid",
197 	.description = "UUID",
198 	.tag = SMBIOS_RAW_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
199 				struct smbios_system_information, uuid ),
200 	.type = &setting_type_uuid,
201 	.scope = &smbios_settings_scope,
202 };
203 
204 /** Manufacturer name setting */
205 const struct setting manufacturer_setting __setting ( SETTING_HOST_EXTRA,
206 						      manufacturer ) = {
207 	.name = "manufacturer",
208 	.description = "Manufacturer",
209 	.tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
210 				   struct smbios_system_information,
211 				   manufacturer ),
212 	.type = &setting_type_string,
213 	.scope = &smbios_settings_scope,
214 };
215 
216 /** Product name setting */
217 const struct setting product_setting __setting ( SETTING_HOST_EXTRA, product )={
218 	.name = "product",
219 	.description = "Product name",
220 	.tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
221 				   struct smbios_system_information,
222 				   product ),
223 	.type = &setting_type_string,
224 	.scope = &smbios_settings_scope,
225 };
226 
227 /** Serial number setting */
228 const struct setting serial_setting __setting ( SETTING_HOST_EXTRA, serial ) = {
229 	.name = "serial",
230 	.description = "Serial number",
231 	.tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION,
232 				   struct smbios_system_information,
233 				   serial ),
234 	.type = &setting_type_string,
235 	.scope = &smbios_settings_scope,
236 };
237 
238 /** Asset tag setting */
239 const struct setting asset_setting __setting ( SETTING_HOST_EXTRA, asset ) = {
240 	.name = "asset",
241 	.description = "Asset tag",
242 	.tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_ENCLOSURE_INFORMATION,
243 				   struct smbios_enclosure_information,
244 				   asset_tag ),
245 	.type = &setting_type_string,
246 	.scope = &smbios_settings_scope,
247 };
248 
249 /** Board serial number setting (may differ from chassis serial number) */
250 const struct setting board_serial_setting __setting ( SETTING_HOST_EXTRA,
251 						      board-serial ) = {
252 	.name = "board-serial",
253 	.description = "Base board serial",
254 	.tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_BASE_BOARD_INFORMATION,
255 				   struct smbios_base_board_information,
256 				   serial ),
257 	.type = &setting_type_string,
258 	.scope = &smbios_settings_scope,
259 };
260