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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_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 */
41 static 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  */
52 static 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  */
70 const 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  */
116 const 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  */
161 static 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  */
183 const 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  */
252 const 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  */
285 int 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  */
301 void smbios_clear ( void ) {
302 
303  /* Clear address */
304  smbios.address = NULL;
305 }
uint32_t signature
Signature.
Definition: smbios.h:55
#define __attribute__(x)
Definition: compiler.h:10
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define SMBIOS_SIGNATURE
Signature for 32-bit SMBIOS entry point.
Definition: smbios.h:36
unsigned short uint16_t
Definition: stdint.h:11
unsigned int count
Number of SMBIOS structures.
Definition: smbios.h:204
const char * smbios_string(const struct smbios_header *structure, unsigned int index)
Get indexed string within SMBIOS structure.
Definition: smbios.c:252
Error codes.
#define SMBIOS_TYPE_END
SMBIOS end of table type.
Definition: smbios.h:190
uint32_t type
Operating system type.
Definition: ena.h:12
#define DBGC(...)
Definition: compiler.h:505
size_t len
Length of SMBIOS structures.
Definition: smbios.h:202
const struct smbios_header * smbios_structure(unsigned int type, unsigned int instance)
Find specific structure type within SMBIOS.
Definition: smbios.c:183
long index
Definition: bigint.h:65
uint32_t string
Definition: multiboot.h:14
SMBIOS entry point descriptor.
Definition: smbios.h:198
#define SMBIOS3_SIGNATURE
Signature for 64-bit SMBIOS entry point.
Definition: smbios.h:40
int find_smbios(struct smbios *smbios)
uint16_t version
SMBIOS version.
Definition: smbios.h:206
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
void smbios_clear(void)
Clear SMBIOS entry point descriptor.
Definition: smbios.c:301
uint32_t start
Starting offset.
Definition: netvsc.h:12
uint8_t len
Length.
Definition: smbios.h:102
uint8_t len
Length.
Definition: smbios.h:124
FILE_SECBOOT(PERMITTED)
Assertions.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
Access to external ("user") memory.
uint32_t signature
Signature.
Definition: smbios.h:96
ring len
Length.
Definition: dwmac.h:231
SMBIOS 32-bit entry point.
Definition: smbios.h:50
static unsigned int count
Number of entries.
Definition: dwmac.h:225
int smbios_version(void)
Get SMBIOS version.
Definition: smbios.c:285
const void * address
Start of SMBIOS structures.
Definition: smbios.h:200
size_t strlen(const char *src)
Get length of string.
Definition: string.c:244
unsigned char uint8_t
Definition: stdint.h:10
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
System Management BIOS.
uint8_t minor
Minor version.
Definition: smbios.h:63
An SMBIOS structure header.
Definition: smbios.h:120
uint8_t type
Type.
Definition: smbios.h:122
uint8_t minor
Minor version.
Definition: smbios.h:106
uint8_t len
Length.
Definition: smbios.h:59
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
static uint8_t smbios_checksum(const void *start, size_t len)
Calculate SMBIOS entry point structure checksum.
Definition: smbios.c:52
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
uint8_t major
Major version.
Definition: smbios.h:61
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
String functions.
static size_t find_strings_terminator(size_t offset)
Find SMBIOS strings terminator.
Definition: smbios.c:161
uint8_t major
Major version.
Definition: smbios.h:104
SMBIOS 64-bit entry point.
Definition: smbios.h:91