You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

smbios.c 5.3KB

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