/*
* 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 .
*/
#include "util.h"
#include "config.h"
#include "hypercall.h"
#include "ctype.h"
#include "vnuma.h"
#include
#include
#include
#include
#include
#include
#include
#include
/*
* 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 void *acpi_mem_alloc(struct acpi_ctxt *ctxt,
uint32_t size, uint32_t align)
{
return mem_alloc(size, align);
}
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:
*/