|
|
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.