Files
xen/tools/libxc/xc_private.c
T
kaf24@firebug.cl.cam.ac.uk 12b1a321bd Here is our latest patch to enable the Xen tools to
build and work with IA64 Xen.
Signed-off-by: Matt Chapman <matthewc@hp.com>
Acked-by: Dan Magenheimer <dan.magenheimer@hp.com>
2005-07-29 10:34:45 +00:00

406 lines
9.5 KiB
C

/******************************************************************************
* xc_private.c
*
* Helper functions for the rest of the library.
*/
#include <zlib.h>
#include "xc_private.h"
void *xc_map_foreign_batch(int xc_handle, u32 dom, int prot,
unsigned long *arr, int num )
{
privcmd_mmapbatch_t ioctlx;
void *addr;
addr = mmap(NULL, num*PAGE_SIZE, prot, MAP_SHARED, xc_handle, 0);
if ( addr == MAP_FAILED )
return NULL;
ioctlx.num=num;
ioctlx.dom=dom;
ioctlx.addr=(unsigned long)addr;
ioctlx.arr=arr;
if ( ioctl( xc_handle, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx ) < 0 )
{
int saved_errno = errno;
perror("XXXXXXXX");
(void)munmap(addr, num*PAGE_SIZE);
errno = saved_errno;
return NULL;
}
return addr;
}
/*******************/
void *xc_map_foreign_range(int xc_handle, u32 dom,
int size, int prot,
unsigned long mfn )
{
privcmd_mmap_t ioctlx;
privcmd_mmap_entry_t entry;
void *addr;
addr = mmap(NULL, size, prot, MAP_SHARED, xc_handle, 0);
if ( addr == MAP_FAILED )
return NULL;
ioctlx.num=1;
ioctlx.dom=dom;
ioctlx.entry=&entry;
entry.va=(unsigned long) addr;
entry.mfn=mfn;
entry.npages=(size+PAGE_SIZE-1)>>PAGE_SHIFT;
if ( ioctl( xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx ) < 0 )
{
int saved_errno = errno;
(void)munmap(addr, size);
errno = saved_errno;
return NULL;
}
return addr;
}
/*******************/
/* NB: arr must be mlock'ed */
int get_pfn_type_batch(int xc_handle,
u32 dom, int num, unsigned long *arr)
{
dom0_op_t op;
op.cmd = DOM0_GETPAGEFRAMEINFO2;
op.u.getpageframeinfo2.domain = (domid_t)dom;
op.u.getpageframeinfo2.num = num;
op.u.getpageframeinfo2.array = arr;
return do_dom0_op(xc_handle, &op);
}
#define GETPFN_ERR (~0U)
unsigned int get_pfn_type(int xc_handle,
unsigned long mfn,
u32 dom)
{
dom0_op_t op;
op.cmd = DOM0_GETPAGEFRAMEINFO;
op.u.getpageframeinfo.pfn = mfn;
op.u.getpageframeinfo.domain = (domid_t)dom;
if ( do_dom0_op(xc_handle, &op) < 0 )
{
PERROR("Unexpected failure when getting page frame info!");
return GETPFN_ERR;
}
return op.u.getpageframeinfo.type;
}
/*******************/
int pin_table(
int xc_handle, unsigned int type, unsigned long mfn, domid_t dom)
{
struct mmuext_op op;
op.cmd = type;
op.mfn = mfn;
if ( do_mmuext_op(xc_handle, &op, 1, dom) < 0 )
return 1;
return 0;
}
static int flush_mmu_updates(int xc_handle, mmu_t *mmu)
{
int err = 0;
privcmd_hypercall_t hypercall;
if ( mmu->idx == 0 )
return 0;
hypercall.op = __HYPERVISOR_mmu_update;
hypercall.arg[0] = (unsigned long)mmu->updates;
hypercall.arg[1] = (unsigned long)mmu->idx;
hypercall.arg[2] = 0;
hypercall.arg[3] = mmu->subject;
if ( mlock(mmu->updates, sizeof(mmu->updates)) != 0 )
{
PERROR("flush_mmu_updates: mmu updates mlock failed");
err = 1;
goto out;
}
if ( do_xen_hypercall(xc_handle, &hypercall) < 0 )
{
ERROR("Failure when submitting mmu updates");
err = 1;
}
mmu->idx = 0;
safe_munlock(mmu->updates, sizeof(mmu->updates));
out:
return err;
}
mmu_t *init_mmu_updates(int xc_handle, domid_t dom)
{
mmu_t *mmu = malloc(sizeof(mmu_t));
if ( mmu == NULL )
return mmu;
mmu->idx = 0;
mmu->subject = dom;
return mmu;
}
int add_mmu_update(int xc_handle, mmu_t *mmu,
unsigned long ptr, unsigned long val)
{
mmu->updates[mmu->idx].ptr = ptr;
mmu->updates[mmu->idx].val = val;
if ( ++mmu->idx == MAX_MMU_UPDATES )
return flush_mmu_updates(xc_handle, mmu);
return 0;
}
int finish_mmu_updates(int xc_handle, mmu_t *mmu)
{
return flush_mmu_updates(xc_handle, mmu);
}
long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid, int vcpu )
{
dom0_op_t op;
op.cmd = DOM0_GETVCPUCONTEXT;
op.u.getvcpucontext.domain = (domid_t)domid;
op.u.getvcpucontext.vcpu = (u16)vcpu;
op.u.getvcpucontext.ctxt = NULL;
if ( (do_dom0_op(xc_handle, &op) < 0) )
{
PERROR("Could not get info on domain");
return -1;
}
return op.u.getvcpucontext.cpu_time;
}
/* This is shared between save and restore, and may generally be useful. */
unsigned long csum_page (void * page)
{
int i;
unsigned long *p = page;
unsigned long long sum=0;
for ( i = 0; i < (PAGE_SIZE/sizeof(unsigned long)); i++ )
sum += p[i];
return sum ^ (sum>>32);
}
unsigned long xc_get_m2p_start_mfn ( int xc_handle )
{
unsigned long mfn;
if ( ioctl( xc_handle, IOCTL_PRIVCMD_GET_MACH2PHYS_START_MFN, &mfn ) < 0 )
{
perror("xc_get_m2p_start_mfn:");
return 0;
}
return mfn;
}
int xc_get_pfn_list(int xc_handle,
u32 domid,
unsigned long *pfn_buf,
unsigned long max_pfns)
{
dom0_op_t op;
int ret;
op.cmd = DOM0_GETMEMLIST;
op.u.getmemlist.domain = (domid_t)domid;
op.u.getmemlist.max_pfns = max_pfns;
op.u.getmemlist.buffer = pfn_buf;
if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
{
PERROR("xc_get_pfn_list: pfn_buf mlock failed");
return -1;
}
ret = do_dom0_op(xc_handle, &op);
safe_munlock(pfn_buf, max_pfns * sizeof(unsigned long));
#if 0
#ifdef DEBUG
DPRINTF(("Ret for xc_get_pfn_list is %d\n", ret));
if (ret >= 0) {
int i, j;
for (i = 0; i < op.u.getmemlist.num_pfns; i += 16) {
fprintf(stderr, "0x%x: ", i);
for (j = 0; j < 16; j++)
fprintf(stderr, "0x%lx ", pfn_buf[i + j]);
fprintf(stderr, "\n");
}
}
#endif
#endif
return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
}
#ifdef __ia64__
int xc_ia64_get_pfn_list(int xc_handle,
u32 domid,
unsigned long *pfn_buf,
unsigned int start_page,
unsigned int nr_pages)
{
dom0_op_t op;
int ret;
op.cmd = DOM0_GETMEMLIST;
op.u.getmemlist.domain = (domid_t)domid;
op.u.getmemlist.max_pfns = ((unsigned long)start_page << 32) | nr_pages;
op.u.getmemlist.buffer = pfn_buf;
if ( mlock(pfn_buf, nr_pages * sizeof(unsigned long)) != 0 )
{
PERROR("Could not lock pfn list buffer");
return -1;
}
/* XXX Hack to put pages in TLB, hypervisor should be able to handle this */
memset(pfn_buf, 0, nr_pages * sizeof(unsigned long));
ret = do_dom0_op(xc_handle, &op);
(void)munlock(pfn_buf, nr_pages * sizeof(unsigned long));
return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
}
#endif
long xc_get_tot_pages(int xc_handle, u32 domid)
{
dom0_op_t op;
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)domid;
return (do_dom0_op(xc_handle, &op) < 0) ?
-1 : op.u.getdomaininfo.tot_pages;
}
int xc_copy_to_domain_page(int xc_handle,
u32 domid,
unsigned long dst_pfn,
void *src_page)
{
void *vaddr = xc_map_foreign_range(
xc_handle, domid, PAGE_SIZE, PROT_WRITE, dst_pfn);
if ( vaddr == NULL )
return -1;
memcpy(vaddr, src_page, PAGE_SIZE);
munmap(vaddr, PAGE_SIZE);
return 0;
}
unsigned long xc_get_filesz(int fd)
{
u16 sig;
u32 _sz = 0;
unsigned long sz;
lseek(fd, 0, SEEK_SET);
if ( read(fd, &sig, sizeof(sig)) != sizeof(sig) )
return 0;
sz = lseek(fd, 0, SEEK_END);
if ( sig == 0x8b1f ) /* GZIP signature? */
{
lseek(fd, -4, SEEK_END);
if ( read(fd, &_sz, 4) != 4 )
return 0;
sz = _sz;
}
lseek(fd, 0, SEEK_SET);
return sz;
}
char *xc_read_kernel_image(const char *filename, unsigned long *size)
{
int kernel_fd = -1;
gzFile kernel_gfd = NULL;
char *image = NULL;
unsigned int bytes;
if ( (kernel_fd = open(filename, O_RDONLY)) < 0 )
{
PERROR("Could not open kernel image");
goto out;
}
if ( (*size = xc_get_filesz(kernel_fd)) == 0 )
{
PERROR("Could not read kernel image");
goto out;
}
if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
{
PERROR("Could not allocate decompression state for state file");
goto out;
}
if ( (image = malloc(*size)) == NULL )
{
PERROR("Could not allocate memory for kernel image");
goto out;
}
if ( (bytes = gzread(kernel_gfd, image, *size)) != *size )
{
PERROR("Error reading kernel image, could not"
" read the whole image (%d != %ld).", bytes, *size);
free(image);
image = NULL;
}
out:
if ( kernel_gfd != NULL )
gzclose(kernel_gfd);
else if ( kernel_fd >= 0 )
close(kernel_fd);
return image;
}
void xc_map_memcpy(unsigned long dst, char *src, unsigned long size,
int xch, u32 dom, unsigned long *parray,
unsigned long vstart)
{
char *va;
unsigned long chunksz, done, pa;
for ( done = 0; done < size; done += chunksz )
{
pa = dst + done - vstart;
va = xc_map_foreign_range(
xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
chunksz = size - done;
if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
memcpy(va + (pa & (PAGE_SIZE-1)), src + done, chunksz);
munmap(va, PAGE_SIZE);
}
}
int xc_dom0_op(int xc_handle, dom0_op_t *op)
{
return do_dom0_op(xc_handle, op);
}