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