186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* 286797937017f52bff088d02edf64fb931177a7eaJun Nakajima * SMBIOS Support 386797937017f52bff088d02edf64fb931177a7eaJun Nakajima * 486797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. 586797937017f52bff088d02edf64fb931177a7eaJun Nakajima * 686797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Authors: 786797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Alex Williamson <alex.williamson@hp.com> 886797937017f52bff088d02edf64fb931177a7eaJun Nakajima * 986797937017f52bff088d02edf64fb931177a7eaJun Nakajima * This work is licensed under the terms of the GNU GPL, version 2. See 1086797937017f52bff088d02edf64fb931177a7eaJun Nakajima * the COPYING file in the top-level directory. 1186797937017f52bff088d02edf64fb931177a7eaJun Nakajima * 1286797937017f52bff088d02edf64fb931177a7eaJun Nakajima */ 1386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 1486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "sysemu.h" 1586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "smbios.h" 1686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 1786797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* 1886797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Structures shared with the BIOS 1986797937017f52bff088d02edf64fb931177a7eaJun Nakajima */ 2086797937017f52bff088d02edf64fb931177a7eaJun Nakajimastruct smbios_header { 2186797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint16_t length; 2286797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint8_t type; 2386797937017f52bff088d02edf64fb931177a7eaJun Nakajima} __attribute__((__packed__)); 2486797937017f52bff088d02edf64fb931177a7eaJun Nakajima 2586797937017f52bff088d02edf64fb931177a7eaJun Nakajimastruct smbios_field { 2686797937017f52bff088d02edf64fb931177a7eaJun Nakajima struct smbios_header header; 2786797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint8_t type; 2886797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint16_t offset; 2986797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint8_t data[]; 3086797937017f52bff088d02edf64fb931177a7eaJun Nakajima} __attribute__((__packed__)); 3186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 3286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastruct smbios_table { 3386797937017f52bff088d02edf64fb931177a7eaJun Nakajima struct smbios_header header; 3486797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint8_t data[]; 3586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} __attribute__((__packed__)); 3686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 3786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SMBIOS_FIELD_ENTRY 0 3886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#define SMBIOS_TABLE_ENTRY 1 3986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 4086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 4186797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic uint8_t *smbios_entries; 4286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic size_t smbios_entries_len; 4386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 4486797937017f52bff088d02edf64fb931177a7eaJun Nakajimauint8_t *smbios_get_table(size_t *length) 4586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 4686797937017f52bff088d02edf64fb931177a7eaJun Nakajima *length = smbios_entries_len; 4786797937017f52bff088d02edf64fb931177a7eaJun Nakajima return smbios_entries; 4886797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 4986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 5086797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* 5186797937017f52bff088d02edf64fb931177a7eaJun Nakajima * To avoid unresolvable overlaps in data, don't allow both 5286797937017f52bff088d02edf64fb931177a7eaJun Nakajima * tables and fields for the same smbios type. 5386797937017f52bff088d02edf64fb931177a7eaJun Nakajima */ 5486797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void smbios_check_collision(int type, int entry) 5586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 5686797937017f52bff088d02edf64fb931177a7eaJun Nakajima uint16_t *num_entries = (uint16_t *)smbios_entries; 5786797937017f52bff088d02edf64fb931177a7eaJun Nakajima struct smbios_header *header; 5886797937017f52bff088d02edf64fb931177a7eaJun Nakajima char *p; 5986797937017f52bff088d02edf64fb931177a7eaJun Nakajima int i; 6086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 6186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!num_entries) 6286797937017f52bff088d02edf64fb931177a7eaJun Nakajima return; 6386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 6486797937017f52bff088d02edf64fb931177a7eaJun Nakajima p = (char *)(num_entries + 1); 6586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 6686797937017f52bff088d02edf64fb931177a7eaJun Nakajima for (i = 0; i < *num_entries; i++) { 6786797937017f52bff088d02edf64fb931177a7eaJun Nakajima header = (struct smbios_header *)p; 6886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (entry == SMBIOS_TABLE_ENTRY && header->type == SMBIOS_FIELD_ENTRY) { 6986797937017f52bff088d02edf64fb931177a7eaJun Nakajima struct smbios_field *field = (void *)header; 7086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (type == field->type) { 7186797937017f52bff088d02edf64fb931177a7eaJun Nakajima fprintf(stderr, "SMBIOS type %d field already defined, " 7286797937017f52bff088d02edf64fb931177a7eaJun Nakajima "cannot add table\n", type); 7386797937017f52bff088d02edf64fb931177a7eaJun Nakajima exit(1); 7486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 7586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } else if (entry == SMBIOS_FIELD_ENTRY && 7686797937017f52bff088d02edf64fb931177a7eaJun Nakajima header->type == SMBIOS_TABLE_ENTRY) { 7786797937017f52bff088d02edf64fb931177a7eaJun Nakajima struct smbios_structure_header *table = (void *)(header + 1); 7886797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (type == table->type) { 7986797937017f52bff088d02edf64fb931177a7eaJun Nakajima fprintf(stderr, "SMBIOS type %d table already defined, " 8086797937017f52bff088d02edf64fb931177a7eaJun Nakajima "cannot add field\n", type); 8186797937017f52bff088d02edf64fb931177a7eaJun Nakajima exit(1); 8286797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 8386797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 8486797937017f52bff088d02edf64fb931177a7eaJun Nakajima p += le16_to_cpu(header->length); 8586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 8686797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 8786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 8886797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid smbios_add_field(int type, int offset, int len, void *data) 8986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 9086797937017f52bff088d02edf64fb931177a7eaJun Nakajima struct smbios_field *field; 9186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 9286797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_check_collision(type, SMBIOS_FIELD_ENTRY); 9386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 9486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!smbios_entries) { 9586797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_entries_len = sizeof(uint16_t); 9686797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_entries = qemu_mallocz(smbios_entries_len); 9786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 9886797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_entries = qemu_realloc(smbios_entries, smbios_entries_len + 9986797937017f52bff088d02edf64fb931177a7eaJun Nakajima sizeof(*field) + len); 10086797937017f52bff088d02edf64fb931177a7eaJun Nakajima field = (struct smbios_field *)(smbios_entries + smbios_entries_len); 10186797937017f52bff088d02edf64fb931177a7eaJun Nakajima field->header.type = SMBIOS_FIELD_ENTRY; 10286797937017f52bff088d02edf64fb931177a7eaJun Nakajima field->header.length = cpu_to_le16(sizeof(*field) + len); 10386797937017f52bff088d02edf64fb931177a7eaJun Nakajima 10486797937017f52bff088d02edf64fb931177a7eaJun Nakajima field->type = type; 10586797937017f52bff088d02edf64fb931177a7eaJun Nakajima field->offset = cpu_to_le16(offset); 10686797937017f52bff088d02edf64fb931177a7eaJun Nakajima memcpy(field->data, data, len); 10786797937017f52bff088d02edf64fb931177a7eaJun Nakajima 10886797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_entries_len += sizeof(*field) + len; 10986797937017f52bff088d02edf64fb931177a7eaJun Nakajima (*(uint16_t *)smbios_entries) = 11086797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); 11186797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 11286797937017f52bff088d02edf64fb931177a7eaJun Nakajima 11386797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void smbios_build_type_0_fields(const char *t) 11486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 11586797937017f52bff088d02edf64fb931177a7eaJun Nakajima char buf[1024]; 11686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 11786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (get_param_value(buf, sizeof(buf), "vendor", t)) 11886797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_add_field(0, offsetof(struct smbios_type_0, vendor_str), 11986797937017f52bff088d02edf64fb931177a7eaJun Nakajima strlen(buf) + 1, buf); 12086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (get_param_value(buf, sizeof(buf), "version", t)) 12186797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_add_field(0, offsetof(struct smbios_type_0, bios_version_str), 12286797937017f52bff088d02edf64fb931177a7eaJun Nakajima strlen(buf) + 1, buf); 12386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (get_param_value(buf, sizeof(buf), "date", t)) 12486797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_add_field(0, offsetof(struct smbios_type_0, 12586797937017f52bff088d02edf64fb931177a7eaJun Nakajima bios_release_date_str), 12686797937017f52bff088d02edf64fb931177a7eaJun Nakajima strlen(buf) + 1, buf); 12786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (get_param_value(buf, sizeof(buf), "release", t)) { 12886797937017f52bff088d02edf64fb931177a7eaJun Nakajima int major, minor; 12986797937017f52bff088d02edf64fb931177a7eaJun Nakajima sscanf(buf, "%d.%d", &major, &minor); 13086797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_add_field(0, offsetof(struct smbios_type_0, 13186797937017f52bff088d02edf64fb931177a7eaJun Nakajima system_bios_major_release), 1, &major); 13286797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_add_field(0, offsetof(struct smbios_type_0, 13386797937017f52bff088d02edf64fb931177a7eaJun Nakajima system_bios_minor_release), 1, &minor); 13486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 13586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 13686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 13786797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void smbios_build_type_1_fields(const char *t) 13886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 13986797937017f52bff088d02edf64fb931177a7eaJun Nakajima char buf[1024]; 14086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 14186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (get_param_value(buf, sizeof(buf), "manufacturer", t)) 14286797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_add_field(1, offsetof(struct smbios_type_1, manufacturer_str), 14386797937017f52bff088d02edf64fb931177a7eaJun Nakajima strlen(buf) + 1, buf); 14486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (get_param_value(buf, sizeof(buf), "product", t)) 14586797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_add_field(1, offsetof(struct smbios_type_1, product_name_str), 14686797937017f52bff088d02edf64fb931177a7eaJun Nakajima strlen(buf) + 1, buf); 14786797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (get_param_value(buf, sizeof(buf), "version", t)) 14886797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_add_field(1, offsetof(struct smbios_type_1, version_str), 14986797937017f52bff088d02edf64fb931177a7eaJun Nakajima strlen(buf) + 1, buf); 15086797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (get_param_value(buf, sizeof(buf), "serial", t)) 15186797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_add_field(1, offsetof(struct smbios_type_1, serial_number_str), 15286797937017f52bff088d02edf64fb931177a7eaJun Nakajima strlen(buf) + 1, buf); 15386797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (get_param_value(buf, sizeof(buf), "uuid", t)) { 15486797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (qemu_uuid_parse(buf, qemu_uuid) != 0) { 15586797937017f52bff088d02edf64fb931177a7eaJun Nakajima fprintf(stderr, "Invalid SMBIOS UUID string\n"); 15686797937017f52bff088d02edf64fb931177a7eaJun Nakajima exit(1); 15786797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 15886797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 15986797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (get_param_value(buf, sizeof(buf), "sku", t)) 16086797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_add_field(1, offsetof(struct smbios_type_1, sku_number_str), 16186797937017f52bff088d02edf64fb931177a7eaJun Nakajima strlen(buf) + 1, buf); 16286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (get_param_value(buf, sizeof(buf), "family", t)) 16386797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_add_field(1, offsetof(struct smbios_type_1, family_str), 16486797937017f52bff088d02edf64fb931177a7eaJun Nakajima strlen(buf) + 1, buf); 16586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 16686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 16786797937017f52bff088d02edf64fb931177a7eaJun Nakajimaint smbios_entry_add(const char *t) 16886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{ 16986797937017f52bff088d02edf64fb931177a7eaJun Nakajima char buf[1024]; 17086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 17186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (get_param_value(buf, sizeof(buf), "file", t)) { 17286797937017f52bff088d02edf64fb931177a7eaJun Nakajima struct smbios_structure_header *header; 17386797937017f52bff088d02edf64fb931177a7eaJun Nakajima struct smbios_table *table; 17486797937017f52bff088d02edf64fb931177a7eaJun Nakajima int size = get_image_size(buf); 17586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 17686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (size < sizeof(struct smbios_structure_header)) { 17786797937017f52bff088d02edf64fb931177a7eaJun Nakajima fprintf(stderr, "Cannot read smbios file %s", buf); 17886797937017f52bff088d02edf64fb931177a7eaJun Nakajima exit(1); 17986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 18086797937017f52bff088d02edf64fb931177a7eaJun Nakajima 18186797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (!smbios_entries) { 18286797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_entries_len = sizeof(uint16_t); 18386797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_entries = qemu_mallocz(smbios_entries_len); 18486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 18586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 18686797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_entries = qemu_realloc(smbios_entries, smbios_entries_len + 18786797937017f52bff088d02edf64fb931177a7eaJun Nakajima sizeof(*table) + size); 18886797937017f52bff088d02edf64fb931177a7eaJun Nakajima table = (struct smbios_table *)(smbios_entries + smbios_entries_len); 18986797937017f52bff088d02edf64fb931177a7eaJun Nakajima table->header.type = SMBIOS_TABLE_ENTRY; 19086797937017f52bff088d02edf64fb931177a7eaJun Nakajima table->header.length = cpu_to_le16(sizeof(*table) + size); 19186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 19286797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (load_image(buf, table->data) != size) { 19386797937017f52bff088d02edf64fb931177a7eaJun Nakajima fprintf(stderr, "Failed to load smbios file %s", buf); 19486797937017f52bff088d02edf64fb931177a7eaJun Nakajima exit(1); 19586797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 19686797937017f52bff088d02edf64fb931177a7eaJun Nakajima 19786797937017f52bff088d02edf64fb931177a7eaJun Nakajima header = (struct smbios_structure_header *)(table->data); 19886797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_check_collision(header->type, SMBIOS_TABLE_ENTRY); 19986797937017f52bff088d02edf64fb931177a7eaJun Nakajima 20086797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_entries_len += sizeof(*table) + size; 20186797937017f52bff088d02edf64fb931177a7eaJun Nakajima (*(uint16_t *)smbios_entries) = 20286797937017f52bff088d02edf64fb931177a7eaJun Nakajima cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); 20386797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 0; 20486797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 20586797937017f52bff088d02edf64fb931177a7eaJun Nakajima 20686797937017f52bff088d02edf64fb931177a7eaJun Nakajima if (get_param_value(buf, sizeof(buf), "type", t)) { 20786797937017f52bff088d02edf64fb931177a7eaJun Nakajima unsigned long type = strtoul(buf, NULL, 0); 20886797937017f52bff088d02edf64fb931177a7eaJun Nakajima switch (type) { 20986797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 0: 21086797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_build_type_0_fields(t); 21186797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 0; 21286797937017f52bff088d02edf64fb931177a7eaJun Nakajima case 1: 21386797937017f52bff088d02edf64fb931177a7eaJun Nakajima smbios_build_type_1_fields(t); 21486797937017f52bff088d02edf64fb931177a7eaJun Nakajima return 0; 21586797937017f52bff088d02edf64fb931177a7eaJun Nakajima default: 21686797937017f52bff088d02edf64fb931177a7eaJun Nakajima fprintf(stderr, "Don't know how to build fields for SMBIOS type " 21786797937017f52bff088d02edf64fb931177a7eaJun Nakajima "%ld\n", type); 21886797937017f52bff088d02edf64fb931177a7eaJun Nakajima exit(1); 21986797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 22086797937017f52bff088d02edf64fb931177a7eaJun Nakajima } 22186797937017f52bff088d02edf64fb931177a7eaJun Nakajima 22286797937017f52bff088d02edf64fb931177a7eaJun Nakajima fprintf(stderr, "smbios: must specify type= or file=\n"); 22386797937017f52bff088d02edf64fb931177a7eaJun Nakajima return -1; 22486797937017f52bff088d02edf64fb931177a7eaJun Nakajima} 225