Files
xen/tools/firmware/hvmloader/util.c
T
kaf24@localhost.localdomain dd59dfdfb1 This patch adds a 32bit gateway to the Bochs BIOS. The 32 bit code is
compiled with gcc and linked into the hvmloader as a byte-array.
Hvmloader allocates memory (rounded up to next 64kb) from the e820
table
below 4GB, copies and relocates the 32bit code in the allocated area
and
copies a jumptable (located in a section '.biosjumptable') pointing to
the 'exported' functions into the Bochs BIOS's memory area to link the
two code sections. The memory area has been reserved and can be
identified with the signature '___JMPT'.

In the Bochs BIOS only stub functions are provided. These load the
index
of a particular function in the jump table, switch to protected mode
and
call the function in the high memory area.  The stack is prepared such
that functions compiled by gcc can just pick the parameters from the
stack as usual - this means that the 16bit real-mode return address is
taken off the stack. The stub functions should have the same signature
as those in 32bit space. For ABI compatibility reasons parameters
inside
the Bochs BIOS stubs should all be 32bit wide.

This patch includes a test function that calls three gcc-compiled
functions in the high memory area and displays their success status.
Simple tests are done doing multiplication and addition of 32-bit
numbers and reading and modification of a static variable. These
functions test the interface and the relocation code. The test code is
removed in patch part 3.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
2007-01-26 16:30:48 +00:00

571 lines
12 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, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*/
#include "acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
#include "util.h"
#include "config.h"
#include <stdint.h>
#include <xenctrl.h>
#include <xen/hvm/hvm_info_table.h>
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;
}
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 ( (long)dest > (long)src )
{
n--;
while ( n > 0 )
{
((char *)dest)[n] = ((char *)src)[n];
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;
}
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) );
}
/* Write a two-character hex representation of 'byte' to digits[].
Pre-condition: sizeof(digits) >= 2 */
void
byte_to_hex(char *digits, uint8_t byte)
{
uint8_t nybbel = byte >> 4;
if ( nybbel > 9 )
digits[0] = 'a' + nybbel-10;
else
digits[0] = '0' + nybbel;
nybbel = byte & 0x0f;
if ( nybbel > 9 )
digits[1] = 'a' + nybbel-10;
else
digits[1] = '0' + nybbel;
}
/* 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';
}
#include <xen/hvm/e820.h>
#define E820_MAP_NR ((unsigned char *)E820_MAP_PAGE + E820_MAP_NR_OFFSET)
#define E820_MAP ((struct e820entry *)(E820_MAP_PAGE + E820_MAP_OFFSET))
uint64_t e820_malloc(uint64_t size, uint32_t type, uint64_t mask)
{
uint64_t addr = 0;
int c = *E820_MAP_NR - 1;
struct e820entry *e820entry = (struct e820entry *)E820_MAP;
while ( c >= 0 )
{
if ( (e820entry[c].type == E820_RAM) &&
((e820entry[c].addr & (~mask)) == 0) &&
(e820entry[c].size >= size) )
{
addr = e820entry[c].addr;
if ( e820entry[c].size != size )
{
(*E820_MAP_NR)++;
memmove(&e820entry[c+1],
&e820entry[c],
(*E820_MAP_NR - c) *
sizeof(struct e820entry));
e820entry[c].size -= size;
addr += e820entry[c].size;
c++;
}
e820entry[c].addr = addr;
e820entry[c].size = size;
e820entry[c].type = type;
break;
}
c--;
}
return addr;
}
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, int base)
{
unsigned long n;
if ( (n = num/base) > 0 )
p = printnum(p, n, base);
*p++ = "0123456789abcdef"[(int)(num % base)];
*p = '\0';
return p;
}
static void _doprint(void (*put)(char), char const *fmt, va_list ap)
{
register char *str, c;
int lflag, zflag, nflag;
char buffer[17];
unsigned value;
int i, slen, pad;
for ( ; *fmt != '\0'; fmt++ )
{
if ( *fmt != '%' )
{
put(*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') )
{
if ( lflag )
value = va_arg(ap, unsigned);
else
value = (unsigned) va_arg(ap, unsigned int);
str = buffer;
printnum(str, value,
c == 'o' ? 8 : (c == 'x' ? 16 : 10));
goto printn;
}
else if ( (c == 'O') || (c == 'D') || (c == 'X') )
{
value = va_arg(ap, unsigned);
str = buffer;
printnum(str, value,
c == 'O' ? 8 : (c == 'X' ? 16 : 10));
printn:
slen = strlen(str);
for ( i = pad - slen; i > 0; i-- )
put(zflag ? '0' : ' ');
while ( *str )
put(*str++);
}
else if ( c == 's' )
{
str = va_arg(ap, char *);
slen = strlen(str);
if ( nflag == 0 )
for ( i = pad - slen; i > 0; i-- )
put(' ');
while ( *str )
put(*str++);
if ( nflag )
for ( i = pad - slen; i > 0; i-- )
put(' ');
}
else if ( c == 'c' )
{
put(va_arg(ap, int));
}
else
{
put(*fmt);
}
}
}
static void putchar(char c)
{
outb(0xe9, c);
}
int printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
_doprint(putchar, fmt, ap);
va_end(ap);
return 0;
}
int vprintf(const char *fmt, va_list ap)
{
_doprint(putchar, fmt, ap);
return 0;
}
void __assert_failed(char *assertion, char *file, int line)
{
printf("HVMLoader assertion '%s' failed at %s:%d\n",
assertion, file, line);
for ( ; ; )
__asm__ __volatile__ ( "ud2" );
}
void __bug(char *file, int line)
{
printf("HVMLoader bug at %s:%d\n", file, line);
for ( ; ; )
__asm__ __volatile__ ( "ud2" );
}
static int validate_hvm_info(struct hvm_info_table *t)
{
char signature[] = "HVM INFO";
uint8_t *ptr = (uint8_t *)t;
uint8_t sum = 0;
int i;
/* strncmp(t->signature, "HVM INFO", 8) */
for ( i = 0; i < 8; i++ )
{
if ( signature[i] != t->signature[i] )
{
printf("Bad hvm info signature\n");
return 0;
}
}
for ( i = 0; i < t->length; i++ )
sum += ptr[i];
return (sum == 0);
}
static 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;
if ( !validate_hvm_info(t) )
{
printf("Bad hvm info table\n");
return NULL;
}
table = t;
return table;
}
int get_vcpu_nr(void)
{
struct hvm_info_table *t = get_hvm_info_table();
return (t ? t->nr_vcpus : 1);
}
int get_acpi_enabled(void)
{
struct hvm_info_table *t = get_hvm_info_table();
return (t ? t->acpi_enabled : 1);
}
int get_apic_mode(void)
{
struct hvm_info_table *t = get_hvm_info_table();
return (t ? t->apic_mode : 1);
}
/*
* Local variables:
* mode: C
* c-set-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/