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  && ( 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  /* If this is the structure we want, return */
161  if ( ( structure->header.type == type ) &&
162  ( instance-- == 0 ) ) {
163  structure->offset = offset;
164  return 0;
165  }
166 
167  /* Move to next SMBIOS structure */
168  offset = ( terminator_offset + 1 );
169  count++;
170  }
171 
172  DBG ( "SMBIOS structure type %d not found\n", type );
173  return -ENOENT;
174 }
175 
176 /**
177  * Copy SMBIOS structure
178  *
179  * @v structure SMBIOS structure descriptor
180  * @v data Buffer to hold SMBIOS structure
181  * @v len Length of buffer
182  * @ret rc Return status code
183  */
184 int read_smbios_structure ( struct smbios_structure *structure,
185  void *data, size_t len ) {
186 
187  assert ( smbios.address != UNULL );
188 
189  if ( len > structure->header.len )
190  len = structure->header.len;
191  copy_from_user ( data, smbios.address, structure->offset, len );
192  return 0;
193 }
194 
195 /**
196  * Find indexed string within SMBIOS structure
197  *
198  * @v structure SMBIOS structure descriptor
199  * @v index String index
200  * @v data Buffer for string
201  * @v len Length of string buffer
202  * @ret rc Length of string, or negative error
203  */
204 int read_smbios_string ( struct smbios_structure *structure,
205  unsigned int index, void *data, size_t len ) {
206  size_t strings_start = ( structure->offset + structure->header.len );
207  size_t strings_end = ( strings_start + structure->strings_len );
208  size_t offset;
209  size_t string_len;
210 
211  assert ( smbios.address != UNULL );
212 
213  /* String numbers start at 1 (0 is used to indicate "no string") */
214  if ( ! index )
215  return -ENOENT;
216 
217  for ( offset = strings_start ; offset < strings_end ;
218  offset += ( string_len + 1 ) ) {
219  /* Get string length. This is known safe, since the
220  * smbios_strings struct is constructed so as to
221  * always end on a string boundary.
222  */
223  string_len = strlen_user ( smbios.address, offset );
224  if ( --index == 0 ) {
225  /* Copy string, truncating as necessary. */
226  if ( len > string_len )
227  len = string_len;
229  return string_len;
230  }
231  }
232 
233  DBG ( "SMBIOS string index %d not found\n", index );
234  return -ENOENT;
235 }
236 
237 /**
238  * Get SMBIOS version
239  *
240  * @ret version Version, or negative error
241  */
242 int smbios_version ( void ) {
243  int rc;
244 
245  /* Find SMBIOS */
246  if ( ( smbios.address == UNULL ) &&
247  ( ( rc = find_smbios ( &smbios ) ) != 0 ) )
248  return rc;
249  assert ( smbios.address != UNULL );
250 
251  return smbios.version;
252 }
size_t strings_len
Length of strings section.
Definition: smbios.h:95
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define SMBIOS_SIGNATURE
Signature for 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:170
Error codes.
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:184
size_t len
Length of SMBIOS structures.
Definition: smbios.h:168
#define ENOENT
No such file or directory.
Definition: errno.h:514
SMBIOS entry point descriptor.
Definition: smbios.h:164
struct smbios_header header
Copy of SMBIOS structure header.
Definition: smbios.h:91
int find_smbios(struct smbios *smbios)
Access to external ("user") memory.
uint16_t version
SMBIOS version.
Definition: smbios.h:172
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
uint32_t start
Starting offset.
Definition: netvsc.h:12
uint8_t len
Length.
Definition: smbios.h:83
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 entry point.
Definition: smbios.h:44
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:242
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:204
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:81
#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:166
uint16_t count
Number of entries.
Definition: ena.h:22
struct arbelprm_port_state_change_st data
Message.
Definition: arbel.h:12
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
uint64_t index
Index of the first segment within the content.
Definition: pccrc.h:21
SMBIOS structure descriptor.
Definition: smbios.h:89
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:93
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33