mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
hvmloader: Properly implement some more SMBIOS fields.
In particular: - BIOS release date - BIOS characteristics - BIOS extended characteristics (Targeted Content Distribution is required to be specified to pass WHQL). - CPU speed Based on a patch by Kamala Narasimhan <kamala.narasimhan@citrix.com> Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
This commit is contained in:
1 parent
f3bf1dc168
commit
75d2b7df30
5 files changed
+152
-23
No files matched your search
@@ -42,16 +42,21 @@ OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||
.PHONY: all
|
||||
all: hvmloader
|
||||
|
||||
hvmloader: roms.h subdirs-all $(SRCS)
|
||||
$(CC) $(CFLAGS) -c $(SRCS)
|
||||
$(LD) $(LDFLAGS_DIRECT) -N -Ttext $(LOADADDR) -o hvmloader.tmp $(OBJS) acpi/acpi.a
|
||||
smbios.o: CFLAGS += -D__SMBIOS_DATE__="\"$(shell date +%m/%d/%Y)\""
|
||||
|
||||
hvmloader: roms.h subdirs-all $(OBJS)
|
||||
$(LD) $(LDFLAGS_DIRECT) -N -Ttext $(LOADADDR) \
|
||||
-o hvmloader.tmp $(OBJS) acpi/acpi.a
|
||||
$(OBJCOPY) hvmloader.tmp hvmloader
|
||||
rm -f hvmloader.tmp
|
||||
|
||||
roms.h: ../rombios/BIOS-bochs-latest ../vgabios/VGABIOS-lgpl-latest.bin ../vgabios/VGABIOS-lgpl-latest.cirrus.bin ../etherboot/eb-roms.h ../extboot/extboot.bin
|
||||
roms.h: ../rombios/BIOS-bochs-latest ../vgabios/VGABIOS-lgpl-latest.bin \
|
||||
../vgabios/VGABIOS-lgpl-latest.cirrus.bin ../etherboot/eb-roms.h \
|
||||
../extboot/extboot.bin
|
||||
sh ./mkhex rombios ../rombios/BIOS-bochs-latest > roms.h
|
||||
sh ./mkhex vgabios_stdvga ../vgabios/VGABIOS-lgpl-latest.bin >> roms.h
|
||||
sh ./mkhex vgabios_cirrusvga ../vgabios/VGABIOS-lgpl-latest.cirrus.bin >> roms.h
|
||||
sh ./mkhex vgabios_cirrusvga \
|
||||
../vgabios/VGABIOS-lgpl-latest.cirrus.bin >> roms.h
|
||||
cat ../etherboot/eb-roms.h >> roms.h
|
||||
sh ./mkhex extboot ../extboot/extboot.bin >> roms.h
|
||||
|
||||
|
||||
@@ -420,6 +420,8 @@ int main(void)
|
||||
|
||||
init_hypercalls();
|
||||
|
||||
printf("CPU speed is %u MHz\n", get_cpu_mhz());
|
||||
|
||||
printf("Writing SMBIOS tables ...\n");
|
||||
smbios_sz = hvm_write_smbios_tables();
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <xen/xen.h>
|
||||
#include <xen/version.h>
|
||||
#include "smbios_types.h"
|
||||
#include "util.h"
|
||||
@@ -246,13 +247,14 @@ smbios_entry_point_init(void *start,
|
||||
int i;
|
||||
struct smbios_entry_point *ep = (struct smbios_entry_point *)start;
|
||||
|
||||
memset(ep, 0, sizeof(*ep));
|
||||
|
||||
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;
|
||||
@@ -260,9 +262,6 @@ smbios_entry_point_init(void *start,
|
||||
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];
|
||||
@@ -280,22 +279,27 @@ 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;
|
||||
|
||||
static const char *smbios_release_date = __SMBIOS_DATE__;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->header.type = 0;
|
||||
p->header.length = sizeof(struct smbios_type_0);
|
||||
p->header.handle = 0;
|
||||
|
||||
|
||||
p->vendor_str = 1;
|
||||
p->version_str = 2;
|
||||
p->starting_address_segment = 0xe800;
|
||||
p->release_date_str = 0;
|
||||
p->release_date_str = 3;
|
||||
p->rom_size = 0;
|
||||
|
||||
memset(p->characteristics, 0, 8);
|
||||
p->characteristics[7] = 0x08; /* BIOS characteristics not supported */
|
||||
p->characteristics_extension_bytes[0] = 0;
|
||||
p->characteristics_extension_bytes[1] = 0;
|
||||
|
||||
|
||||
/* BIOS Characteristics. */
|
||||
p->characteristics[0] = 0x80; /* PCI is supported */
|
||||
p->characteristics[2] = 0x08; /* EDD is supported */
|
||||
|
||||
/* Extended Characteristics: Enable Targeted Content Distribution. */
|
||||
p->characteristics_extension_bytes[1] = 0x04;
|
||||
|
||||
p->major_release = (uint8_t) xen_major_version;
|
||||
p->minor_release = (uint8_t) xen_minor_version;
|
||||
p->embedded_controller_major = 0xff;
|
||||
@@ -306,6 +310,8 @@ smbios_type_0_init(void *start, const char *xen_version,
|
||||
start += strlen("Xen") + 1;
|
||||
strcpy((char *)start, xen_version);
|
||||
start += strlen(xen_version) + 1;
|
||||
strcpy((char *)start, smbios_release_date);
|
||||
start += strlen(smbios_release_date) + 1;
|
||||
|
||||
*((uint8_t *)start) = 0;
|
||||
return start + 1;
|
||||
@@ -318,6 +324,9 @@ smbios_type_1_init(void *start, const char *xen_version,
|
||||
{
|
||||
char uuid_str[37];
|
||||
struct smbios_type_1 *p = (struct smbios_type_1 *)start;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->header.type = 1;
|
||||
p->header.length = sizeof(struct smbios_type_1);
|
||||
p->header.handle = 0x100;
|
||||
@@ -355,6 +364,8 @@ smbios_type_3_init(void *start)
|
||||
{
|
||||
struct smbios_type_3 *p = (struct smbios_type_3 *)start;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->header.type = 3;
|
||||
p->header.length = sizeof(struct smbios_type_3);
|
||||
p->header.handle = 0x300;
|
||||
@@ -379,12 +390,15 @@ smbios_type_3_init(void *start)
|
||||
|
||||
/* Type 4 -- Processor Information */
|
||||
static void *
|
||||
smbios_type_4_init(void *start, unsigned int cpu_number, char *cpu_manufacturer)
|
||||
smbios_type_4_init(
|
||||
void *start, unsigned int cpu_number, char *cpu_manufacturer)
|
||||
{
|
||||
char buf[80];
|
||||
struct smbios_type_4 *p = (struct smbios_type_4 *)start;
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->header.type = 4;
|
||||
p->header.length = sizeof(struct smbios_type_4);
|
||||
p->header.handle = 0x400 + cpu_number;
|
||||
@@ -403,8 +417,7 @@ smbios_type_4_init(void *start, unsigned int cpu_number, char *cpu_manufacturer)
|
||||
p->voltage = 0;
|
||||
p->external_clock = 0;
|
||||
|
||||
p->max_speed = 0; /* unknown */
|
||||
p->current_speed = 0; /* unknown */
|
||||
p->max_speed = p->current_speed = get_cpu_mhz();
|
||||
|
||||
p->status = 0x41; /* socket populated, CPU enabled */
|
||||
p->upgrade = 0x01; /* other */
|
||||
@@ -431,6 +444,8 @@ smbios_type_16_init(void *start, uint32_t memsize)
|
||||
{
|
||||
struct smbios_type_16 *p = (struct smbios_type_16*)start;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->header.type = 16;
|
||||
p->header.handle = 0x1000;
|
||||
p->header.length = sizeof(struct smbios_type_16);
|
||||
@@ -453,6 +468,8 @@ smbios_type_17_init(void *start, uint32_t memory_size_mb)
|
||||
{
|
||||
struct smbios_type_17 *p = (struct smbios_type_17 *)start;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->header.type = 17;
|
||||
p->header.length = sizeof(struct smbios_type_17);
|
||||
p->header.handle = 0x1100;
|
||||
@@ -484,6 +501,8 @@ smbios_type_19_init(void *start, uint32_t memory_size_mb)
|
||||
{
|
||||
struct smbios_type_19 *p = (struct smbios_type_19 *)start;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->header.type = 19;
|
||||
p->header.length = sizeof(struct smbios_type_19);
|
||||
p->header.handle = 0x1300;
|
||||
@@ -504,6 +523,8 @@ smbios_type_20_init(void *start, uint32_t memory_size_mb)
|
||||
{
|
||||
struct smbios_type_20 *p = (struct smbios_type_20 *)start;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->header.type = 20;
|
||||
p->header.length = sizeof(struct smbios_type_20);
|
||||
p->header.handle = 0x1400;
|
||||
@@ -528,6 +549,8 @@ smbios_type_32_init(void *start)
|
||||
{
|
||||
struct smbios_type_32 *p = (struct smbios_type_32 *)start;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->header.type = 32;
|
||||
p->header.length = sizeof(struct smbios_type_32);
|
||||
p->header.handle = 0x2000;
|
||||
@@ -545,6 +568,8 @@ smbios_type_127_init(void *start)
|
||||
{
|
||||
struct smbios_type_127 *p = (struct smbios_type_127 *)start;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
p->header.type = 127;
|
||||
p->header.length = sizeof(struct smbios_type_127);
|
||||
p->header.handle = 0x7f00;
|
||||
|
||||
@@ -21,7 +21,10 @@
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
#include "e820.h"
|
||||
#include "hypercall.h"
|
||||
#include <stdint.h>
|
||||
#include <xen/xen.h>
|
||||
#include <xen/memory.h>
|
||||
#include <xen/hvm/hvm_info_table.h>
|
||||
|
||||
void outb(uint16_t addr, uint8_t val)
|
||||
@@ -585,6 +588,56 @@ int get_apic_mode(void)
|
||||
return (t ? t->apic_mode : 1);
|
||||
}
|
||||
|
||||
uint16_t get_cpu_mhz(void)
|
||||
{
|
||||
struct xen_add_to_physmap xatp;
|
||||
struct shared_info *shared_info = (struct shared_info *)0xa0000;
|
||||
struct vcpu_time_info *info = &shared_info->vcpu_info[0].time;
|
||||
uint64_t cpu_khz;
|
||||
uint32_t tsc_to_nsec_mul, version;
|
||||
int8_t tsc_shift;
|
||||
|
||||
static uint16_t cpu_mhz;
|
||||
if ( cpu_mhz != 0 )
|
||||
return cpu_mhz;
|
||||
|
||||
/* Map shared-info page to 0xa0000 (i.e., overlap VGA hole). */
|
||||
xatp.domid = DOMID_SELF;
|
||||
xatp.space = XENMAPSPACE_shared_info;
|
||||
xatp.idx = 0;
|
||||
xatp.gpfn = (unsigned long)shared_info >> 12;
|
||||
if ( hypercall_memory_op(XENMEM_add_to_physmap, &xatp) != 0 )
|
||||
BUG();
|
||||
|
||||
/* Get a consistent snapshot of scale factor (multiplier and shift). */
|
||||
do {
|
||||
version = info->version;
|
||||
rmb();
|
||||
tsc_to_nsec_mul = info->tsc_to_system_mul;
|
||||
tsc_shift = info->tsc_shift;
|
||||
rmb();
|
||||
} while ((version & 1) | (version ^ info->version));
|
||||
|
||||
/* Compute CPU speed in kHz. */
|
||||
cpu_khz = 1000000ull << 32;
|
||||
do_div(cpu_khz, tsc_to_nsec_mul);
|
||||
if ( tsc_shift < 0 )
|
||||
cpu_khz = cpu_khz << -tsc_shift;
|
||||
else
|
||||
cpu_khz = cpu_khz >> tsc_shift;
|
||||
|
||||
/* Get the VGA MMIO hole back by remapping shared info to scratch. */
|
||||
xatp.domid = DOMID_SELF;
|
||||
xatp.space = XENMAPSPACE_shared_info;
|
||||
xatp.idx = 0;
|
||||
xatp.gpfn = 0xfffff; /* scratch pfn */
|
||||
if ( hypercall_memory_op(XENMEM_add_to_physmap, &xatp) != 0 )
|
||||
BUG();
|
||||
|
||||
cpu_mhz = (uint16_t)(((uint32_t)cpu_khz + 500) / 1000);
|
||||
return cpu_mhz;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
#undef NULL
|
||||
#define NULL ((void*)0)
|
||||
|
||||
extern void __assert_failed(char *assertion, char *file, int line)
|
||||
void __assert_failed(char *assertion, char *file, int line)
|
||||
__attribute__((noreturn));
|
||||
#define ASSERT(p) \
|
||||
do { if (!(p)) __assert_failed(#p, __FILE__, __LINE__); } while (0)
|
||||
extern void __bug(char *file, int line) __attribute__((noreturn));
|
||||
void __bug(char *file, int line) __attribute__((noreturn));
|
||||
#define BUG() __bug(__FILE__, __LINE__)
|
||||
#define BUG_ON(p) do { if (p) BUG(); } while (0)
|
||||
#define BUILD_BUG_ON(p) ((void)sizeof(char[1 - 2 * !!(p)]))
|
||||
@@ -49,10 +49,54 @@ void pci_write(uint32_t devfn, uint32_t reg, uint32_t len, uint32_t val);
|
||||
#define pci_writew(devfn, reg, val) (pci_write(devfn, reg, 2, (uint16_t)val))
|
||||
#define pci_writel(devfn, reg, val) (pci_write(devfn, reg, 4, (uint32_t)val))
|
||||
|
||||
/* Get CPU speed in MHz. */
|
||||
uint16_t get_cpu_mhz(void);
|
||||
|
||||
/* Do cpuid instruction, with operation 'idx' */
|
||||
void cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx,
|
||||
uint32_t *ecx, uint32_t *edx);
|
||||
|
||||
/* Read the TSC register. */
|
||||
static inline uint64_t rdtsc(void)
|
||||
{
|
||||
uint64_t tsc;
|
||||
asm volatile ( "rdtsc" : "=A" (tsc) );
|
||||
return tsc;
|
||||
}
|
||||
|
||||
/* Relax the CPU and let the compiler know that time passes. */
|
||||
static inline void cpu_relax(void)
|
||||
{
|
||||
asm volatile ( "rep ; nop" : : : "memory" );
|
||||
}
|
||||
|
||||
/* Memory barriers. */
|
||||
#define barrier() asm volatile ( "" : : : "memory" )
|
||||
#define rmb() barrier()
|
||||
#define wmb() barrier()
|
||||
|
||||
/*
|
||||
* Divide a 64-bit dividend by a 32-bit divisor.
|
||||
* (1) Overwrites the 64-bit dividend _in_place_ with the quotient
|
||||
* (2) Returns the 32-bit remainder
|
||||
*/
|
||||
#define do_div(n, base) ({ \
|
||||
unsigned long __upper, __low, __high, __mod, __base; \
|
||||
__base = (base); \
|
||||
asm ( "" : "=a" (__low), "=d" (__high) : "A" (n) ); \
|
||||
__upper = __high; \
|
||||
if ( __high ) \
|
||||
{ \
|
||||
__upper = __high % (__base); \
|
||||
__high = __high / (__base); \
|
||||
} \
|
||||
asm ( "divl %2" \
|
||||
: "=a" (__low), "=d" (__mod) \
|
||||
: "rm" (__base), "0" (__low), "1" (__upper) ); \
|
||||
asm ( "" : "=A" (n) : "a" (__low), "d" (__high) ); \
|
||||
__mod; \
|
||||
})
|
||||
|
||||
/* HVM-builder info. */
|
||||
int get_vcpu_nr(void);
|
||||
int get_acpi_enabled(void);
|
||||
|
||||