Files
xen/tools/firmware/hvmloader/util.c
T
Roger Pau Monne 22650d6054 x86/hvmloader: select xen platform pci MMIO BAR UC or WB MTRR cache attribute
The Xen platform PCI device (vendor ID 0x5853) exposed to x86 HVM guests
doesn't have the functionality of a traditional PCI device.  The exposed
MMIO BAR is used by some guests (including Linux) as a safe place to map
foreign memory, including the grant table itself.

Traditionally BARs from devices have the uncacheable (UC) cache attribute
from the MTRR, to ensure correct functionality of such devices.  hvmloader
mimics this behavior and sets the MTRR attributes of both the low and high
PCI MMIO windows (where BARs of PCI devices reside) as UC in MTRR.

This however causes performance issues for users of the Xen platform PCI
device BAR, as for the purposes of mapping remote memory there's no need to
use the UC attribute.  On Intel systems this is worked around by using
iPAT, that allows the hypervisor to force the effective cache attribute of
a p2m entry regardless of the guest PAT value.  AMD however doesn't have an
equivalent of iPAT, and guest PAT values are always considered.

Linux commit:

41925b105e34 xen: replace xen_remap() with memremap()

Attempted to mitigate this by forcing mappings of the grant-table to use
the write-back (WB) cache attribute.  However Linux memremap() takes MTRRs
into account to calculate which PAT type to use, and seeing the MTRR cache
attribute for the region being UC the PAT also ends up as UC, regardless of
the caller having requested WB.

As a workaround to allow current Linux to map the grant-table as WB using
memremap() introduce an xl.cfg option (xen_platform_pci_bar_uc=0) that can
be used to select whether the Xen platform PCI device BAR will have the UC
attribute in MTRR.  Such workaround in hvmloader should also be paired with
a fix for Linux so it attempts to change the MTRR of the Xen platform PCI
device BAR to WB by itself.

Overall, the long term solution would be to provide the guest with a safe
range in the guest physical address space where mappings to foreign pages
can be created.

Some vif throughput performance figures provided by Anthoine from a 8
vCPUs, 4GB of RAM HVM guest(s) running on AMD hardware:

Without this patch:
vm -> dom0: 1.1Gb/s
vm -> vm:   5.0Gb/s

With the patch:
vm -> dom0: 4.5Gb/s
vm -> vm:   7.0Gb/s

Reported-by: Anthoine Bourgeois <anthoine.bourgeois@vates.tech>
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Oleksii Kurochko<oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com> # hvmloader
Reviewed-by: Anthony PERARD <anthony.perard@vates.tech>
2025-06-18 09:30:11 +02:00

966 lines
22 KiB
C

/*
* util.c: Helper library functions for HVMLoader.
*
* Leendert van Doorn, leendert@watson.ibm.com
* Copyright (c) 2005, International Business Machines Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
*/
#include "util.h"
#include "config.h"
#include "hypercall.h"
#include "ctype.h"
#include "vnuma.h"
#include <acpi2_0.h>
#include <libacpi.h>
#include <stdint.h>
#include <xen/xen.h>
#include <xen/memory.h>
#include <xen/sched.h>
#include <xen/hvm/hvm_xs_strings.h>
#include <xen/hvm/params.h>
/*
* Check whether there exists overlap in the specified memory range.
* Returns true if exists, else returns false.
*/
bool check_overlap(uint64_t start, uint64_t size,
uint64_t reserved_start, uint64_t reserved_size)
{
return (start + size > reserved_start) &&
(start < reserved_start + reserved_size);
}
uint8_t cmos_inb(uint8_t idx)
{
outb(0x70, idx);
return inb(0x71);
}
void cmos_outb(uint8_t idx, uint8_t val)
{
outb(0x70, idx);
outb(0x71, val);
}
char *itoa(char *a, unsigned int i)
{
unsigned int _i = i, x = 0;
do {
x++;
_i /= 10;
} while ( _i != 0 );
a += x;
*a-- = '\0';
do {
*a-- = (i % 10) + '0';
i /= 10;
} while ( i != 0 );
return a + 1;
}
int strcmp(const char *cs, const char *ct)
{
signed char res;
while ( ((res = *cs - *ct++) == 0) && (*cs++ != '\0') )
continue;
return res;
}
int strncmp(const char *s1, const char *s2, uint32_t n)
{
uint32_t ctr;
for (ctr = 0; ctr < n; ctr++)
if (s1[ctr] != s2[ctr])
return (int)(s1[ctr] - s2[ctr]);
return 0;
}
void *memcpy(void *dest, const void *src, unsigned n)
{
int t0, t1, t2;
asm volatile (
"cld\n"
"rep; movsl\n"
"testb $2,%b4\n"
"je 1f\n"
"movsw\n"
"1: testb $1,%b4\n"
"je 2f\n"
"movsb\n"
"2:"
: "=&c" (t0), "=&D" (t1), "=&S" (t2)
: "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src)
: "memory" );
return dest;
}
void *memmove(void *dest, const void *src, unsigned n)
{
if ( (unsigned long)dest > (unsigned long)src )
while ( n-- != 0 )
((char *)dest)[n] = ((char *)src)[n];
else
memcpy(dest, src, n);
return dest;
}
char *
strcpy(char *dest, const char *src)
{
char *p = dest;
while ( *src )
*p++ = *src++;
*p = 0;
return dest;
}
char *
strncpy(char *dest, const char *src, unsigned n)
{
int i = 0;
char *p = dest;
/* write non-NUL characters from src into dest until we run
out of room in dest or encounter a NUL in src */
while ( (i < n) && *src )
{
*p++ = *src++;
i++;
}
/* pad remaining bytes of dest with NUL bytes */
while ( i < n )
{
*p++ = 0;
i++;
}
return dest;
}
unsigned
strlen(const char *s)
{
int i = 0;
while ( *s++ )
i++;
return i;
}
static inline int __digit(char c, int base)
{
int d = -1;
if ( (c >= '0') && (c <= '9') )
d = c - '0';
if ( (c >= 'A') && (c <= 'Z') )
d = c - 'A' + 10;
if ( (c >= 'a') && (c <= 'z') )
d = c - 'a' + 10;
if (d >= base)
d = -1;
return d;
}
long long
strtoll(const char *s, char **end, int base)
{
long long v = 0;
int sign = 1;
while ( (*s != '\0') && isspace(*s) )
s++;
if ( *s == '\0' ) goto out;
if ( *s == '-' ) {
sign = -1;
s++;
} else {
if ( *s == '+' )
s++;
}
if ( *s == '\0' ) goto out;
if ( *s == '0' ) {
s++;
if ( *s == '\0' ) goto out;
if ( *s == 'x' ) {
if ( base != 0 && base != 16) goto out;
base = 16;
s++;
} else {
if ( base != 0 && base != 8) goto out;
base = 8;
}
} else {
if (base != 0 && base != 10) goto out;
base = 10;
}
while ( *s != '\0' ) {
int d = __digit(*s, base);
if ( d < 0 ) goto out;
v = (v * base) + d;
s++;
}
out:
if (end) *end = (char *)s;
return sign * v;
}
void *
memset(void *s, int c, unsigned n)
{
uint8_t b = (uint8_t) c;
uint8_t *p = (uint8_t *)s;
int i;
for ( i = 0; i < n; i++ )
*p++ = b;
return s;
}
int
memcmp(const void *s1, const void *s2, unsigned n)
{
unsigned i;
uint8_t *p1 = (uint8_t *) s1;
uint8_t *p2 = (uint8_t *) s2;
for ( i = 0; i < n; i++ )
{
if ( p1[i] < p2[i] )
return -1;
else if ( p1[i] > p2[i] )
return 1;
}
return 0;
}
static const char hex_digits[] = "0123456789abcdef";
/* Write a two-character hex representation of 'byte' to digits[].
Pre-condition: sizeof(digits) >= 2 */
void
byte_to_hex(char *digits, uint8_t byte)
{
digits[0] = hex_digits[byte >> 4];
digits[1] = hex_digits[byte & 0x0f];
}
/* Convert an array of 16 unsigned bytes to a DCE/OSF formatted UUID
string.
Pre-condition: sizeof(dest) >= 37 */
void
uuid_to_string(char *dest, uint8_t *uuid)
{
int i = 0;
char *p = dest;
for ( i = 0; i < 4; i++ )
{
byte_to_hex(p, uuid[i]);
p += 2;
}
*p++ = '-';
for ( i = 4; i < 6; i++ )
{
byte_to_hex(p, uuid[i]);
p += 2;
}
*p++ = '-';
for ( i = 6; i < 8; i++ )
{
byte_to_hex(p, uuid[i]);
p += 2;
}
*p++ = '-';
for ( i = 8; i < 10; i++ )
{
byte_to_hex(p, uuid[i]);
p += 2;
}
*p++ = '-';
for ( i = 10; i < 16; i++ )
{
byte_to_hex(p, uuid[i]);
p += 2;
}
*p = '\0';
}
int get_mem_mapping_layout(struct e820entry entries[], uint32_t *max_entries)
{
int rc;
struct xen_memory_map memmap = {
.nr_entries = *max_entries
};
set_xen_guest_handle(memmap.buffer, entries);
rc = hypercall_memory_op(XENMEM_memory_map, &memmap);
*max_entries = memmap.nr_entries;
return rc;
}
void mem_hole_populate_ram(xen_pfn_t mfn, uint32_t nr_mfns)
{
static int over_allocated;
struct xen_add_to_physmap xatp;
struct xen_memory_reservation xmr;
for ( ; nr_mfns-- != 0; mfn++ )
{
/* Try to allocate a brand new page in the reserved area. */
if ( !over_allocated )
{
xmr.domid = DOMID_SELF;
xmr.mem_flags = 0;
xmr.extent_order = 0;
xmr.nr_extents = 1;
set_xen_guest_handle(xmr.extent_start, &mfn);
if ( hypercall_memory_op(XENMEM_populate_physmap, &xmr) == 1 )
continue;
over_allocated = 1;
}
/* Otherwise, relocate a page from the ordinary RAM map. */
if ( hvm_info->high_mem_pgend )
{
xatp.idx = --hvm_info->high_mem_pgend;
if ( xatp.idx == (1ull << (32 - PAGE_SHIFT)) )
hvm_info->high_mem_pgend = 0;
}
else
{
xatp.idx = --hvm_info->low_mem_pgend;
}
xatp.domid = DOMID_SELF;
xatp.space = XENMAPSPACE_gmfn;
xatp.gpfn = mfn;
if ( hypercall_memory_op(XENMEM_add_to_physmap, &xatp) != 0 )
BUG();
}
/* Sync memory map[]. */
adjust_memory_map();
}
static uint32_t alloc_up = RESERVED_MEMORY_DYNAMIC_START - 1;
static uint32_t alloc_down = RESERVED_MEMORY_DYNAMIC_END;
xen_pfn_t mem_hole_alloc(uint32_t nr_mfns)
{
alloc_down -= nr_mfns << PAGE_SHIFT;
BUG_ON(alloc_up >= alloc_down);
return alloc_down >> PAGE_SHIFT;
}
void *mem_alloc(uint32_t size, uint32_t align)
{
uint32_t s, e;
/* Align to at least 16 bytes. */
if ( align < 16 )
align = 16;
s = (alloc_up + align) & ~(align - 1);
e = s + size - 1;
BUG_ON((e < s) || (e >= alloc_down));
while ( (alloc_up >> PAGE_SHIFT) != (e >> PAGE_SHIFT) )
{
alloc_up += PAGE_SIZE;
mem_hole_populate_ram(alloc_up >> PAGE_SHIFT, 1);
}
alloc_up = e;
return (void *)(unsigned long)s;
}
void *scratch_alloc(uint32_t size, uint32_t align)
{
uint32_t s, e;
/* Align to at least 16 bytes. */
if ( align < 16 )
align = 16;
s = (scratch_start + align) & ~(align - 1);
e = s + size - 1;
BUG_ON(e < s);
scratch_start = e;
return (void *)(unsigned long)s;
}
#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
(0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
uint32_t pci_read(uint32_t devfn, uint32_t reg, uint32_t len)
{
outl(0xcf8, PCI_CONF1_ADDRESS(0, devfn, reg));
switch ( len )
{
case 1: return inb(0xcfc + (reg & 3));
case 2: return inw(0xcfc + (reg & 2));
}
return inl(0xcfc);
}
void pci_write(uint32_t devfn, uint32_t reg, uint32_t len, uint32_t val)
{
outl(0xcf8, PCI_CONF1_ADDRESS(0, devfn, reg));
switch ( len )
{
case 1: outb(0xcfc + (reg & 3), val); break;
case 2: outw(0xcfc + (reg & 2), val); break;
case 4: outl(0xcfc, val); break;
}
}
static char *printnum(char *p, unsigned long num, unsigned base)
{
unsigned long n;
if ( (n = num/base) > 0 )
p = printnum(p, n, base);
*p++ = hex_digits[num % base];
*p = '\0';
return p;
}
static void _doprint(void (*emit)(void *, char), void *arg, const char *fmt, va_list ap)
{
char *str, c;
int lflag, zflag, nflag;
char buffer[17];
unsigned long value;
int i, slen, pad;
for ( ; *fmt != '\0'; fmt++ )
{
if ( *fmt != '%' )
{
emit(arg, *fmt);
continue;
}
pad = zflag = nflag = lflag = 0;
c = *++fmt;
if ( (c == '-') || isdigit(c) )
{
if ( c == '-' )
{
nflag = 1;
c = *++fmt;
}
zflag = c == '0';
for ( pad = 0; isdigit(c); c = *++fmt )
pad = (pad * 10) + c - '0';
}
if ( c == 'l' ) /* long extension */
{
lflag = 1;
c = *++fmt;
}
if ( (c == 'd') || (c == 'u') || (c == 'o') ||
(c == 'x') || (c == 'X') )
{
if ( lflag )
{
value = va_arg(ap, unsigned long);
if ( (c == 'd') && ((long)value < 0) )
{
value = -value;
emit(arg, '-');
}
}
else
{
value = va_arg(ap, unsigned int);
if ( (c == 'd') && ((int)value < 0) )
{
value = -(int)value;
emit(arg, '-');
}
}
str = buffer;
printnum(str, value,
c == 'o' ? 8 : ((c == 'x') || (c == 'X') ? 16 : 10));
slen = strlen(str);
for ( i = pad - slen; i > 0; i-- )
emit(arg, zflag ? '0' : ' ');
while ( *str )
{
char ch = *str++;
if ( (ch >= 'a') && (c == 'X') )
ch += 'A'-'a';
emit(arg, ch);
}
}
else if ( c == 's' )
{
str = va_arg(ap, char *);
slen = strlen(str);
if ( nflag == 0 )
for ( i = pad - slen; i > 0; i-- )
emit(arg, ' ');
while ( *str )
emit(arg, *str++);
if ( nflag )
for ( i = pad - slen; i > 0; i-- )
emit(arg, ' ');
}
else if ( c == 'c' )
{
emit(arg, va_arg(ap, int));
}
else
{
emit(arg, *fmt);
}
}
}
static void putchar(char c)
{
outb(0xe9, c);
}
static void __put(void *arg, char c)
{
putchar(c);
}
int printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
_doprint(__put, NULL, fmt, ap);
va_end(ap);
return 0;
}
int vprintf(const char *fmt, va_list ap)
{
_doprint(__put, NULL, fmt, ap);
return 0;
}
struct __copy_context {
char *ptr;
size_t emitted;
size_t remaining;
};
static void __copy(void *arg, char c)
{
struct __copy_context *ctxt = arg;
ctxt->emitted++;
if (ctxt->remaining == 0)
return;
*(ctxt->ptr++) = c;
--ctxt->remaining;
}
int snprintf(char *buf, size_t size, const char *fmt, ...)
{
va_list ap;
struct __copy_context ctxt;
ctxt.ptr = buf;
ctxt.emitted = 0;
ctxt.remaining = size;
va_start(ap, fmt);
_doprint(__copy, &ctxt, fmt, ap);
va_end(ap);
if (ctxt.remaining != 0)
*ctxt.ptr = '\0';
return ctxt.emitted;
}
static void __attribute__((noreturn)) crash(void)
{
struct sched_shutdown shutdown = { .reason = SHUTDOWN_crash };
printf("*** HVMLoader crashed.\n");
hypercall_sched_op(SCHEDOP_shutdown, &shutdown);
printf("*** Failed to crash. Halting.\n");
for ( ; ; )
asm volatile ( "hlt" );
}
void __assert_failed(const char *assertion, const char *file, int line)
{
printf("*** HVMLoader assertion '%s' failed at %s:%d\n",
assertion, file, line);
crash();
}
void __bug(const char *file, int line)
{
printf("*** HVMLoader bug at %s:%d\n", file, line);
crash();
}
static void validate_hvm_info(struct hvm_info_table *t)
{
uint8_t *ptr = (uint8_t *)t;
uint8_t sum = 0;
int i;
if ( strncmp(t->signature, "HVM INFO", 8) )
{
printf("Bad hvm info signature\n");
BUG();
}
if ( t->length < sizeof(struct hvm_info_table) )
{
printf("Bad hvm info length\n");
BUG();
}
for ( i = 0; i < t->length; i++ )
sum += ptr[i];
if ( sum != 0 )
{
printf("Bad hvm info checksum\n");
BUG();
}
}
struct hvm_info_table *get_hvm_info_table(void)
{
static struct hvm_info_table *table;
struct hvm_info_table *t;
if ( table != NULL )
return table;
t = (struct hvm_info_table *)HVM_INFO_PADDR;
validate_hvm_info(t);
table = t;
return table;
}
struct shared_info *get_shared_info(void)
{
static struct shared_info *shared_info = NULL;
struct xen_add_to_physmap xatp;
if ( shared_info != NULL )
return shared_info;
xatp.domid = DOMID_SELF;
xatp.space = XENMAPSPACE_shared_info;
xatp.idx = 0;
xatp.gpfn = mem_hole_alloc(1);
shared_info = (struct shared_info *)(xatp.gpfn << PAGE_SHIFT);
if ( hypercall_memory_op(XENMEM_add_to_physmap, &xatp) != 0 )
BUG();
return shared_info;
}
uint16_t get_cpu_mhz(void)
{
struct shared_info *shared_info = get_shared_info();
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;
/* 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;
cpu_mhz = (uint16_t)(((uint32_t)cpu_khz + 500) / 1000);
return cpu_mhz;
}
int uart_exists(uint16_t uart_base)
{
uint16_t ier = uart_base + 1;
uint8_t a, b, c;
a = inb(ier);
outb(ier, 0);
b = inb(ier);
outb(ier, 0xf);
c = inb(ier);
outb(ier, a);
return ((b == 0) && (c == 0xf));
}
int lpt_exists(uint16_t lpt_base)
{
/* Idea taken from linux-2.6.31.5:parport_pc.c */
uint16_t control = lpt_base + 2;
outb(control, 0xc);
return ((inb(control) & 0xf) == 0xc);
}
int hpet_exists(unsigned long hpet_base)
{
uint32_t hpet_id = *(uint32_t *)hpet_base;
return ((hpet_id >> 16) == 0x8086);
}
static uint8_t battery_port_exists(void)
{
return (inb(0x88) == 0x1F);
}
static unsigned long acpi_v2p(struct acpi_ctxt *ctxt, void *v)
{
return virt_to_phys(v);
}
static unsigned long acpi_alloc_up = ACPI_MEMORY_DYNAMIC_START - 1;
unsigned long acpi_pages_allocated(void)
{
return (acpi_alloc_up >> PAGE_SHIFT) -
((ACPI_MEMORY_DYNAMIC_START - 1) >> PAGE_SHIFT);
}
static void *acpi_mem_alloc(struct acpi_ctxt *ctxt,
uint32_t size, uint32_t align)
{
unsigned long s, e;
/* Align to at least 16 bytes. */
if ( align < 16 )
align = 16;
s = (acpi_alloc_up + align) & ~(align - 1);
e = s + size - 1;
BUG_ON((e < s) || (e >= RESERVED_MEMORY_DYNAMIC_START));
while ( (acpi_alloc_up >> PAGE_SHIFT) != (e >> PAGE_SHIFT) )
{
acpi_alloc_up += PAGE_SIZE;
mem_hole_populate_ram(acpi_alloc_up >> PAGE_SHIFT, 1);
}
acpi_alloc_up = e;
return (void *)s;
}
static void acpi_mem_free(struct acpi_ctxt *ctxt,
void *v, uint32_t size)
{
/* ACPI builder currently doesn't free memory so this is just a stub */
}
static uint32_t acpi_lapic_id(unsigned cpu)
{
return cpu_to_apicid[cpu];
}
void hvmloader_acpi_build_tables(struct acpi_config *config,
unsigned int physical)
{
const char *s;
struct acpi_ctxt ctxt;
long long tpm_version;
char *end;
/* Allocate and initialise the acpi info area. */
mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
/* If the device model is specified switch to the corresponding tables */
s = xenstore_read("platform/device-model", "");
if ( !strncmp(s, "qemu_xen", 9) )
{
config->dsdt_anycpu = dsdt_anycpu_qemu_xen;
config->dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len;
config->dsdt_15cpu = NULL;
config->dsdt_15cpu_len = 0;
}
config->lapic_base_address = LAPIC_BASE_ADDRESS;
config->lapic_id = acpi_lapic_id;
config->ioapic_base_address = IOAPIC_BASE_ADDRESS;
config->ioapic_id = IOAPIC_ID;
config->pci_isa_irq_mask = PCI_ISA_IRQ_MASK;
if ( uart_exists(0x3f8) )
config->table_flags |= ACPI_HAS_COM1;
if ( uart_exists(0x2f8) )
config->table_flags |= ACPI_HAS_COM2;
if ( lpt_exists(0x378) )
config->table_flags |= ACPI_HAS_LPT1;
if ( hpet_exists(ACPI_HPET_ADDRESS) )
config->table_flags |= ACPI_HAS_HPET;
config->pci_start = pci_mem_start;
config->pci_len = RESERVED_MEMBASE - pci_mem_start;
if ( pci_hi_mem_end > pci_hi_mem_start )
{
config->pci_hi_start = pci_hi_mem_start;
config->pci_hi_len = pci_hi_mem_end - pci_hi_mem_start;
}
s = xenstore_read("platform/generation-id", "0:0");
if ( s )
{
config->vm_gid[0] = strtoll(s, &end, 0);
config->vm_gid[1] = 0;
if ( end && end[0] == ':' )
config->vm_gid[1] = strtoll(end+1, NULL, 0);
}
s = xenstore_read(HVM_XS_ACPI_PT_ADDRESS, NULL);
if ( s )
{
config->pt.addr = strtoll(s, NULL, 0);
s = xenstore_read(HVM_XS_ACPI_PT_LENGTH, NULL);
if ( s )
config->pt.length = strtoll(s, NULL, 0);
}
if ( battery_port_exists() )
config->table_flags |= ACPI_HAS_SSDT_PM;
if ( !strncmp(xenstore_read("platform/acpi_s3", "1"), "1", 1) )
config->table_flags |= ACPI_HAS_SSDT_S3;
if ( !strncmp(xenstore_read("platform/acpi_s4", "1"), "1", 1) )
config->table_flags |= ACPI_HAS_SSDT_S4;
if ( !strncmp(xenstore_read("platform/acpi_laptop_slate", "0"), "1", 1) )
config->table_flags |= ACPI_HAS_SSDT_LAPTOP_SLATE;
config->table_flags |= (ACPI_HAS_IOAPIC | ACPI_HAS_WAET |
ACPI_HAS_PMTIMER | ACPI_HAS_BUTTONS |
ACPI_HAS_VGA | ACPI_HAS_8042 |
ACPI_HAS_CMOS_RTC);
config->acpi_revision = 4;
config->tpm_version = 0;
s = xenstore_read("platform/tpm_version", "1");
tpm_version = strtoll(s, &end, 0);
if ( end[0] == '\0' )
{
switch ( tpm_version )
{
case 1:
config->table_flags |= ACPI_HAS_TPM;
config->tis_hdr = (uint16_t *)ACPI_TIS_HDR_ADDRESS;
config->tpm_version = 1;
break;
case 2:
config->table_flags |= ACPI_HAS_TPM;
config->crb_id = (uint16_t *)TPM_CRB_INTF_ID;
mem_hole_populate_ram(TPM_LOG_AREA_ADDRESS >> PAGE_SHIFT,
TPM_LOG_SIZE >> PAGE_SHIFT);
memset((void *)TPM_LOG_AREA_ADDRESS, 0, TPM_LOG_SIZE);
config->tpm_version = 2;
break;
}
}
config->numa.nr_vmemranges = nr_vmemranges;
config->numa.nr_vnodes = nr_vnodes;
config->numa.vcpu_to_vnode = vcpu_to_vnode;
config->numa.vdistance = vdistance;
config->numa.vmemrange = vmemrange;
config->hvminfo = hvm_info;
config->rsdp = physical;
config->infop = ACPI_INFO_PHYSICAL_ADDRESS;
ctxt.mem_ops.alloc = acpi_mem_alloc;
ctxt.mem_ops.free = acpi_mem_free;
ctxt.mem_ops.v2p = acpi_v2p;
acpi_build_tables(&ctxt, config);
hvm_param_set(HVM_PARAM_VM_GENERATION_ID_ADDR, config->vm_gid_addr);
}
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/