Skip to content

Commit

Permalink
tests: add mock vmmapi calls
Browse files Browse the repository at this point in the history
  • Loading branch information
fabianfreyer committed Feb 16, 2018
1 parent 9eddf37 commit 58aef22
Show file tree
Hide file tree
Showing 3 changed files with 388 additions and 1 deletion.
291 changes: 291 additions & 0 deletions tests/mock/bhyveload.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,294 @@ cb_copyout(void *arg, uint64_t from, void *to, size_t size)
return (0);
}

struct seg_desc {
uint64_t base;
uint32_t limit;
uint32_t access;
};


/* Mock vm_{get,set}_desc from vmmapi. */
static SLIST_HEAD(vm_seg_desc_head, vm_seg_desc) vm_seg_desc_head;

struct vm_seg_desc { /* data or code segment */
int cpuid;
int regnum; /* enum vm_reg_name */
struct seg_desc desc;
SLIST_ENTRY(vm_seg_desc) next;
};

int
vm_set_desc(struct vmctx *ctx, int vcpu, int reg,
uint64_t base, uint32_t limit, uint32_t access)
{
struct vm_seg_desc *segdesc;

SLIST_FOREACH(segdesc, &vm_seg_desc_head, next) {
if (segdesc->cpuid != vcpu || segdesc->regnum != reg)
continue;

segdesc->desc.base = base;
segdesc->desc.limit = limit;
segdesc->desc.access = access;
return 0;
}

segdesc = calloc(1, sizeof(struct vm_seg_desc));
segdesc->cpuid = vcpu;
segdesc->regnum = reg;
segdesc->desc.base = base;
segdesc->desc.limit = limit;
segdesc->desc.access = access;
SLIST_INSERT_HEAD(&vm_seg_desc_head, segdesc, next);
return 0;
}

int
vm_get_desc(struct vmctx *ctx, int vcpu, int reg,
uint64_t *base, uint32_t *limit, uint32_t *access)
{
struct vm_seg_desc *segdesc;

SLIST_FOREACH(segdesc, &vm_seg_desc_head, next) {
if (segdesc->cpuid != vcpu || segdesc->regnum != reg)
continue;

*base = segdesc->desc.base;
*limit = segdesc->desc.limit;
*access = segdesc->desc.access;
return 0;
}

*base = 0;
*limit = 0;
*access = 0;
return 0;
}

/* Mock vm_{get,set}_register from vmmapi. */
static SLIST_HEAD(vm_reg_head, vm_reg) vm_reg_head;

struct vm_reg { /* data or code segment */
int cpuid;
int regnum; /* enum vm_reg_name */
uint64_t value;
SLIST_ENTRY(vm_reg) next;
};

int
vm_set_register(struct vmctx *ctx, int vcpu, int reg, uint64_t val)
{
struct vm_reg *_reg;
printf("set register %d = %lu\n", reg, val);

SLIST_FOREACH(_reg, &vm_reg_head, next) {
if (_reg->cpuid != vcpu || _reg->regnum != reg)
continue;

_reg->value = val;
return 0;
}

_reg = calloc(1, sizeof(struct vm_reg));
_reg->cpuid = vcpu;
_reg->regnum = reg;
_reg->value = val;
SLIST_INSERT_HEAD(&vm_reg_head, _reg, next);
return 0;
}

int
vm_get_register(struct vmctx *ctx, int vcpu, int reg, uint64_t *retval)
{
struct vm_reg *_reg;

SLIST_FOREACH(_reg, &vm_reg_head, next) {
if (_reg->cpuid != vcpu || _reg->regnum != reg)
continue;

*retval = _reg->value;
printf("get register %d = %lu\n", reg, *retval);
return 0;
}

return 0;
}

/*
* The following function is taken from vmmapi.c
* From Intel Vol 3a:
* Table 9-1. IA-32 Processor States Following Power-up293gg, Reset or INIT
*/
#define CR0_NE 0x00000020
int
vcpu_reset(struct vmctx *vmctx, int vcpu)
{
int error;
uint64_t rflags, rip, cr0, cr4, zero, desc_base, rdx;
uint32_t desc_access, desc_limit;
uint16_t sel;

zero = 0;

rflags = 0x2;
error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RFLAGS, rflags);
if (error)
goto done;

rip = 0xfff0;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RIP, rip)) != 0)
goto done;

cr0 = CR0_NE;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR0, cr0)) != 0)
goto done;

if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR3, zero)) != 0)
goto done;

cr4 = 0;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR4, cr4)) != 0)
goto done;

/*
* CS: present, r/w, accessed, 16-bit, byte granularity, usable
*/
desc_base = 0xffff0000;
desc_limit = 0xffff;
desc_access = 0x0093;
error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_CS,
desc_base, desc_limit, desc_access);
if (error)
goto done;

sel = 0xf000;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CS, sel)) != 0)
goto done;

/*
* SS,DS,ES,FS,GS: present, r/w, accessed, 16-bit, byte granularity
*/
desc_base = 0;
desc_limit = 0xffff;
desc_access = 0x0093;
error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_SS,
desc_base, desc_limit, desc_access);
if (error)
goto done;

error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_DS,
desc_base, desc_limit, desc_access);
if (error)
goto done;

error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_ES,
desc_base, desc_limit, desc_access);
if (error)
goto done;

error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_FS,
desc_base, desc_limit, desc_access);
if (error)
goto done;

error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GS,
desc_base, desc_limit, desc_access);
if (error)
goto done;

sel = 0;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_SS, sel)) != 0)
goto done;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_DS, sel)) != 0)
goto done;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_ES, sel)) != 0)
goto done;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_FS, sel)) != 0)
goto done;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_GS, sel)) != 0)
goto done;

/* General purpose registers */
rdx = 0xf00;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RAX, zero)) != 0)
goto done;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBX, zero)) != 0)
goto done;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RCX, zero)) != 0)
goto done;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDX, rdx)) != 0)
goto done;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSI, zero)) != 0)
goto done;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RDI, zero)) != 0)
goto done;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RBP, zero)) != 0)
goto done;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSP, zero)) != 0)
goto done;

/* GDTR, IDTR */
desc_base = 0;
desc_limit = 0xffff;
desc_access = 0;
error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR,
desc_base, desc_limit, desc_access);
if (error != 0)
goto done;

error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_IDTR,
desc_base, desc_limit, desc_access);
if (error != 0)
goto done;

/* TR */
desc_base = 0;
desc_limit = 0xffff;
desc_access = 0x0000008b;
error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_TR, 0, 0, desc_access);
if (error)
goto done;

sel = 0;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_TR, sel)) != 0)
goto done;

/* LDTR */
desc_base = 0;
desc_limit = 0xffff;
desc_access = 0x00000082;
error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_LDTR, desc_base,
desc_limit, desc_access);
if (error)
goto done;

sel = 0;
if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_LDTR, 0)) != 0)
goto done;

/* XXX cr2, debug registers */

error = 0;
done:
return (error);
}

static int
cb_vm_set_register(void *arg, int vcpu, int reg, uint64_t val)
{
struct vmctx ctx;
return (vm_set_register(&ctx, vcpu, reg, val));
}

static int
cb_vm_set_desc(void *arg, int vcpu, int reg, uint64_t base, u_int limit,
u_int access)
{
struct vmctx ctx;
return (vm_set_desc(&ctx, vcpu, reg, base, limit, access));
}

struct loader_callbacks callbacks = {
.getc = cb_getc,
.putc = cb_putc,
Expand All @@ -400,4 +688,7 @@ struct loader_callbacks callbacks = {
.getmem = cb_getmem,

.getenv = cb_getenv,

.vm_set_register = cb_vm_set_register,
.vm_set_desc = cb_vm_set_desc,
};
59 changes: 58 additions & 1 deletion tests/mock/bhyveload.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,61 @@ extern void* lowmem_buffer;
extern struct loader_callbacks callbacks;

void addenv(const char *str);
void setmem(size_t lowmem, size_t highmem);
void setmem(size_t lowmem, size_t highmem);


/* vmmapi foo */

/* opaque struct */
struct vmctx {};

enum vm_reg_name {
VM_REG_GUEST_RAX,
VM_REG_GUEST_RBX,
VM_REG_GUEST_RCX,
VM_REG_GUEST_RDX,
VM_REG_GUEST_RSI,
VM_REG_GUEST_RDI,
VM_REG_GUEST_RBP,
VM_REG_GUEST_R8,
VM_REG_GUEST_R9,
VM_REG_GUEST_R10,
VM_REG_GUEST_R11,
VM_REG_GUEST_R12,
VM_REG_GUEST_R13,
VM_REG_GUEST_R14,
VM_REG_GUEST_R15,
VM_REG_GUEST_CR0,
VM_REG_GUEST_CR3,
VM_REG_GUEST_CR4,
VM_REG_GUEST_DR7,
VM_REG_GUEST_RSP,
VM_REG_GUEST_RIP,
VM_REG_GUEST_RFLAGS,
VM_REG_GUEST_ES,
VM_REG_GUEST_CS,
VM_REG_GUEST_SS,
VM_REG_GUEST_DS,
VM_REG_GUEST_FS,
VM_REG_GUEST_GS,
VM_REG_GUEST_LDTR,
VM_REG_GUEST_TR,
VM_REG_GUEST_IDTR,
VM_REG_GUEST_GDTR,
VM_REG_GUEST_EFER,
VM_REG_GUEST_CR2,
VM_REG_GUEST_PDPTE0,
VM_REG_GUEST_PDPTE1,
VM_REG_GUEST_PDPTE2,
VM_REG_GUEST_PDPTE3,
VM_REG_GUEST_INTR_SHADOW,
VM_REG_LAST
};

int vm_set_register(struct vmctx *ctx, int vcpu, int reg, uint64_t val);
int vm_get_register(struct vmctx *ctx, int vcpu, int reg, uint64_t *retval);
int vm_set_desc(struct vmctx *ctx, int vcpu, int reg,
uint64_t base, uint32_t limit, uint32_t access);
int vm_get_desc(struct vmctx *ctx, int vcpu, int reg,
uint64_t *base, uint32_t *limit, uint32_t *access);
int vcpu_reset(struct vmctx *ctx, int vcpu);
Loading

0 comments on commit 58aef22

Please sign in to comment.