📄 smbios.c
字号:
/* * smbios.c - Generate SMBIOS tables for Xen HVM domU's. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Copyright (C) IBM Corporation, 2006 * * Authors: Andrew D. Ball <aball@us.ibm.com> */#include <stdint.h>#include <xen/version.h>#include "smbios_types.h"#include "util.h"#include "hypercall.h"#include "e820.h"static intwrite_smbios_tables(void *start, uint32_t vcpus, uint64_t memsize, uint8_t uuid[16], char *xen_version, uint32_t xen_major_version, uint32_t xen_minor_version);static voidget_cpu_manufacturer(char *buf, int len);static voidsmbios_entry_point_init(void *start, uint16_t max_structure_size, uint16_t structure_table_length, uint32_t structure_table_address, uint16_t number_of_structures);static void *smbios_type_0_init(void *start, const char *xen_version, uint32_t xen_major_version, uint32_t xen_minor_version);static void *smbios_type_1_init(void *start, const char *xen_version, uint8_t uuid[16]);static void *smbios_type_3_init(void *start);static void *smbios_type_4_init(void *start, unsigned int cpu_number, char *cpu_manufacturer);static void *smbios_type_16_init(void *start, uint32_t memory_size_mb);static void *smbios_type_17_init(void *start, uint32_t memory_size_mb);static void *smbios_type_19_init(void *start, uint32_t memory_size_mb);static void *smbios_type_20_init(void *start, uint32_t memory_size_mb);static void *smbios_type_32_init(void *start);static void *smbios_type_127_init(void *start);static voidget_cpu_manufacturer(char *buf, int len){ char id[12]; uint32_t eax = 0; cpuid(0, &eax, (uint32_t *)&id[0], (uint32_t *)&id[8], (uint32_t *)&id[4]); if (memcmp(id, "GenuineIntel", 12) == 0) strncpy(buf, "Intel", len); else if (memcmp(id, "AuthenticAMD", 12) == 0) strncpy(buf, "AMD", len); else strncpy(buf, "unknown", len);}static intwrite_smbios_tables(void *start, uint32_t vcpus, uint64_t memsize, uint8_t uuid[16], char *xen_version, uint32_t xen_major_version, uint32_t xen_minor_version){ unsigned cpu_num, nr_structs = 0, max_struct_size = 0; char *p, *q; char cpu_manufacturer[15]; get_cpu_manufacturer(cpu_manufacturer, 15); p = (char *)start + sizeof(struct smbios_entry_point);#define do_struct(fn) do { \ q = (fn); \ nr_structs++; \ if ( (q - p) > max_struct_size ) \ max_struct_size = q - p; \ p = q; \} while (0) do_struct(smbios_type_0_init(p, xen_version, xen_major_version, xen_minor_version)); do_struct(smbios_type_1_init(p, xen_version, uuid)); do_struct(smbios_type_3_init(p)); for ( cpu_num = 1; cpu_num <= vcpus; cpu_num++ ) do_struct(smbios_type_4_init(p, cpu_num, cpu_manufacturer)); do_struct(smbios_type_16_init(p, memsize)); do_struct(smbios_type_17_init(p, memsize)); do_struct(smbios_type_19_init(p, memsize)); do_struct(smbios_type_20_init(p, memsize)); do_struct(smbios_type_32_init(p)); do_struct(smbios_type_127_init(p));#undef do_struct smbios_entry_point_init( start, max_struct_size, (p - (char *)start) - sizeof(struct smbios_entry_point), SMBIOS_PHYSICAL_ADDRESS + sizeof(struct smbios_entry_point), nr_structs); return ((char *)p - (char *)start);}/* Calculate how much pseudo-physical memory (in MB) is allocated to us. */static uint64_tget_memsize(void){ struct e820entry *map = HVM_E820; uint8_t num_entries = *HVM_E820_NR; uint64_t memsize = 0; int i; /* * Walk through e820map, ignoring any entries that aren't marked * as usable or reserved. */ for ( i = 0; i < num_entries; i++ ) { if ( (map->type == E820_RAM) || (map->type == E820_RESERVED) ) memsize += map->size; map++; } /* * Round up to the nearest MB. The user specifies domU pseudo-physical * memory in megabytes, so not doing this could easily lead to reporting * one less MB than the user specified. */ return (memsize + (1 << 20) - 1) >> 20;}inthvm_write_smbios_tables(void){ xen_domain_handle_t uuid; uint16_t xen_major_version, xen_minor_version; uint32_t xen_version; char xen_extra_version[XEN_EXTRAVERSION_LEN]; /* guess conservatively on buffer length for Xen version string */ char xen_version_str[80]; /* temporary variables used to build up Xen version string */ char *p = NULL; /* points to next point of insertion */ unsigned len = 0; /* length of string already composed */ char tmp[16]; /* holds result of itoa() */ unsigned tmp_len; /* length of next string to add */ hypercall_xen_version(XENVER_guest_handle, uuid); BUILD_BUG_ON(sizeof(xen_domain_handle_t) != 16); /* xen_version major and minor */ xen_version = hypercall_xen_version(XENVER_version, NULL); xen_major_version = (uint16_t) (xen_version >> 16); xen_minor_version = (uint16_t) xen_version; hypercall_xen_version(XENVER_extraversion, xen_extra_version); /* build up human-readable Xen version string */ p = xen_version_str; len = 0; itoa(tmp, xen_major_version); tmp_len = strlen(tmp); len += tmp_len; if ( len >= sizeof(xen_version_str) ) goto error_out; strcpy(p, tmp); p += tmp_len; len++; if ( len >= sizeof(xen_version_str) ) goto error_out; *p = '.'; p++; itoa(tmp, xen_minor_version); tmp_len = strlen(tmp); len += tmp_len; if ( len >= sizeof(xen_version_str) ) goto error_out; strcpy(p, tmp); p += tmp_len; tmp_len = strlen(xen_extra_version); len += tmp_len; if ( len >= sizeof(xen_version_str) ) goto error_out; strcpy(p, xen_extra_version); p += tmp_len; xen_version_str[sizeof(xen_version_str)-1] = '\0'; /* NB. 0xC0000 is a safe large memory area for scratch. */ len = write_smbios_tables((void *)0xC0000, get_vcpu_nr(), get_memsize(), uuid, xen_version_str, xen_major_version, xen_minor_version); if ( len > SMBIOS_MAXIMUM_SIZE ) goto error_out; /* Okay, not too large: copy out of scratch to final location. */ memcpy((void *)SMBIOS_PHYSICAL_ADDRESS, (void *)0xC0000, len); return len; error_out: printf("Could not write SMBIOS tables, error in hvmloader.c:" "hvm_write_smbios_tables()\n"); return 0;}static voidsmbios_entry_point_init(void *start, uint16_t max_structure_size, uint16_t structure_table_length, uint32_t structure_table_address, uint16_t number_of_structures){ uint8_t sum; int i; struct smbios_entry_point *ep = (struct smbios_entry_point *)start; strncpy(ep->anchor_string, "_SM_", 4); ep->length = 0x1f; ep->smbios_major_version = 2; ep->smbios_minor_version = 4; ep->max_structure_size = max_structure_size; ep->entry_point_revision = 0; memset(ep->formatted_area, 0, 5); strncpy(ep->intermediate_anchor_string, "_DMI_", 5); ep->structure_table_length = structure_table_length; ep->structure_table_address = structure_table_address; ep->number_of_structures = number_of_structures; ep->smbios_bcd_revision = 0x24; ep->checksum = 0; ep->intermediate_checksum = 0; sum = 0; for ( i = 0; i < 0x10; i++ ) sum += ((int8_t *)start)[i]; ep->checksum = -sum; sum = 0; for ( i = 0x10; i < ep->length; i++ ) sum += ((int8_t *)start)[i]; ep->intermediate_checksum = -sum;}/* Type 0 -- BIOS Information */static void *smbios_type_0_init(void *start, const char *xen_version, uint32_t xen_major_version, uint32_t xen_minor_version){ struct smbios_type_0 *p = (struct smbios_type_0 *)start;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -