smbios.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * SMBIOS Support
  3. *
  4. * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  5. *
  6. * Authors:
  7. * Alex Williamson <alex.williamson@hp.com>
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2. See
  10. * the COPYING file in the top-level directory.
  11. *
  12. * Contributions after 2012-01-13 are licensed under the terms of the
  13. * GNU GPL, version 2 or (at your option) any later version.
  14. */
  15. #include "sysemu/sysemu.h"
  16. #include "smbios.h"
  17. #include "loader.h"
  18. /*
  19. * Structures shared with the BIOS
  20. */
  21. struct smbios_header {
  22. uint16_t length;
  23. uint8_t type;
  24. } QEMU_PACKED;
  25. struct smbios_field {
  26. struct smbios_header header;
  27. uint8_t type;
  28. uint16_t offset;
  29. uint8_t data[];
  30. } QEMU_PACKED;
  31. struct smbios_table {
  32. struct smbios_header header;
  33. uint8_t data[];
  34. } QEMU_PACKED;
  35. #define SMBIOS_FIELD_ENTRY 0
  36. #define SMBIOS_TABLE_ENTRY 1
  37. static uint8_t *smbios_entries;
  38. static size_t smbios_entries_len;
  39. static int smbios_type4_count = 0;
  40. static void smbios_validate_table(void)
  41. {
  42. if (smbios_type4_count && smbios_type4_count != smp_cpus) {
  43. fprintf(stderr,
  44. "Number of SMBIOS Type 4 tables must match cpu count.\n");
  45. exit(1);
  46. }
  47. }
  48. uint8_t *smbios_get_table(size_t *length)
  49. {
  50. smbios_validate_table();
  51. *length = smbios_entries_len;
  52. return smbios_entries;
  53. }
  54. /*
  55. * To avoid unresolvable overlaps in data, don't allow both
  56. * tables and fields for the same smbios type.
  57. */
  58. static void smbios_check_collision(int type, int entry)
  59. {
  60. uint16_t *num_entries = (uint16_t *)smbios_entries;
  61. struct smbios_header *header;
  62. char *p;
  63. int i;
  64. if (!num_entries)
  65. return;
  66. p = (char *)(num_entries + 1);
  67. for (i = 0; i < *num_entries; i++) {
  68. header = (struct smbios_header *)p;
  69. if (entry == SMBIOS_TABLE_ENTRY && header->type == SMBIOS_FIELD_ENTRY) {
  70. struct smbios_field *field = (void *)header;
  71. if (type == field->type) {
  72. fprintf(stderr, "SMBIOS type %d field already defined, "
  73. "cannot add table\n", type);
  74. exit(1);
  75. }
  76. } else if (entry == SMBIOS_FIELD_ENTRY &&
  77. header->type == SMBIOS_TABLE_ENTRY) {
  78. struct smbios_structure_header *table = (void *)(header + 1);
  79. if (type == table->type) {
  80. fprintf(stderr, "SMBIOS type %d table already defined, "
  81. "cannot add field\n", type);
  82. exit(1);
  83. }
  84. }
  85. p += le16_to_cpu(header->length);
  86. }
  87. }
  88. void smbios_add_field(int type, int offset, int len, void *data)
  89. {
  90. struct smbios_field *field;
  91. smbios_check_collision(type, SMBIOS_FIELD_ENTRY);
  92. if (!smbios_entries) {
  93. smbios_entries_len = sizeof(uint16_t);
  94. smbios_entries = g_malloc0(smbios_entries_len);
  95. }
  96. smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
  97. sizeof(*field) + len);
  98. field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
  99. field->header.type = SMBIOS_FIELD_ENTRY;
  100. field->header.length = cpu_to_le16(sizeof(*field) + len);
  101. field->type = type;
  102. field->offset = cpu_to_le16(offset);
  103. memcpy(field->data, data, len);
  104. smbios_entries_len += sizeof(*field) + len;
  105. (*(uint16_t *)smbios_entries) =
  106. cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
  107. }
  108. static void smbios_build_type_0_fields(const char *t)
  109. {
  110. char buf[1024];
  111. if (get_param_value(buf, sizeof(buf), "vendor", t))
  112. smbios_add_field(0, offsetof(struct smbios_type_0, vendor_str),
  113. strlen(buf) + 1, buf);
  114. if (get_param_value(buf, sizeof(buf), "version", t))
  115. smbios_add_field(0, offsetof(struct smbios_type_0, bios_version_str),
  116. strlen(buf) + 1, buf);
  117. if (get_param_value(buf, sizeof(buf), "date", t))
  118. smbios_add_field(0, offsetof(struct smbios_type_0,
  119. bios_release_date_str),
  120. strlen(buf) + 1, buf);
  121. if (get_param_value(buf, sizeof(buf), "release", t)) {
  122. int major, minor;
  123. sscanf(buf, "%d.%d", &major, &minor);
  124. smbios_add_field(0, offsetof(struct smbios_type_0,
  125. system_bios_major_release), 1, &major);
  126. smbios_add_field(0, offsetof(struct smbios_type_0,
  127. system_bios_minor_release), 1, &minor);
  128. }
  129. }
  130. static void smbios_build_type_1_fields(const char *t)
  131. {
  132. char buf[1024];
  133. if (get_param_value(buf, sizeof(buf), "manufacturer", t))
  134. smbios_add_field(1, offsetof(struct smbios_type_1, manufacturer_str),
  135. strlen(buf) + 1, buf);
  136. if (get_param_value(buf, sizeof(buf), "product", t))
  137. smbios_add_field(1, offsetof(struct smbios_type_1, product_name_str),
  138. strlen(buf) + 1, buf);
  139. if (get_param_value(buf, sizeof(buf), "version", t))
  140. smbios_add_field(1, offsetof(struct smbios_type_1, version_str),
  141. strlen(buf) + 1, buf);
  142. if (get_param_value(buf, sizeof(buf), "serial", t))
  143. smbios_add_field(1, offsetof(struct smbios_type_1, serial_number_str),
  144. strlen(buf) + 1, buf);
  145. if (get_param_value(buf, sizeof(buf), "uuid", t)) {
  146. if (qemu_uuid_parse(buf, qemu_uuid) != 0) {
  147. fprintf(stderr, "Invalid SMBIOS UUID string\n");
  148. exit(1);
  149. }
  150. }
  151. if (get_param_value(buf, sizeof(buf), "sku", t))
  152. smbios_add_field(1, offsetof(struct smbios_type_1, sku_number_str),
  153. strlen(buf) + 1, buf);
  154. if (get_param_value(buf, sizeof(buf), "family", t))
  155. smbios_add_field(1, offsetof(struct smbios_type_1, family_str),
  156. strlen(buf) + 1, buf);
  157. }
  158. int smbios_entry_add(const char *t)
  159. {
  160. char buf[1024];
  161. if (get_param_value(buf, sizeof(buf), "file", t)) {
  162. struct smbios_structure_header *header;
  163. struct smbios_table *table;
  164. int size = get_image_size(buf);
  165. if (size == -1 || size < sizeof(struct smbios_structure_header)) {
  166. fprintf(stderr, "Cannot read smbios file %s\n", buf);
  167. exit(1);
  168. }
  169. if (!smbios_entries) {
  170. smbios_entries_len = sizeof(uint16_t);
  171. smbios_entries = g_malloc0(smbios_entries_len);
  172. }
  173. smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
  174. sizeof(*table) + size);
  175. table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
  176. table->header.type = SMBIOS_TABLE_ENTRY;
  177. table->header.length = cpu_to_le16(sizeof(*table) + size);
  178. if (load_image(buf, table->data) != size) {
  179. fprintf(stderr, "Failed to load smbios file %s", buf);
  180. exit(1);
  181. }
  182. header = (struct smbios_structure_header *)(table->data);
  183. smbios_check_collision(header->type, SMBIOS_TABLE_ENTRY);
  184. if (header->type == 4) {
  185. smbios_type4_count++;
  186. }
  187. smbios_entries_len += sizeof(*table) + size;
  188. (*(uint16_t *)smbios_entries) =
  189. cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
  190. return 0;
  191. }
  192. if (get_param_value(buf, sizeof(buf), "type", t)) {
  193. unsigned long type = strtoul(buf, NULL, 0);
  194. switch (type) {
  195. case 0:
  196. smbios_build_type_0_fields(t);
  197. return 0;
  198. case 1:
  199. smbios_build_type_1_fields(t);
  200. return 0;
  201. default:
  202. fprintf(stderr, "Don't know how to build fields for SMBIOS type "
  203. "%ld\n", type);
  204. exit(1);
  205. }
  206. }
  207. fprintf(stderr, "smbios: must specify type= or file=\n");
  208. return -1;
  209. }