iPXE
smbios.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2007 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 <stdint.h>
28#include <string.h>
29#include <errno.h>
30#include <assert.h>
31#include <ipxe/uaccess.h>
32#include <ipxe/smbios.h>
33
34/** @file
35 *
36 * System Management BIOS
37 *
38 */
39
40/** SMBIOS entry point descriptor */
41static struct smbios smbios = {
42 .address = NULL,
43};
44
45/**
46 * Calculate SMBIOS entry point structure checksum
47 *
48 * @v start Start address of region
49 * @v len Length of entry point structure
50 * @ret sum Byte checksum
51 */
52static uint8_t smbios_checksum ( const void *start, size_t len ) {
53 const uint8_t *byte = start;
54 uint8_t sum = 0;
55
56 /* Compute checksum */
57 while ( len-- )
58 sum += *(byte++);
59
60 return sum;
61}
62
63/**
64 * Scan for SMBIOS 32-bit entry point structure
65 *
66 * @v start Start address of region to scan
67 * @v len Length of region to scan
68 * @ret entry SMBIOS entry point structure, or NULL if not found
69 */
70const struct smbios_entry * find_smbios_entry ( const void *start,
71 size_t len ) {
72 static size_t offset = 0; /* Avoid repeated attempts to locate SMBIOS */
73 const struct smbios_entry *entry;
74 uint8_t sum;
75
76 /* Try to find SMBIOS */
77 for ( ; ( offset + sizeof ( *entry ) ) <= len ; offset += 0x10 ) {
78
79 /* Verify signature */
80 entry = ( start + offset );
81 if ( entry->signature != SMBIOS_SIGNATURE )
82 continue;
83
84 /* Verify length */
85 if ( ( entry->len < sizeof ( *entry ) ) ||
86 ( ( offset + entry->len ) > len ) ) {
87 DBGC ( &smbios, "SMBIOS at %#08lx has bad length "
88 "%#02x\n", virt_to_phys ( entry ), entry->len );
89 continue;
90 }
91
92 /* Verify checksum */
93 if ( ( sum = smbios_checksum ( entry, entry->len ) ) != 0 ) {
94 DBGC ( &smbios, "SMBIOS at %#08lx has bad checksum "
95 "%#02x\n", virt_to_phys ( entry ), sum );
96 continue;
97 }
98
99 /* Fill result structure */
100 DBGC ( &smbios, "Found SMBIOS v%d.%d entry point at %#08lx\n",
101 entry->major, entry->minor, virt_to_phys ( entry ) );
102 return entry;
103 }
104
105 DBGC ( &smbios, "No SMBIOS found\n" );
106 return NULL;
107}
108
109/**
110 * Scan for SMBIOS 64-bit entry point structure
111 *
112 * @v start Start address of region to scan
113 * @v len Length of region to scan
114 * @ret entry SMBIOS entry point structure, or NULL if not found
115 */
116const struct smbios3_entry * find_smbios3_entry ( const void *start,
117 size_t len ) {
118 static size_t offset = 0; /* Avoid repeated attempts to locate SMBIOS */
119 const struct smbios3_entry *entry;
120 uint8_t sum;
121
122 /* Try to find SMBIOS */
123 for ( ; ( offset + sizeof ( *entry ) ) <= len ; offset += 0x10 ) {
124
125 /* Verify signature */
126 entry = ( start + offset );
127 if ( entry->signature != SMBIOS3_SIGNATURE )
128 continue;
129
130 /* Verify length */
131 if ( ( entry->len < sizeof ( *entry ) ) ||
132 ( ( offset + entry->len ) > len ) ) {
133 DBGC ( &smbios, "SMBIOS at %#08lx has bad length "
134 "%#02x\n", virt_to_phys ( entry ), entry->len );
135 continue;
136 }
137
138 /* Verify checksum */
139 if ( ( sum = smbios_checksum ( entry, entry->len ) ) != 0 ) {
140 DBGC ( &smbios, "SMBIOS3 at %#08lx has bad checksum "
141 "%#02x\n", virt_to_phys ( entry ), sum );
142 continue;
143 }
144
145 /* Fill result structure */
146 DBGC ( &smbios, "Found SMBIOS3 v%d.%d entry point at %#08lx\n",
147 entry->major, entry->minor, virt_to_phys ( entry ) );
148 return entry;
149 }
150
151 DBGC ( &smbios, "No SMBIOS3 found\n" );
152 return NULL;
153}
154
155/**
156 * Find SMBIOS strings terminator
157 *
158 * @v offset Offset to start of strings
159 * @ret offset Offset to strings terminator, or 0 if not found
160 */
161static size_t find_strings_terminator ( size_t offset ) {
162 const uint16_t *nulnul __attribute__ (( aligned ( 1 ) ));
163
164 /* Sanity checks */
165 assert ( smbios.address != NULL );
166
167 /* Check for presence of terminating empty string */
168 for ( ; ( offset + sizeof ( *nulnul ) ) <= smbios.len ; offset++ ) {
169 nulnul = ( smbios.address + offset );
170 if ( *nulnul == 0 )
171 return ( offset + 1 );
172 }
173 return 0;
174}
175
176/**
177 * Find specific structure type within SMBIOS
178 *
179 * @v type Structure type to search for
180 * @v instance Instance of this type of structure
181 * @ret structure SMBIOS structure header, or NULL if not found
182 */
183const struct smbios_header * smbios_structure ( unsigned int type,
184 unsigned int instance ) {
185 const struct smbios_header *structure;
186 unsigned int count = 0;
187 size_t offset = 0;
188 size_t strings_offset;
189 size_t terminator_offset;
190 size_t strings_len;
191 int rc;
192
193 /* Find SMBIOS */
194 if ( ( smbios.address == NULL ) &&
195 ( ( rc = find_smbios ( &smbios ) ) != 0 ) )
196 return NULL;
197 assert ( smbios.address != NULL );
198
199 /* Scan through list of structures */
200 while ( ( ( offset + sizeof ( *structure ) ) < smbios.len ) &&
201 ( ( smbios.count == 0 ) || ( count < smbios.count ) ) ) {
202
203 /* Access next SMBIOS structure header */
204 structure = ( smbios.address + offset );
205
206 /* Determine start and extent of strings block */
207 strings_offset = ( offset + structure->len );
208 if ( strings_offset > smbios.len ) {
209 DBGC ( &smbios, "SMBIOS structure at offset %#zx "
210 "with length %#x extends beyond SMBIOS\n",
211 offset, structure->len );
212 return NULL;
213 }
214 terminator_offset = find_strings_terminator ( strings_offset );
215 if ( ! terminator_offset ) {
216 DBGC ( &smbios, "SMBIOS structure at offset %#zx has "
217 "unterminated strings section\n", offset );
218 return NULL;
219 }
220 strings_len = ( terminator_offset - strings_offset);
221 DBGC ( &smbios, "SMBIOS structure at offset %#zx has type %d, "
222 "length %#x, strings length %#zx\n", offset,
223 structure->type, structure->len, strings_len );
224
225 /* Stop if we have reached an end-of-table marker */
226 if ( ( smbios.count == 0 ) &&
227 ( structure->type == SMBIOS_TYPE_END ) )
228 break;
229
230 /* If this is the structure we want, return */
231 if ( ( structure->type == type ) &&
232 ( instance-- == 0 ) ) {
233 return structure;
234 }
235
236 /* Move to next SMBIOS structure */
237 offset = ( terminator_offset + 1 );
238 count++;
239 }
240
241 DBGC ( &smbios, "SMBIOS structure type %d not found\n", type );
242 return NULL;
243}
244
245/**
246 * Get indexed string within SMBIOS structure
247 *
248 * @v structure SMBIOS structure header
249 * @v index String index
250 * @ret string SMBIOS string, or NULL if not fond
251 */
252const char * smbios_string ( const struct smbios_header *structure,
253 unsigned int index ) {
254 const char *string;
255 unsigned int i;
256 size_t len;
257
258 /* Sanity check */
259 assert ( smbios.address != NULL );
260
261 /* Step through strings */
262 string = ( ( ( const void * ) structure ) + structure->len );
263 for ( i = index ; i-- ; ) {
264 /* Get string length. This is known safe, since we
265 * check for the empty-string terminator in
266 * smbios_structure().
267 */
268 len = strlen ( string );
269 if ( ! len )
270 break;
271 if ( i == 0 )
272 return string;
273 string += ( len + 1 /* NUL */ );
274 }
275
276 DBGC ( &smbios, "SMBIOS string index %d not found\n", index );
277 return NULL;
278}
279
280/**
281 * Get SMBIOS version
282 *
283 * @ret version Version, or negative error
284 */
285int smbios_version ( void ) {
286 int rc;
287
288 /* Find SMBIOS */
289 if ( ( smbios.address == NULL ) &&
290 ( ( rc = find_smbios ( &smbios ) ) != 0 ) )
291 return rc;
292 assert ( smbios.address != NULL );
293
294 return smbios.version;
295}
296
297/**
298 * Clear SMBIOS entry point descriptor
299 *
300 */
301void smbios_clear ( void ) {
302
303 /* Clear address */
305}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned short uint16_t
Definition stdint.h:11
unsigned char uint8_t
Definition stdint.h:10
long index
Definition bigint.h:65
Assertions.
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
uint16_t offset
Offset to command line.
Definition bzimage.h:3
ring len
Length.
Definition dwmac.h:226
uint32_t type
Operating system type.
Definition ena.h:1
Error codes.
#define DBGC(...)
Definition compiler.h:505
uint32_t start
Starting offset.
Definition netvsc.h:1
static unsigned int count
Number of entries.
Definition dwmac.h:220
#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 __attribute__(x)
Definition compiler.h:10
System Management BIOS.
#define SMBIOS3_SIGNATURE
Signature for 64-bit SMBIOS entry point.
Definition smbios.h:40
#define SMBIOS_SIGNATURE
Signature for 32-bit SMBIOS entry point.
Definition smbios.h:36
int find_smbios(struct smbios *smbios)
#define SMBIOS_TYPE_END
SMBIOS end of table type.
Definition smbios.h:190
String functions.
Access to external ("user") memory.
uint32_t string
Definition multiboot.h:2
const char * smbios_string(const struct smbios_header *structure, unsigned int index)
Get indexed string within SMBIOS structure.
Definition smbios.c:252
static size_t find_strings_terminator(size_t offset)
Find SMBIOS strings terminator.
Definition smbios.c:161
static uint8_t smbios_checksum(const void *start, size_t len)
Calculate SMBIOS entry point structure checksum.
Definition smbios.c:52
const struct smbios_entry * find_smbios_entry(const void *start, size_t len)
Scan for SMBIOS 32-bit entry point structure.
Definition smbios.c:70
void smbios_clear(void)
Clear SMBIOS entry point descriptor.
Definition smbios.c:301
const struct smbios3_entry * find_smbios3_entry(const void *start, size_t len)
Scan for SMBIOS 64-bit entry point structure.
Definition smbios.c:116
const struct smbios_header * smbios_structure(unsigned int type, unsigned int instance)
Find specific structure type within SMBIOS.
Definition smbios.c:183
int smbios_version(void)
Get SMBIOS version.
Definition smbios.c:285
size_t strlen(const char *src)
Get length of string.
Definition string.c:244
SMBIOS 64-bit entry point.
Definition smbios.h:91
uint8_t major
Major version.
Definition smbios.h:104
uint8_t len
Length.
Definition smbios.h:102
uint8_t minor
Minor version.
Definition smbios.h:106
uint32_t signature
Signature.
Definition smbios.h:96
SMBIOS 32-bit entry point.
Definition smbios.h:50
uint8_t minor
Minor version.
Definition smbios.h:63
uint32_t signature
Signature.
Definition smbios.h:55
uint8_t major
Major version.
Definition smbios.h:61
uint8_t len
Length.
Definition smbios.h:59
An SMBIOS structure header.
Definition smbios.h:120
uint8_t len
Length.
Definition smbios.h:124
uint8_t type
Type.
Definition smbios.h:122
SMBIOS entry point descriptor.
Definition smbios.h:198
size_t len
Length of SMBIOS structures.
Definition smbios.h:202
unsigned int count
Number of SMBIOS structures.
Definition smbios.h:204
uint16_t version
SMBIOS version.
Definition smbios.h:206
const void * address
Start of SMBIOS structures.
Definition smbios.h:200