mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
g->id is an array and is allocated as part of g itself; it's not a separate allocation. Coverity-ID: 1054980 Signed-off-by: Matthew Daley <mattjd@gmail.com> Acked-by: Tim Deegan <tim@xen.org> Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
625 lines
17 KiB
C
625 lines
17 KiB
C
/*
|
|
* kdd-xen.c -- xen-specific functions for the kdd debugging stub
|
|
*
|
|
* Tim Deegan <Tim.Deegan@citrix.com>
|
|
*
|
|
* Copyright (c) 2007-2010, Citrix Systems Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <inttypes.h>
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include <xenctrl.h>
|
|
#include <xen/xen.h>
|
|
#include <xen/hvm/save.h>
|
|
|
|
#include "kdd.h"
|
|
|
|
#define MAPSIZE 4093 /* Prime */
|
|
|
|
#define PAGE_SHIFT 12
|
|
#define PAGE_SIZE (1U << PAGE_SHIFT)
|
|
|
|
struct kdd_guest {
|
|
struct xentoollog_logger xc_log; /* Must be first for xc log callbacks */
|
|
xc_interface *xc_handle;
|
|
uint32_t domid;
|
|
char id[80];
|
|
FILE *log;
|
|
int verbosity;
|
|
void *hvm_buf;
|
|
uint32_t hvm_sz;
|
|
uint32_t pfns[MAPSIZE];
|
|
void * maps[MAPSIZE];
|
|
};
|
|
|
|
|
|
/* Flush any mappings we have of the guest memory: it's not polite
|
|
* top hold on to them while the guest is running */
|
|
static void flush_maps(kdd_guest *g)
|
|
{
|
|
int i;
|
|
for (i = 0; i < MAPSIZE; i++) {
|
|
if (g->maps[i] != NULL)
|
|
munmap(g->maps[i], PAGE_SIZE);
|
|
g->maps[i] = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/* Halt the guest so we can debug it */
|
|
void kdd_halt(kdd_guest *g)
|
|
{
|
|
uint32_t sz;
|
|
void *buf;
|
|
|
|
xc_domain_pause(g->xc_handle, g->domid);
|
|
|
|
/* How much space do we need for the HVM state? */
|
|
sz = xc_domain_hvm_getcontext(g->xc_handle, g->domid, 0, 0);
|
|
if (sz == (uint32_t) -1) {
|
|
KDD_LOG(g, "Can't get HVM state size for domid %"PRIu32": %s\n",
|
|
g->domid, strerror(errno));
|
|
return;
|
|
}
|
|
buf = realloc(g->hvm_buf, sz);
|
|
if (!buf) {
|
|
KDD_LOG(g, "Couldn't allocate %"PRIu32" for HVM buffer\n", sz);
|
|
return;
|
|
}
|
|
g->hvm_buf = buf;
|
|
g->hvm_sz = sz;
|
|
memset(buf, 0, sz);
|
|
|
|
/* Get the HVM state */
|
|
sz = xc_domain_hvm_getcontext(g->xc_handle, g->domid, buf, sz);
|
|
if (sz == (uint32_t) -1) {
|
|
KDD_LOG(g, "Can't get HVM state for domid %"PRIu32": %s\n",
|
|
g->domid, strerror(errno));
|
|
}
|
|
}
|
|
|
|
/* Check whether the guest has stopped. Returns 'interesting' vcpu or -1 */
|
|
/* TODO: open DEBUG_VIRQ if it's free and wait for events rather than
|
|
* always polling the guest state */
|
|
int kdd_poll_guest(kdd_guest *g)
|
|
{
|
|
/* TODO: finish plumbing through polling for breakpoints */
|
|
return 0;
|
|
}
|
|
|
|
/* Update the HVM state */
|
|
static void hvm_writeback(kdd_guest *g)
|
|
{
|
|
if (g->hvm_buf && xc_domain_hvm_setcontext(g->xc_handle, g->domid,
|
|
g->hvm_buf, g->hvm_sz))
|
|
KDD_LOG(g, "Can't set HVM state for domid %"PRIu32": %s\n",
|
|
g->domid, strerror(errno));
|
|
}
|
|
|
|
/* Start the guest running again */
|
|
void kdd_run(kdd_guest *g)
|
|
{
|
|
flush_maps(g);
|
|
hvm_writeback(g);
|
|
xc_domain_unpause(g->xc_handle, g->domid);
|
|
}
|
|
|
|
/* How many CPUs are there in this guest? */
|
|
int kdd_count_cpus(kdd_guest *g)
|
|
{
|
|
struct hvm_save_descriptor *desc;
|
|
int maxcpu = 0;
|
|
|
|
if (!g->hvm_buf)
|
|
return 0;
|
|
|
|
/* Scan the CPU save records. */
|
|
for (desc = g->hvm_buf;
|
|
(void *) desc >= g->hvm_buf && (void *) desc < g->hvm_buf + g->hvm_sz;
|
|
desc = ((void *)desc) + (sizeof *desc) + desc->length) {
|
|
if (desc->typecode == HVM_SAVE_CODE(CPU)) {
|
|
if (maxcpu < desc->instance)
|
|
maxcpu = desc->instance;
|
|
}
|
|
}
|
|
return maxcpu + 1;
|
|
}
|
|
|
|
/* Helper fn: get CPU state from cached HVM state */
|
|
static struct hvm_hw_cpu *get_cpu(kdd_guest *g, int cpuid)
|
|
{
|
|
struct hvm_save_descriptor *desc;
|
|
struct hvm_hw_cpu *cpu;
|
|
|
|
if (!g->hvm_buf)
|
|
return NULL;
|
|
|
|
/* Find the right CPU */
|
|
for (desc = g->hvm_buf;
|
|
(void *) desc >= g->hvm_buf && (void *) desc < g->hvm_buf + g->hvm_sz;
|
|
desc = ((void *)desc) + (sizeof *desc) + desc->length) {
|
|
if (desc->typecode == HVM_SAVE_CODE(CPU) && desc->instance == cpuid) {
|
|
cpu = ((void *)desc) + (sizeof *desc);
|
|
if ((void *) cpu + sizeof (*cpu) <= g->hvm_buf + g->hvm_sz)
|
|
return cpu;
|
|
}
|
|
}
|
|
|
|
KDD_LOG(g, "Dom %"PRIu32" has no CPU %i\n", g->domid, cpuid);
|
|
return NULL;
|
|
}
|
|
|
|
/* Helper fn: get APIC state from cached HVM state */
|
|
static struct hvm_hw_lapic_regs *get_lapic(kdd_guest *g, int cpuid)
|
|
{
|
|
struct hvm_save_descriptor *desc;
|
|
struct hvm_hw_lapic_regs *regs;
|
|
|
|
if (!g->hvm_buf)
|
|
return NULL;
|
|
|
|
/* Find the right CPU's LAPIC */
|
|
for (desc = g->hvm_buf;
|
|
(void *) desc >= g->hvm_buf && (void *) desc < g->hvm_buf + g->hvm_sz;
|
|
desc = ((void *)desc) + (sizeof *desc) + desc->length) {
|
|
if (desc->typecode == HVM_SAVE_CODE(LAPIC_REGS) && desc->instance == cpuid) {
|
|
regs = ((void *)desc) + (sizeof *desc);
|
|
if ((void *) regs + sizeof (*regs) <= g->hvm_buf + g->hvm_sz)
|
|
return regs;
|
|
}
|
|
}
|
|
|
|
KDD_LOG(g, "Dom %"PRIu32" has no LAPIC %i\n", g->domid, cpuid);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* Accessors for guest user registers */
|
|
static void kdd_get_regs_x86_32(struct hvm_hw_cpu *cpu, kdd_regs_x86_32 *r)
|
|
{
|
|
r->gs = cpu->gs_sel;
|
|
r->fs = cpu->fs_sel;
|
|
r->es = cpu->es_sel;
|
|
r->ds = cpu->ds_sel;
|
|
r->edi = cpu->rdi;
|
|
r->esi = cpu->rsi;
|
|
r->ebx = cpu->rbx;
|
|
r->edx = cpu->rdx;
|
|
r->ecx = cpu->rcx;
|
|
r->eax = cpu->rax;
|
|
r->ebp = cpu->rbp;
|
|
r->eip = cpu->rip;
|
|
r->cs = cpu->cs_sel;
|
|
r->eflags = cpu->rflags;
|
|
r->esp = cpu->rsp;
|
|
r->ss = cpu->ss_sel;
|
|
memcpy(r->fp, cpu->fpu_regs, 112); // 108 save area + 4 of ???
|
|
}
|
|
|
|
static void kdd_set_regs_x86_32(struct hvm_hw_cpu *cpu, kdd_regs_x86_32 *r)
|
|
{
|
|
cpu->gs_sel = r->gs;
|
|
cpu->fs_sel = r->fs;
|
|
cpu->es_sel = r->es;
|
|
cpu->ds_sel = r->ds;
|
|
cpu->rdi = r->edi;
|
|
cpu->rsi = r->esi;
|
|
cpu->rbx = r->ebx;
|
|
cpu->rdx = r->edx;
|
|
cpu->rcx = r->ecx;
|
|
cpu->rax = r->eax;
|
|
cpu->rbp = r->ebp;
|
|
cpu->rip = r->eip;
|
|
cpu->cs_sel = r->cs;
|
|
cpu->rflags = r->eflags;
|
|
cpu->rsp = r->esp;
|
|
cpu->ss_sel = r->ss;
|
|
memcpy(cpu->fpu_regs, r->fp, 112); // 108 save area + 4 of ???
|
|
}
|
|
|
|
static void kdd_get_regs_x86_64(struct hvm_hw_cpu *cpu, kdd_regs_x86_64 *r)
|
|
{
|
|
// XXX debug pattern
|
|
uint16_t i;
|
|
for (i = 0 ; i < (sizeof *r / 2) ; i++)
|
|
((uint16_t *)r)[i] = i;
|
|
|
|
r->cs = cpu->cs_sel;
|
|
r->ds = cpu->ds_sel;
|
|
r->es = cpu->es_sel;
|
|
r->fs = cpu->fs_sel;
|
|
r->gs = cpu->gs_sel;
|
|
r->ss = cpu->ss_sel;
|
|
r->rflags = cpu->rflags;
|
|
r->dr0 = cpu->dr0;
|
|
r->dr1 = cpu->dr1;
|
|
r->dr2 = cpu->dr2;
|
|
r->dr3 = cpu->dr3;
|
|
r->dr6 = cpu->dr6;
|
|
r->dr7 = cpu->dr7;
|
|
r->rax = cpu->rax;
|
|
r->rcx = cpu->rcx;
|
|
r->rdx = cpu->rdx;
|
|
r->rbx = cpu->rbx;
|
|
r->rsp = cpu->rsp;
|
|
r->rbp = cpu->rbp;
|
|
r->rsi = cpu->rsi;
|
|
r->rdi = cpu->rdi;
|
|
r->r8 = cpu->r8;
|
|
r->r9 = cpu->r9;
|
|
r->r10 = cpu->r10;
|
|
r->r11 = cpu->r11;
|
|
r->r12 = cpu->r12;
|
|
r->r13 = cpu->r13;
|
|
r->r14 = cpu->r14;
|
|
r->r15 = cpu->r15;
|
|
r->rip = cpu->rip;
|
|
memcpy(r->fp, cpu->fpu_regs, 112); // Definitely not right
|
|
}
|
|
|
|
static void kdd_set_regs_x86_64(struct hvm_hw_cpu *cpu, kdd_regs_x86_64 *r)
|
|
{
|
|
cpu->cs_sel = r->cs;
|
|
cpu->ds_sel = r->ds;
|
|
cpu->es_sel = r->es;
|
|
cpu->fs_sel = r->fs;
|
|
cpu->gs_sel = r->gs;
|
|
cpu->ss_sel = r->ss;
|
|
cpu->rflags = r->rflags;
|
|
cpu->dr0 = r->dr0;
|
|
cpu->dr1 = r->dr1;
|
|
cpu->dr2 = r->dr2;
|
|
cpu->dr3 = r->dr3;
|
|
cpu->dr6 = r->dr6;
|
|
cpu->dr7 = r->dr7;
|
|
cpu->rax = r->rax;
|
|
cpu->rcx = r->rcx;
|
|
cpu->rdx = r->rdx;
|
|
cpu->rbx = r->rbx;
|
|
cpu->rsp = r->rsp;
|
|
cpu->rbp = r->rbp;
|
|
cpu->rsi = r->rsi;
|
|
cpu->rdi = r->rdi;
|
|
cpu->r8 = r->r8;
|
|
cpu->r9 = r->r9;
|
|
cpu->r10 = r->r10;
|
|
cpu->r11 = r->r11;
|
|
cpu->r12 = r->r12;
|
|
cpu->r13 = r->r13;
|
|
cpu->r14 = r->r14;
|
|
cpu->r15 = r->r15;
|
|
cpu->rip = r->rip;
|
|
memcpy(r->fp, cpu->fpu_regs, 112); // Definitely not right
|
|
}
|
|
|
|
|
|
int kdd_get_regs(kdd_guest *g, int cpuid, kdd_regs *r, int w64)
|
|
{
|
|
struct hvm_hw_cpu *cpu;
|
|
|
|
cpu = get_cpu(g, cpuid);
|
|
if (!cpu)
|
|
return -1;
|
|
|
|
memset(r, 0, sizeof(*r));
|
|
|
|
if (w64)
|
|
kdd_get_regs_x86_64(cpu, &r->r64);
|
|
else
|
|
kdd_get_regs_x86_32(cpu, &r->r32);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int kdd_set_regs(kdd_guest *g, int cpuid, kdd_regs *r, int w64)
|
|
{
|
|
struct hvm_hw_cpu *cpu;
|
|
|
|
cpu = get_cpu(g, cpuid);
|
|
if (!cpu)
|
|
return -1;
|
|
|
|
if (w64)
|
|
kdd_set_regs_x86_64(cpu, &r->r64);
|
|
else
|
|
kdd_set_regs_x86_32(cpu, &r->r32);
|
|
|
|
hvm_writeback(g);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Accessors for guest control registers */
|
|
static void kdd_get_ctrl_x86_32(struct hvm_hw_cpu *cpu, kdd_ctrl_x86_32 *c)
|
|
{
|
|
c->cr0 = cpu->cr0;
|
|
c->cr2 = cpu->cr2;
|
|
c->cr3 = cpu->cr3;
|
|
c->cr4 = cpu->cr4;
|
|
c->dr0 = cpu->dr0;
|
|
c->dr1 = cpu->dr1;
|
|
c->dr2 = cpu->dr2;
|
|
c->dr3 = cpu->dr3;
|
|
c->dr6 = cpu->dr6;
|
|
c->dr7 = cpu->dr7;
|
|
c->gdt_base = cpu->gdtr_base;
|
|
c->gdt_limit = cpu->gdtr_limit;
|
|
c->idt_base = cpu->idtr_base;
|
|
c->idt_limit = cpu->idtr_limit;
|
|
c->tss_sel = cpu->tr_sel;
|
|
c->ldt_sel = cpu->ldtr_sel;
|
|
}
|
|
|
|
static void kdd_get_ctrl_x86_64(struct hvm_hw_cpu *cpu,
|
|
struct hvm_hw_lapic_regs *lapic,
|
|
kdd_ctrl_x86_64 *c)
|
|
{
|
|
c->cr0 = cpu->cr0;
|
|
c->cr2 = cpu->cr2;
|
|
c->cr3 = cpu->cr3;
|
|
c->cr4 = cpu->cr4;
|
|
c->dr0 = cpu->dr0;
|
|
c->dr1 = cpu->dr1;
|
|
c->dr2 = cpu->dr2;
|
|
c->dr3 = cpu->dr3;
|
|
c->dr6 = cpu->dr6;
|
|
c->dr7 = cpu->dr7;
|
|
c->gdt_base = cpu->gdtr_base;
|
|
c->gdt_limit = cpu->gdtr_limit;
|
|
c->idt_base = cpu->idtr_base;
|
|
c->idt_limit = cpu->idtr_limit;
|
|
c->tss_sel = cpu->tr_sel;
|
|
c->ldt_sel = cpu->ldtr_sel;
|
|
c->cr8 = lapic->data[0x80] >> 4; /* Top half of the low byte of the TPR */
|
|
}
|
|
|
|
|
|
int kdd_get_ctrl(kdd_guest *g, int cpuid, kdd_ctrl *ctrl, int w64)
|
|
{
|
|
struct hvm_hw_cpu *cpu;
|
|
struct hvm_hw_lapic_regs *lapic;
|
|
|
|
cpu = get_cpu(g, cpuid);
|
|
if (!cpu)
|
|
return -1;
|
|
|
|
if (w64) {
|
|
lapic = get_lapic(g, cpuid);
|
|
if (!lapic)
|
|
return -1;
|
|
kdd_get_ctrl_x86_64(cpu, lapic, &ctrl->c64);
|
|
} else {
|
|
kdd_get_ctrl_x86_32(cpu, &ctrl->c32);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int kdd_wrmsr(kdd_guest *g, int cpuid, uint32_t msr, uint64_t value)
|
|
{
|
|
struct hvm_hw_cpu *cpu;
|
|
|
|
cpu = get_cpu(g, cpuid);
|
|
if (!cpu)
|
|
return -1;
|
|
|
|
switch (msr) {
|
|
case 0x00000174: cpu->sysenter_cs = value; break;
|
|
case 0x00000175: cpu->sysenter_esp = value; break;
|
|
case 0x00000176: cpu->sysenter_eip = value; break;
|
|
case 0xc0000080: cpu->msr_efer = value; break;
|
|
case 0xc0000081: cpu->msr_star = value; break;
|
|
case 0xc0000082: cpu->msr_lstar = value; break;
|
|
case 0xc0000083: cpu->msr_cstar = value; break;
|
|
case 0xc0000084: cpu->msr_syscall_mask = value; break;
|
|
case 0xc0000100: cpu->fs_base = value; break;
|
|
case 0xc0000101: cpu->gs_base = value; break;
|
|
case 0xc0000102: cpu->shadow_gs = value; break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
hvm_writeback(g);
|
|
return 0;
|
|
}
|
|
|
|
int kdd_rdmsr(kdd_guest *g, int cpuid, uint32_t msr, uint64_t *value)
|
|
{
|
|
struct hvm_hw_cpu *cpu;
|
|
|
|
cpu = get_cpu(g, cpuid);
|
|
if (!cpu)
|
|
return -1;
|
|
|
|
switch (msr) {
|
|
case 0x00000174: *value = cpu->sysenter_cs; break;
|
|
case 0x00000175: *value = cpu->sysenter_esp; break;
|
|
case 0x00000176: *value = cpu->sysenter_eip; break;
|
|
case 0xc0000080: *value = cpu->msr_efer; break;
|
|
case 0xc0000081: *value = cpu->msr_star; break;
|
|
case 0xc0000082: *value = cpu->msr_lstar; break;
|
|
case 0xc0000083: *value = cpu->msr_cstar; break;
|
|
case 0xc0000084: *value = cpu->msr_syscall_mask; break;
|
|
case 0xc0000100: *value = cpu->fs_base; break;
|
|
case 0xc0000101: *value = cpu->gs_base; break;
|
|
case 0xc0000102: *value = cpu->shadow_gs; break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Accessor for guest physical memory */
|
|
static uint32_t kdd_access_physical_page(kdd_guest *g, uint64_t addr,
|
|
uint32_t len, uint8_t *buf, int write)
|
|
{
|
|
uint32_t map_pfn, map_offset;
|
|
uint8_t *map;
|
|
|
|
map_pfn = (addr >> PAGE_SHIFT);
|
|
map_offset = addr & (PAGE_SIZE - 1);
|
|
|
|
/* Evict any mapping of the wrong frame from our slot */
|
|
if (g->pfns[map_pfn % MAPSIZE] != map_pfn
|
|
&& g->maps[map_pfn % MAPSIZE] != NULL) {
|
|
munmap(g->maps[map_pfn % MAPSIZE], PAGE_SIZE);
|
|
g->maps[map_pfn % MAPSIZE] = NULL;
|
|
}
|
|
g->pfns[map_pfn % MAPSIZE] = map_pfn;
|
|
|
|
/* Now map the frame if it's not already there */
|
|
if (g->maps[map_pfn % MAPSIZE] != NULL)
|
|
map = g->maps[map_pfn % MAPSIZE];
|
|
else {
|
|
map = xc_map_foreign_range(g->xc_handle,
|
|
g->domid,
|
|
PAGE_SIZE,
|
|
PROT_READ|PROT_WRITE,
|
|
map_pfn);
|
|
|
|
KDD_DEBUG(g, "map: %u, 0x%16.16"PRIx32": %p +0x%"PRIx32"\n",
|
|
write ? PROT_READ|PROT_WRITE : PROT_READ,
|
|
map_pfn, map, map_offset);
|
|
|
|
if (!map)
|
|
return 0;
|
|
g->maps[map_pfn % MAPSIZE] = map;
|
|
}
|
|
|
|
if (write)
|
|
memcpy(map + map_offset, buf, len);
|
|
else
|
|
memcpy(buf, map + map_offset, len);
|
|
|
|
return len;
|
|
}
|
|
|
|
uint32_t kdd_access_physical(kdd_guest *g, uint64_t addr,
|
|
uint32_t len, uint8_t *buf, int write)
|
|
{
|
|
uint32_t chunk, rv, done = 0;
|
|
while (len > 0) {
|
|
chunk = PAGE_SIZE - (addr & (PAGE_SIZE - 1));
|
|
if (chunk > len)
|
|
chunk = len;
|
|
rv = kdd_access_physical_page(g, addr, chunk, buf, write);
|
|
done += rv;
|
|
if (rv != chunk)
|
|
return done;
|
|
addr += chunk;
|
|
buf += chunk;
|
|
len -= chunk;
|
|
}
|
|
return done;
|
|
}
|
|
|
|
|
|
/* Plumb libxc log messages into our own logging */
|
|
static void kdd_xc_log(struct xentoollog_logger *logger,
|
|
xentoollog_level level,
|
|
int errnoval /* or -1 */,
|
|
const char *context /* eg "xc", "xl", may be 0 */,
|
|
const char *format /* without level, context, \n */,
|
|
va_list al)
|
|
{
|
|
kdd_guest *g = (kdd_guest *) logger;
|
|
/* Suppress most libxc levels unless we're logging at debug level */
|
|
if (g->verbosity < 1 || (level < XTL_WARN && g->verbosity < 3))
|
|
return;
|
|
fprintf(g->log, "libxc[%s:%i:%i]: ", context ? : "?", level, errnoval);
|
|
vfprintf(g->log, format, al);
|
|
fprintf(g->log, "\n");
|
|
(void) fflush(g->log);
|
|
}
|
|
|
|
|
|
/* Set up guest-specific state */
|
|
kdd_guest *kdd_guest_init(char *arg, FILE *log, int verbosity)
|
|
{
|
|
kdd_guest *g = NULL;
|
|
xc_interface *xch = NULL;
|
|
uint32_t domid;
|
|
xc_dominfo_t info;
|
|
|
|
g = calloc(1, sizeof (kdd_guest));
|
|
if (!g)
|
|
goto err;
|
|
g->log = log;
|
|
g->verbosity = verbosity;
|
|
g->xc_log.vmessage = kdd_xc_log;
|
|
|
|
xch = xc_interface_open(&g->xc_log, NULL, 0);
|
|
if (!xch)
|
|
goto err;
|
|
g->xc_handle = xch;
|
|
|
|
domid = strtoul(arg, NULL, 0);
|
|
if (domid == 0)
|
|
goto err;
|
|
g->domid = domid;
|
|
|
|
/* Check that the domain exists and is HVM */
|
|
if (xc_domain_getinfo(xch, domid, 1, &info) != 1 || !info.hvm)
|
|
goto err;
|
|
|
|
snprintf(g->id, (sizeof g->id) - 1,
|
|
"a xen guest with domain id %i", g->domid);
|
|
|
|
return g;
|
|
|
|
err:
|
|
free(g);
|
|
if (xch)
|
|
xc_interface_close(xch);
|
|
return NULL;
|
|
}
|
|
|
|
/* Say what kind of guest this is */
|
|
char *kdd_guest_identify(kdd_guest *g)
|
|
{
|
|
return g->id;
|
|
}
|
|
|
|
/* Tear down guest-specific state */
|
|
void kdd_guest_teardown(kdd_guest *g)
|
|
{
|
|
flush_maps(g);
|
|
xc_interface_close(g->xc_handle);
|
|
free(g->hvm_buf);
|
|
free(g);
|
|
}
|