2
0

smbios_legacy.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * SMBIOS legacy support
  3. *
  4. * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  5. * Copyright (C) 2013 Red Hat, Inc.
  6. *
  7. * Authors:
  8. * Alex Williamson <alex.williamson@hp.com>
  9. * Markus Armbruster <armbru@redhat.com>
  10. *
  11. * This work is licensed under the terms of the GNU GPL, version 2. See
  12. * the COPYING file in the top-level directory.
  13. *
  14. * Contributions after 2012-01-13 are licensed under the terms of the
  15. * GNU GPL, version 2 or (at your option) any later version.
  16. */
  17. #include "qemu/osdep.h"
  18. #include "qemu/bswap.h"
  19. #include "hw/firmware/smbios.h"
  20. #include "system/system.h"
  21. #include "qapi/error.h"
  22. struct smbios_header {
  23. uint16_t length;
  24. uint8_t type;
  25. } QEMU_PACKED;
  26. struct smbios_field {
  27. struct smbios_header header;
  28. uint8_t type;
  29. uint16_t offset;
  30. uint8_t data[];
  31. } QEMU_PACKED;
  32. struct smbios_table {
  33. struct smbios_header header;
  34. uint8_t data[];
  35. } QEMU_PACKED;
  36. #define SMBIOS_FIELD_ENTRY 0
  37. #define SMBIOS_TABLE_ENTRY 1
  38. static uint8_t *smbios_entries;
  39. static size_t smbios_entries_len;
  40. GArray *usr_blobs_sizes;
  41. void smbios_add_usr_blob_size(size_t size)
  42. {
  43. if (!usr_blobs_sizes) {
  44. usr_blobs_sizes = g_array_new(false, false, sizeof(size_t));
  45. }
  46. g_array_append_val(usr_blobs_sizes, size);
  47. }
  48. static void smbios_add_field(int type, int offset, const void *data, size_t len)
  49. {
  50. struct smbios_field *field;
  51. if (!smbios_entries) {
  52. smbios_entries_len = sizeof(uint16_t);
  53. smbios_entries = g_malloc0(smbios_entries_len);
  54. }
  55. smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
  56. sizeof(*field) + len);
  57. field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
  58. field->header.type = SMBIOS_FIELD_ENTRY;
  59. field->header.length = cpu_to_le16(sizeof(*field) + len);
  60. field->type = type;
  61. field->offset = cpu_to_le16(offset);
  62. memcpy(field->data, data, len);
  63. smbios_entries_len += sizeof(*field) + len;
  64. (*(uint16_t *)smbios_entries) =
  65. cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
  66. }
  67. static void smbios_maybe_add_str(int type, int offset, const char *data)
  68. {
  69. if (data) {
  70. smbios_add_field(type, offset, data, strlen(data) + 1);
  71. }
  72. }
  73. static void smbios_build_type_0_fields(void)
  74. {
  75. smbios_maybe_add_str(0, offsetof(struct smbios_type_0, vendor_str),
  76. smbios_type0.vendor);
  77. smbios_maybe_add_str(0, offsetof(struct smbios_type_0, bios_version_str),
  78. smbios_type0.version);
  79. smbios_maybe_add_str(0, offsetof(struct smbios_type_0,
  80. bios_release_date_str),
  81. smbios_type0.date);
  82. if (smbios_type0.have_major_minor) {
  83. smbios_add_field(0, offsetof(struct smbios_type_0,
  84. system_bios_major_release),
  85. &smbios_type0.major, 1);
  86. smbios_add_field(0, offsetof(struct smbios_type_0,
  87. system_bios_minor_release),
  88. &smbios_type0.minor, 1);
  89. }
  90. }
  91. static void smbios_build_type_1_fields(void)
  92. {
  93. smbios_maybe_add_str(1, offsetof(struct smbios_type_1, manufacturer_str),
  94. smbios_type1.manufacturer);
  95. smbios_maybe_add_str(1, offsetof(struct smbios_type_1, product_name_str),
  96. smbios_type1.product);
  97. smbios_maybe_add_str(1, offsetof(struct smbios_type_1, version_str),
  98. smbios_type1.version);
  99. smbios_maybe_add_str(1, offsetof(struct smbios_type_1, serial_number_str),
  100. smbios_type1.serial);
  101. smbios_maybe_add_str(1, offsetof(struct smbios_type_1, sku_number_str),
  102. smbios_type1.sku);
  103. smbios_maybe_add_str(1, offsetof(struct smbios_type_1, family_str),
  104. smbios_type1.family);
  105. if (qemu_uuid_set) {
  106. /*
  107. * We don't encode the UUID in the "wire format" here because this
  108. * function is for legacy mode and needs to keep the guest ABI, and
  109. * because we don't know what's the SMBIOS version advertised by the
  110. * BIOS.
  111. */
  112. smbios_add_field(1, offsetof(struct smbios_type_1, uuid),
  113. &qemu_uuid, 16);
  114. }
  115. }
  116. uint8_t *smbios_get_table_legacy(size_t *length, Error **errp)
  117. {
  118. int i;
  119. size_t usr_offset;
  120. /* complain if fields were given for types > 1 */
  121. if (find_next_bit(smbios_have_fields_bitmap,
  122. SMBIOS_MAX_TYPE + 1, 2) < SMBIOS_MAX_TYPE + 1) {
  123. error_setg(errp, "can't process fields for smbios "
  124. "types > 1 on machine versions < 2.1!");
  125. goto err_exit;
  126. }
  127. if (test_bit(4, smbios_have_binfile_bitmap)) {
  128. error_setg(errp, "can't process table for smbios "
  129. "type 4 on machine versions < 2.1!");
  130. goto err_exit;
  131. }
  132. g_free(smbios_entries);
  133. smbios_entries_len = sizeof(uint16_t);
  134. smbios_entries = g_malloc0(smbios_entries_len);
  135. /*
  136. * build a set of legacy smbios_table entries using user provided blobs
  137. */
  138. for (i = 0, usr_offset = 0; usr_blobs_sizes && i < usr_blobs_sizes->len;
  139. i++)
  140. {
  141. struct smbios_table *table;
  142. struct smbios_structure_header *header;
  143. size_t size = g_array_index(usr_blobs_sizes, size_t, i);
  144. header = (struct smbios_structure_header *)(usr_blobs + usr_offset);
  145. smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
  146. size + sizeof(*table));
  147. table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
  148. table->header.type = SMBIOS_TABLE_ENTRY;
  149. table->header.length = cpu_to_le16(sizeof(*table) + size);
  150. memcpy(table->data, header, size);
  151. smbios_entries_len += sizeof(*table) + size;
  152. /*
  153. * update number of entries in the blob,
  154. * see SeaBIOS: qemu_cfg_legacy():QEMU_CFG_SMBIOS_ENTRIES
  155. */
  156. (*(uint16_t *)smbios_entries) =
  157. cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
  158. usr_offset += size;
  159. }
  160. smbios_build_type_0_fields();
  161. smbios_build_type_1_fields();
  162. if (!smbios_validate_table(SMBIOS_ENTRY_POINT_TYPE_32, errp)) {
  163. goto err_exit;
  164. }
  165. *length = smbios_entries_len;
  166. return smbios_entries;
  167. err_exit:
  168. g_free(smbios_entries);
  169. return NULL;
  170. }