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 = UNULL,
42 };
43 
44 /**
45  * Scan for SMBIOS entry point structure
46  *
47  * @v start Start address of region to scan
48  * @v len Length of region to scan
49  * @v entry SMBIOS entry point structure to fill in
50  * @ret rc Return status code
51  */
53  struct smbios_entry *entry ) {
54  uint8_t buf[256]; /* 256 is maximum length possible */
55  static size_t offset = 0; /* Avoid repeated attempts to locate SMBIOS */
56  size_t entry_len;
57  unsigned int i;
58  uint8_t sum;
59 
60  /* Try to find SMBIOS */
61  for ( ; offset < len ; offset += 0x10 ) {
62 
63  /* Read start of header and verify signature */
64  copy_from_user ( entry, start, offset, sizeof ( *entry ) );
65  if ( entry->signature != SMBIOS_SIGNATURE )
66  continue;
67 
68  /* Read whole header and verify checksum */
69  entry_len = entry->len;
70  assert ( entry_len <= sizeof ( buf ) );
71  copy_from_user ( buf, start, offset, entry_len );
72  for ( i = 0, sum = 0 ; i < entry_len ; i++ ) {
73  sum += buf[i];
74  }
75  if ( sum != 0 ) {
76  DBG ( "SMBIOS at %08lx has bad checksum %02x\n",
77  user_to_phys ( start, offset ), sum );
78  continue;
79  }
80 
81  /* Fill result structure */
82  DBG ( "Found SMBIOS v%d.%d entry point at %08lx\n",
83  entry->major, entry->minor,
84  user_to_phys ( start, offset ) );
85  return 0;
86  }
87 
88  DBG ( "No SMBIOS found\n" );
89  return -ENODEV;
90 }
91 
92 /**
93  * Find SMBIOS strings terminator
94  *
95  * @v offset Offset to start of strings
96  * @ret offset Offset to strings terminator, or 0 if not found
97  */
98 static size_t find_strings_terminator ( size_t offset ) {
99  size_t max_offset = ( smbios.len - 2 );
100  uint16_t nulnul;
101 
102  for ( ; offset <= max_offset ; offset++ ) {
103  copy_from_user ( &nulnul, smbios.address, offset, 2 );
104  if ( nulnul == 0 )
105  return ( offset + 1 );
106  }
107  return 0;
108 }
109 
110 /**
111  * Find specific structure type within SMBIOS
112  *
113  * @v type Structure type to search for
114  * @v instance Instance of this type of structure
115  * @v structure SMBIOS structure descriptor to fill in
116  * @ret rc Return status code
117  */
118 int find_smbios_structure ( unsigned int type, unsigned int instance,
119  struct smbios_structure *structure ) {
120  unsigned int count = 0;
121  size_t offset = 0;
122  size_t strings_offset;
123  size_t terminator_offset;
124  int rc;
125 
126  /* Find SMBIOS */
127  if ( ( smbios.address == UNULL ) &&
128  ( ( rc = find_smbios ( &smbios ) ) != 0 ) )
129  return rc;
130  assert ( smbios.address != UNULL );
131 
132  /* Scan through list of structures */
133  while ( ( ( offset + sizeof ( structure->header ) ) < smbios.len ) &&
134  ( ( smbios.count == 0 ) || ( count < smbios.count ) ) ) {
135 
136  /* Read next SMBIOS structure header */
137  copy_from_user ( &structure->header, smbios.address, offset,
138  sizeof ( structure->header ) );
139 
140  /* Determine start and extent of strings block */
141  strings_offset = ( offset + structure->header.len );
142  if ( strings_offset > smbios.len ) {
143  DBG ( "SMBIOS structure at offset %zx with length "
144  "%x extends beyond SMBIOS\n", offset,
145  structure->header.len );
146  return -ENOENT;
147  }
148  terminator_offset = find_strings_terminator ( strings_offset );
149  if ( ! terminator_offset ) {
150  DBG ( "SMBIOS structure at offset %zx has "
151  "unterminated strings section\n", offset );
152  return -ENOENT;
153  }
154  structure->strings_len = ( terminator_offset - strings_offset);
155 
156  DBG ( "SMBIOS structure at offset %zx has type %d, length %x, "
157  "strings length %zx\n", offset, structure->header.type,
158  structure->header.len, structure->strings_len );
159 
160  /* Stop if we have reached an end-of-table marker */
161  if ( ( smbios.count == 0 ) &&
162  ( structure->header.type == SMBIOS_TYPE_END ) )
163  break;
164 
165  /* If this is the structure we want, return */
166  if ( ( structure->header.type == type ) &&
167  ( instance-- == 0 ) ) {
168  structure->offset = offset;
169  return 0;
170  }
171 
172  /* Move to next SMBIOS structure */
173  offset = ( terminator_offset + 1 );
174  count++;
175  }
176 
177  DBG ( "SMBIOS structure type %d not found\n", type );
178  return -ENOENT;
179 }
180 
181 /**
182  * Copy SMBIOS structure
183  *
184  * @v structure SMBIOS structure descriptor
185  * @v data Buffer to hold SMBIOS structure
186  * @v len Length of buffer
187  * @ret rc Return status code
188  */
189 int read_smbios_structure ( struct smbios_structure *structure,
190  void *data, size_t len ) {
191 
192  assert ( smbios.address != UNULL );
193 
194  if ( len > structure->header.len )
195  len = structure->header.len;
196  copy_from_user ( data, smbios.address, structure->offset, len );
197  return 0;
198 }
199 
200 /**
201  * Find indexed string within SMBIOS structure
202  *
203  * @v structure SMBIOS structure descriptor
204  * @v index String index
205  * @v data Buffer for string
206  * @v len Length of string buffer
207  * @ret rc Length of string, or negative error
208  */
209 int read_smbios_string ( struct smbios_structure *structure,
210  unsigned int index, void *data, size_t len ) {
211  size_t strings_start = ( structure->offset + structure->header.len );
212  size_t strings_end = ( strings_start + structure->strings_len );
213  size_t offset;
214  size_t string_len;
215 
216  assert ( smbios.address != UNULL );
217 
218  /* String numbers start at 1 (0 is used to indicate "no string") */
219  if ( ! index )
220  return -ENOENT;
221 
222  for ( offset = strings_start ; offset < strings_end ;
223  offset += ( string_len + 1 ) ) {
224  /* Get string length. This is known safe, since the
225  * smbios_strings struct is constructed so as to
226  * always end on a string boundary.
227  */
228  string_len = strlen_user ( smbios.address, offset );
229  if ( --index == 0 ) {
230  /* Copy string, truncating as necessary. */
231  if ( len > string_len )
232  len = string_len;
234  return string_len;
235  }
236  }
237 
238  DBG ( "SMBIOS string index %d not found\n", index );
239  return -ENOENT;
240 }
241 
242 /**
243  * Get SMBIOS version
244  *
245  * @ret version Version, or negative error
246  */
247 int smbios_version ( void ) {
248  int rc;
249 
250  /* Find SMBIOS */
251  if ( ( smbios.address == UNULL ) &&
252  ( ( rc = find_smbios ( &smbios ) ) != 0 ) )
253  return rc;
254  assert ( smbios.address != UNULL );
255 
256  return smbios.version;
257 }
258 
259 /**
260  * Clear SMBIOS entry point descriptor
261  *
262  */
263 void smbios_clear ( void ) {
264 
265  /* Clear address */
266  smbios.address = UNULL;
267 }
size_t strings_len
Length of strings section.
Definition: smbios.h:135
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:213
Error codes.
#define SMBIOS_TYPE_END
SMBIOS end of table type.
Definition: smbios.h:199
uint8_t type
Type.
Definition: ena.h:16
static __always_inline void copy_from_user(void *dest, userptr_t src, off_t src_off, size_t len)
Copy data from user buffer.
Definition: uaccess.h:337
unsigned long user_to_phys(userptr_t userptr, off_t offset)
Convert user pointer to physical address.
int read_smbios_structure(struct smbios_structure *structure, void *data, size_t len)
Copy SMBIOS structure.
Definition: smbios.c:189
size_t len
Length of SMBIOS structures.
Definition: smbios.h:211
#define ENOENT
No such file or directory.
Definition: errno.h:514
SMBIOS entry point descriptor.
Definition: smbios.h:207
struct smbios_header header
Copy of SMBIOS structure header.
Definition: smbios.h:131
int find_smbios(struct smbios *smbios)
Access to external ("user") memory.
uint16_t version
SMBIOS version.
Definition: smbios.h:215
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
void smbios_clear(void)
Clear SMBIOS entry point descriptor.
Definition: smbios.c:263
uint32_t start
Starting offset.
Definition: netvsc.h:12
uint8_t len
Length.
Definition: smbios.h:123
int find_smbios_structure(unsigned int type, unsigned int instance, struct smbios_structure *structure)
Find specific structure type within SMBIOS.
Definition: smbios.c:118
Assertions.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
int find_smbios_entry(userptr_t start, size_t len, struct smbios_entry *entry)
Scan for SMBIOS entry point structure.
Definition: smbios.c:52
SMBIOS 32-bit entry point.
Definition: smbios.h:49
static userptr_t size_t offset
Offset of the first segment within the content.
Definition: deflate.h:259
int smbios_version(void)
Get SMBIOS version.
Definition: smbios.c:247
int read_smbios_string(struct smbios_structure *structure, unsigned int index, void *data, size_t len)
Find indexed string within SMBIOS structure.
Definition: smbios.c:209
union aes_table_entry entry[256]
Table entries, indexed by S(N)
Definition: aes.c:26
#define ENODEV
No such device.
Definition: errno.h:509
unsigned char uint8_t
Definition: stdint.h:10
System Management BIOS.
size_t strlen_user(userptr_t userptr, off_t offset)
Find length of NUL-terminated string in user buffer.
uint8_t type
Type.
Definition: smbios.h:121
#define UNULL
Equivalent of NULL for user pointers.
Definition: uaccess.h:36
uint32_t len
Length.
Definition: ena.h:14
userptr_t address
Start of SMBIOS structures.
Definition: smbios.h:209
uint16_t count
Number of entries.
Definition: ena.h:22
struct arbelprm_port_state_change_st data
Message.
Definition: arbel.h:12
uint64_t index
Index of the first segment within the content.
Definition: pccrc.h:21
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
SMBIOS structure descriptor.
Definition: smbios.h:129
String functions.
static size_t find_strings_terminator(size_t offset)
Find SMBIOS strings terminator.
Definition: smbios.c:98
size_t offset
Offset of structure within SMBIOS.
Definition: smbios.h:133
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33