source: bootcd/isolinux/syslinux-6.03/gpxe/src/interface/smbios/smbios.c @ 26ffad7

Last change on this file since 26ffad7 was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 5.0 KB
Line 
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19FILE_LICENCE ( GPL2_OR_LATER );
20
21#include <stdint.h>
22#include <string.h>
23#include <errno.h>
24#include <assert.h>
25#include <gpxe/uaccess.h>
26#include <gpxe/smbios.h>
27
28/** @file
29 *
30 * System Management BIOS
31 *
32 */
33
34/** SMBIOS entry point descriptor */
35static 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 */
45static 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 */
64int 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 */
129int 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 */
149int 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}
Note: See TracBrowser for help on using the repository browser.