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 18 #include "qemu/osdep.h" 19 #include "qemu/bswap.h" 20 #include "hw/firmware/smbios.h" 21 #include "sysemu/sysemu.h" 22 #include "qapi/error.h" 23 24 struct smbios_header { 25 uint16_t length; 26 uint8_t type; 27 } QEMU_PACKED; 28 29 struct smbios_field { 30 struct smbios_header header; 31 uint8_t type; 32 uint16_t offset; 33 uint8_t data[]; 34 } QEMU_PACKED; 35 36 struct smbios_table { 37 struct smbios_header header; 38 uint8_t data[]; 39 } QEMU_PACKED; 40 41 #define SMBIOS_FIELD_ENTRY 0 42 #define SMBIOS_TABLE_ENTRY 1 43 44 static uint8_t *smbios_entries; 45 static size_t smbios_entries_len; 46 GArray *usr_blobs_sizes; 47 48 void smbios_add_usr_blob_size(size_t size) 49 { 50 if (!usr_blobs_sizes) { 51 usr_blobs_sizes = g_array_new(false, false, sizeof(size_t)); 52 } 53 g_array_append_val(usr_blobs_sizes, size); 54 } 55 56 static void smbios_add_field(int type, int offset, const void *data, size_t len) 57 { 58 struct smbios_field *field; 59 60 if (!smbios_entries) { 61 smbios_entries_len = sizeof(uint16_t); 62 smbios_entries = g_malloc0(smbios_entries_len); 63 } 64 smbios_entries = g_realloc(smbios_entries, smbios_entries_len + 65 sizeof(*field) + len); 66 field = (struct smbios_field *)(smbios_entries + smbios_entries_len); 67 field->header.type = SMBIOS_FIELD_ENTRY; 68 field->header.length = cpu_to_le16(sizeof(*field) + len); 69 70 field->type = type; 71 field->offset = cpu_to_le16(offset); 72 memcpy(field->data, data, len); 73 74 smbios_entries_len += sizeof(*field) + len; 75 (*(uint16_t *)smbios_entries) = 76 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); 77 } 78 79 static void smbios_maybe_add_str(int type, int offset, const char *data) 80 { 81 if (data) { 82 smbios_add_field(type, offset, data, strlen(data) + 1); 83 } 84 } 85 86 static void smbios_build_type_0_fields(void) 87 { 88 smbios_maybe_add_str(0, offsetof(struct smbios_type_0, vendor_str), 89 smbios_type0.vendor); 90 smbios_maybe_add_str(0, offsetof(struct smbios_type_0, bios_version_str), 91 smbios_type0.version); 92 smbios_maybe_add_str(0, offsetof(struct smbios_type_0, 93 bios_release_date_str), 94 smbios_type0.date); 95 if (smbios_type0.have_major_minor) { 96 smbios_add_field(0, offsetof(struct smbios_type_0, 97 system_bios_major_release), 98 &smbios_type0.major, 1); 99 smbios_add_field(0, offsetof(struct smbios_type_0, 100 system_bios_minor_release), 101 &smbios_type0.minor, 1); 102 } 103 } 104 105 static void smbios_build_type_1_fields(void) 106 { 107 smbios_maybe_add_str(1, offsetof(struct smbios_type_1, manufacturer_str), 108 smbios_type1.manufacturer); 109 smbios_maybe_add_str(1, offsetof(struct smbios_type_1, product_name_str), 110 smbios_type1.product); 111 smbios_maybe_add_str(1, offsetof(struct smbios_type_1, version_str), 112 smbios_type1.version); 113 smbios_maybe_add_str(1, offsetof(struct smbios_type_1, serial_number_str), 114 smbios_type1.serial); 115 smbios_maybe_add_str(1, offsetof(struct smbios_type_1, sku_number_str), 116 smbios_type1.sku); 117 smbios_maybe_add_str(1, offsetof(struct smbios_type_1, family_str), 118 smbios_type1.family); 119 if (qemu_uuid_set) { 120 /* 121 * We don't encode the UUID in the "wire format" here because this 122 * function is for legacy mode and needs to keep the guest ABI, and 123 * because we don't know what's the SMBIOS version advertised by the 124 * BIOS. 125 */ 126 smbios_add_field(1, offsetof(struct smbios_type_1, uuid), 127 &qemu_uuid, 16); 128 } 129 } 130 131 uint8_t *smbios_get_table_legacy(size_t *length, Error **errp) 132 { 133 int i; 134 size_t usr_offset; 135 136 /* complain if fields were given for types > 1 */ 137 if (find_next_bit(smbios_have_fields_bitmap, 138 SMBIOS_MAX_TYPE + 1, 2) < SMBIOS_MAX_TYPE + 1) { 139 error_setg(errp, "can't process fields for smbios " 140 "types > 1 on machine versions < 2.1!"); 141 goto err_exit; 142 } 143 144 if (test_bit(4, smbios_have_binfile_bitmap)) { 145 error_setg(errp, "can't process table for smbios " 146 "type 4 on machine versions < 2.1!"); 147 goto err_exit; 148 } 149 150 g_free(smbios_entries); 151 smbios_entries_len = sizeof(uint16_t); 152 smbios_entries = g_malloc0(smbios_entries_len); 153 154 /* 155 * build a set of legacy smbios_table entries using user provided blobs 156 */ 157 for (i = 0, usr_offset = 0; usr_blobs_sizes && i < usr_blobs_sizes->len; 158 i++) 159 { 160 struct smbios_table *table; 161 struct smbios_structure_header *header; 162 size_t size = g_array_index(usr_blobs_sizes, size_t, i); 163 164 header = (struct smbios_structure_header *)(usr_blobs + usr_offset); 165 smbios_entries = g_realloc(smbios_entries, smbios_entries_len + 166 size + sizeof(*table)); 167 table = (struct smbios_table *)(smbios_entries + smbios_entries_len); 168 table->header.type = SMBIOS_TABLE_ENTRY; 169 table->header.length = cpu_to_le16(sizeof(*table) + size); 170 memcpy(table->data, header, size); 171 smbios_entries_len += sizeof(*table) + size; 172 /* 173 * update number of entries in the blob, 174 * see SeaBIOS: qemu_cfg_legacy():QEMU_CFG_SMBIOS_ENTRIES 175 */ 176 (*(uint16_t *)smbios_entries) = 177 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); 178 usr_offset += size; 179 } 180 181 smbios_build_type_0_fields(); 182 smbios_build_type_1_fields(); 183 if (!smbios_validate_table(SMBIOS_ENTRY_POINT_TYPE_32, errp)) { 184 goto err_exit; 185 } 186 187 *length = smbios_entries_len; 188 return smbios_entries; 189 err_exit: 190 g_free(smbios_entries); 191 return NULL; 192 } 193