|
|
1.1 root 1: /*
2: * Copyright (C) 2007 Michael Brown <[email protected]>.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17: */
18:
19: FILE_LICENCE ( GPL2_OR_LATER );
20:
21: #include <stdint.h>
22: #include <string.h>
23: #include <errno.h>
24: #include <assert.h>
25: #include <ipxe/uaccess.h>
26: #include <ipxe/smbios.h>
27:
28: /** @file
29: *
30: * System Management BIOS
31: *
32: */
33:
34: /** SMBIOS entry point descriptor */
35: static struct smbios smbios = {
36: .address = UNULL,
37: };
38:
39: /**
40: * Find SMBIOS strings terminator
41: *
42: * @v offset Offset to start of strings
43: * @ret offset Offset to strings terminator, or 0 if not found
44: */
45: static size_t find_strings_terminator ( size_t offset ) {
46: size_t max_offset = ( smbios.len - 2 );
47: uint16_t nulnul;
48:
49: for ( ; offset <= max_offset ; offset++ ) {
50: copy_from_user ( &nulnul, smbios.address, offset, 2 );
51: if ( nulnul == 0 )
52: return ( offset + 1 );
53: }
54: return 0;
55: }
56:
57: /**
58: * Find specific structure type within SMBIOS
59: *
60: * @v type Structure type to search for
61: * @v structure SMBIOS structure descriptor to fill in
62: * @ret rc Return status code
63: */
64: int find_smbios_structure ( unsigned int type,
65: struct smbios_structure *structure ) {
66: unsigned int count = 0;
67: size_t offset = 0;
68: size_t strings_offset;
69: size_t terminator_offset;
70: int rc;
71:
72: /* Find SMBIOS */
73: if ( ( smbios.address == UNULL ) &&
74: ( ( rc = find_smbios ( &smbios ) ) != 0 ) )
75: return rc;
76: assert ( smbios.address != UNULL );
77:
78: /* Scan through list of structures */
79: while ( ( ( offset + sizeof ( structure->header ) ) < smbios.len )
80: && ( count < smbios.count ) ) {
81:
82: /* Read next SMBIOS structure header */
83: copy_from_user ( &structure->header, smbios.address, offset,
84: sizeof ( structure->header ) );
85:
86: /* Determine start and extent of strings block */
87: strings_offset = ( offset + structure->header.len );
88: if ( strings_offset > smbios.len ) {
89: DBG ( "SMBIOS structure at offset %zx with length "
90: "%x extends beyond SMBIOS\n", offset,
91: structure->header.len );
92: return -ENOENT;
93: }
94: terminator_offset = find_strings_terminator ( strings_offset );
95: if ( ! terminator_offset ) {
96: DBG ( "SMBIOS structure at offset %zx has "
97: "unterminated strings section\n", offset );
98: return -ENOENT;
99: }
100: structure->strings_len = ( terminator_offset - strings_offset);
101:
102: DBG ( "SMBIOS structure at offset %zx has type %d, length %x, "
103: "strings length %zx\n", offset, structure->header.type,
104: structure->header.len, structure->strings_len );
105:
106: /* If this is the structure we want, return */
107: if ( structure->header.type == type ) {
108: structure->offset = offset;
109: return 0;
110: }
111:
112: /* Move to next SMBIOS structure */
113: offset = ( terminator_offset + 1 );
114: count++;
115: }
116:
117: DBG ( "SMBIOS structure type %d not found\n", type );
118: return -ENOENT;
119: }
120:
121: /**
122: * Copy SMBIOS structure
123: *
124: * @v structure SMBIOS structure descriptor
125: * @v data Buffer to hold SMBIOS structure
126: * @v len Length of buffer
127: * @ret rc Return status code
128: */
129: int read_smbios_structure ( struct smbios_structure *structure,
130: void *data, size_t len ) {
131:
132: assert ( smbios.address != UNULL );
133:
134: if ( len > structure->header.len )
135: len = structure->header.len;
136: copy_from_user ( data, smbios.address, structure->offset, len );
137: return 0;
138: }
139:
140: /**
141: * Find indexed string within SMBIOS structure
142: *
143: * @v structure SMBIOS structure descriptor
144: * @v index String index
145: * @v data Buffer for string
146: * @v len Length of string buffer
147: * @ret rc Length of string, or negative error
148: */
149: int read_smbios_string ( struct smbios_structure *structure,
150: unsigned int index, void *data, size_t len ) {
151: size_t strings_start = ( structure->offset + structure->header.len );
152: size_t strings_end = ( strings_start + structure->strings_len );
153: size_t offset;
154: size_t string_len;
155:
156: assert ( smbios.address != UNULL );
157:
158: /* String numbers start at 1 (0 is used to indicate "no string") */
159: if ( ! index )
160: return -ENOENT;
161:
162: for ( offset = strings_start ; offset < strings_end ;
163: offset += ( string_len + 1 ) ) {
164: /* Get string length. This is known safe, since the
165: * smbios_strings struct is constructed so as to
166: * always end on a string boundary.
167: */
168: string_len = strlen_user ( smbios.address, offset );
169: if ( --index == 0 ) {
170: /* Copy string, truncating as necessary. */
171: if ( len > string_len )
172: len = string_len;
173: copy_from_user ( data, smbios.address, offset, len );
174: return string_len;
175: }
176: }
177:
178: DBG ( "SMBIOS string index %d not found\n", index );
179: return -ENOENT;
180: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.