Files
xen/tools/firmware/hvmloader/util.c
T
Igor Druzhinin f63b20a213 hvmloader: indicate ACPI tables with "ACPI data" type in e820
Guest kernel does need to know in some cases where the tables are located
to treat these regions properly. One example is kexec process where
the first kernel needs to pass ACPI region locations to the second
kernel which is now a requirement in Linux after 02a3e3cdb7f12 ("x86/boot:
Parse SRAT table and count immovable memory regions") in order for kexec
transition to actually work.

That commit introduced accesses to XSDT and SRAT while the second kernel
is still using kexec transition tables. The transition tables do not have
e820 "reserved" regions mapped where those tables are located currently
in a Xen guest. Instead "ACPI data" regions are mapped with the transition
tables that was introduced by the following commit 6bbeb276b7 ("x86/kexec:
Add the EFI system tables and ACPI tables to the ident map").

Reserve 1MB (out of 16MB currently available) right after ACPI info page for
ACPI tables exclusively but populate this region on demand and only indicate
populated memory as "ACPI data" since according to ACPI spec that memory is
reclaimable by the guest if necessary. That is close to how we treat
the same ACPI data in PVH guests. 1MB should be enough for now but could be
later extended if required.

Signed-off-by: Igor Druzhinin <igor.druzhinin@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: 8efa46516c
master date: 2020-09-09 17:56:13 +0200
2020-09-22 17:40:36 +02:00

1034 lines
23 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);
}
void wrmsr(uint32_t idx, uint64_t v)
{
asm volatile (
"wrmsr"
: : "c" (idx), "a" ((uint32_t)v), "d" ((uint32_t)(v>>32)) );
}
uint64_t rdmsr(uint32_t idx)
{
uint32_t lo, hi;
asm volatile (
"rdmsr"
: "=a" (lo), "=d" (hi) : "c" (idx) );
return (lo | ((uint64_t)hi << 32));
}
void outb(uint16_t addr, uint8_t val)
{
asm volatile ( "outb %%al, %%dx" : : "d" (addr), "a" (val) );
}
void outw(uint16_t addr, uint16_t val)
{
asm volatile ( "outw %%ax, %%dx" : : "d" (addr), "a" (val) );
}
void outl(uint16_t addr, uint32_t val)
{
asm volatile ( "outl %%eax, %%dx" : : "d" (addr), "a" (val) );
}
uint8_t inb(uint16_t addr)
{
uint8_t val;
asm volatile ( "inb %%dx,%%al" : "=a" (val) : "d" (addr) );
return val;
}
uint16_t inw(uint16_t addr)
{
uint16_t val;
asm volatile ( "inw %%dx,%%ax" : "=a" (val) : "d" (addr) );
return val;
}
uint32_t inl(uint16_t addr)
{
uint32_t val;
asm volatile ( "inl %%dx,%%eax" : "=a" (val) : "d" (addr) );
return val;
}
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;
}
void
cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
{
asm volatile (
"cpuid"
: "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
: "0" (idx) );
}
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;
}
uint32_t ioapic_read(uint32_t reg)
{
*(volatile uint32_t *)(ioapic_base_address + 0x00) = reg;
return *(volatile uint32_t *)(ioapic_base_address + 0x10);
}
void ioapic_write(uint32_t reg, uint32_t val)
{
*(volatile uint32_t *)(ioapic_base_address + 0x00) = reg;
*(volatile uint32_t *)(ioapic_base_address + 0x10) = val;
}
uint32_t lapic_read(uint32_t reg)
{
return *(volatile uint32_t *)(LAPIC_BASE_ADDRESS + reg);
}
void lapic_write(uint32_t reg, uint32_t val)
{
*(volatile uint32_t *)(LAPIC_BASE_ADDRESS + reg) = val;
}
#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(char *assertion, char *file, int line)
{
printf("*** HVMLoader assertion '%s' failed at %s:%d\n",
assertion, file, line);
crash();
}
void __bug(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 LAPIC_ID(cpu);
}
void hvmloader_acpi_build_tables(struct acpi_config *config,
unsigned int physical)
{
const char *s;
struct acpi_ctxt ctxt;
/* 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_traditional", 21) )
{
config->dsdt_anycpu = dsdt_anycpu;
config->dsdt_anycpu_len = dsdt_anycpu_len;
config->dsdt_15cpu = dsdt_15cpu;
config->dsdt_15cpu_len = dsdt_15cpu_len;
}
else 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 = pci_mem_end - 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 )
{
char *end;
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_TCPA | 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->tis_hdr = (uint16_t *)ACPI_TIS_HDR_ADDRESS;
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:
*/