smbios.c 7.6 KB

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