smbios.c
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021 #include <stdint.h>
00022 #include <string.h>
00023 #include <errno.h>
00024 #include <assert.h>
00025 #include <gpxe/uaccess.h>
00026 #include <gpxe/smbios.h>
00027
00028
00029
00030
00031
00032
00033
00034
00035 static struct smbios smbios = {
00036 .address = UNULL,
00037 };
00038
00039
00040
00041
00042
00043
00044
00045 static size_t find_strings_terminator ( size_t offset ) {
00046 size_t max_offset = ( smbios.len - 2 );
00047 uint16_t nulnul;
00048
00049 for ( ; offset <= max_offset ; offset++ ) {
00050 copy_from_user ( &nulnul, smbios.address, offset, 2 );
00051 if ( nulnul == 0 )
00052 return ( offset + 1 );
00053 }
00054 return 0;
00055 }
00056
00057
00058
00059
00060
00061
00062
00063
00064 int find_smbios_structure ( unsigned int type,
00065 struct smbios_structure *structure ) {
00066 unsigned int count = 0;
00067 size_t offset = 0;
00068 size_t strings_offset;
00069 size_t terminator_offset;
00070 int rc;
00071
00072
00073 if ( ( smbios.address == UNULL ) &&
00074 ( ( rc = find_smbios ( &smbios ) ) != 0 ) )
00075 return rc;
00076 assert ( smbios.address != UNULL );
00077
00078
00079 while ( ( ( offset + sizeof ( structure->header ) ) < smbios.len )
00080 && ( count < smbios.count ) ) {
00081
00082
00083 copy_from_user ( &structure->header, smbios.address, offset,
00084 sizeof ( structure->header ) );
00085
00086
00087 strings_offset = ( offset + structure->header.len );
00088 if ( strings_offset > smbios.len ) {
00089 DBG ( "SMBIOS structure at offset %zx with length "
00090 "%x extends beyond SMBIOS\n", offset,
00091 structure->header.len );
00092 return -ENOENT;
00093 }
00094 terminator_offset = find_strings_terminator ( strings_offset );
00095 if ( ! terminator_offset ) {
00096 DBG ( "SMBIOS structure at offset %zx has "
00097 "unterminated strings section\n", offset );
00098 return -ENOENT;
00099 }
00100 structure->strings_len = ( terminator_offset - strings_offset);
00101
00102 DBG ( "SMBIOS structure at offset %zx has type %d, length %x, "
00103 "strings length %zx\n", offset, structure->header.type,
00104 structure->header.len, structure->strings_len );
00105
00106
00107 if ( structure->header.type == type ) {
00108 structure->offset = offset;
00109 return 0;
00110 }
00111
00112
00113 offset = ( terminator_offset + 1 );
00114 count++;
00115 }
00116
00117 DBG ( "SMBIOS structure type %d not found\n", type );
00118 return -ENOENT;
00119 }
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 int read_smbios_structure ( struct smbios_structure *structure,
00130 void *data, size_t len ) {
00131
00132 assert ( smbios.address != UNULL );
00133
00134 if ( len > structure->header.len )
00135 len = structure->header.len;
00136 copy_from_user ( data, smbios.address, structure->offset, len );
00137 return 0;
00138 }
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 int read_smbios_string ( struct smbios_structure *structure,
00150 unsigned int index, void *data, size_t len ) {
00151 size_t strings_start = ( structure->offset + structure->header.len );
00152 size_t strings_end = ( strings_start + structure->strings_len );
00153 size_t offset;
00154 size_t string_len;
00155
00156 assert ( smbios.address != UNULL );
00157
00158
00159 if ( ! index )
00160 return -ENOENT;
00161
00162 for ( offset = strings_start ; offset < strings_end ;
00163 offset += ( string_len + 1 ) ) {
00164
00165
00166
00167
00168 string_len = strlen_user ( smbios.address, offset );
00169 if ( --index == 0 ) {
00170
00171 if ( len > string_len )
00172 len = string_len;
00173 copy_from_user ( data, smbios.address, offset, len );
00174 return string_len;
00175 }
00176 }
00177
00178 DBG ( "SMBIOS string index %d not found\n", index );
00179 return -ENOENT;
00180 }