static int device_nic_val(caml_gc *gc, libxl_device_nic *c_val, value v)
{
	CAMLparam1(v);
	int i;
	int ret = 0;
	c_val->backend_domid = Int_val(Field(v, 0));
	c_val->devid = Int_val(Field(v, 1));
	c_val->mtu = Int_val(Field(v, 2));
	c_val->model = dup_String_val(gc, Field(v, 3));

	if (Wosize_val(Field(v, 4)) != 6) {
		ret = 1;
		goto out;
	}
	for (i = 0; i < 6; i++)
		c_val->mac[i] = Int_val(Field(Field(v, 4), i));

	/* not handling c_val->ip */
	c_val->bridge = dup_String_val(gc, Field(v, 5));
	c_val->ifname = dup_String_val(gc, Field(v, 6));
	c_val->script = dup_String_val(gc, Field(v, 7));
	c_val->nictype = (Int_val(Field(v, 8))) + NICTYPE_IOEMU;

out:
	CAMLreturn(ret);
}
static int domain_build_info_val (caml_gc *gc, libxl_domain_build_info *c_val, value v)
{
	CAMLparam1(v);
	CAMLlocal1(infopriv);

	c_val->max_vcpus = Int_val(Field(v, 0));
	c_val->cur_vcpus = Int_val(Field(v, 1));
	c_val->max_memkb = Int64_val(Field(v, 2));
	c_val->target_memkb = Int64_val(Field(v, 3));
	c_val->video_memkb = Int64_val(Field(v, 4));
	c_val->shadow_memkb = Int64_val(Field(v, 5));
	c_val->kernel.path = dup_String_val(gc, Field(v, 6));
	c_val->is_hvm = Tag_val(Field(v, 7)) == 0;
	infopriv = Field(Field(v, 7), 0);
	if (c_val->hvm) {
		c_val->u.hvm.pae = Bool_val(Field(infopriv, 0));
		c_val->u.hvm.apic = Bool_val(Field(infopriv, 1));
		c_val->u.hvm.acpi = Bool_val(Field(infopriv, 2));
		c_val->u.hvm.nx = Bool_val(Field(infopriv, 3));
		c_val->u.hvm.viridian = Bool_val(Field(infopriv, 4));
		c_val->u.hvm.timeoffset = dup_String_val(gc, Field(infopriv, 5));
		c_val->u.hvm.timer_mode = Int_val(Field(infopriv, 6));
		c_val->u.hvm.hpet = Int_val(Field(infopriv, 7));
		c_val->u.hvm.vpt_align = Int_val(Field(infopriv, 8));
	} else {
		c_val->u.pv.slack_memkb = Int64_val(Field(infopriv, 0));
		c_val->u.pv.cmdline = dup_String_val(gc, Field(infopriv, 1));
		c_val->u.pv.ramdisk.path = dup_String_val(gc, Field(infopriv, 2));
		c_val->u.pv.features = dup_String_val(gc, Field(infopriv, 3));
	}

	CAMLreturn(0);
}
static int device_disk_val(caml_gc *gc, libxl_device_disk *c_val, value v)
{
	CAMLparam1(v);

	c_val->backend_domid = Int_val(Field(v, 0));
	c_val->pdev_path = dup_String_val(gc, Field(v, 1));
	c_val->vdev = dup_String_val(gc, Field(v, 2));
        c_val->backend = (Int_val(Field(v, 3)));
        c_val->format = (Int_val(Field(v, 4)));
	c_val->unpluggable = Bool_val(Field(v, 5));
	c_val->readwrite = Bool_val(Field(v, 6));
	c_val->is_cdrom = Bool_val(Field(v, 7));

	CAMLreturn(0);
}
static int device_vfb_val(caml_gc *gc, libxl_device_vfb *c_val, value v)
{
	CAMLparam1(v);

	c_val->backend_domid = Int_val(Field(v, 0));
	c_val->devid = Int_val(Field(v, 1));
	c_val->vnc = Bool_val(Field(v, 2));
	c_val->vnclisten = dup_String_val(gc, Field(v, 3));
	c_val->vncpasswd = dup_String_val(gc, Field(v, 4));
	c_val->vncdisplay = Int_val(Field(v, 5));
	c_val->keymap = dup_String_val(gc, Field(v, 6));
	c_val->sdl = Bool_val(Field(v, 7));
	c_val->opengl = Bool_val(Field(v, 8));
	c_val->display = dup_String_val(gc, Field(v, 9));
	c_val->xauthority = dup_String_val(gc, Field(v, 10));

	CAMLreturn(0);
}
static int string_string_tuple_array_val (caml_gc *gc, char ***c_val, value v)
{
	CAMLparam1(v);
	CAMLlocal1(a);
	int i;
	char **array;

	for (i = 0, a = Field(v, 5); a != Val_emptylist; a = Field(a, 1)) { i++; }

	array = gc_calloc(gc, (i + 1) * 2, sizeof(char *));
	if (!array)
		return 1;
	for (i = 0, a = Field(v, 5); a != Val_emptylist; a = Field(a, 1), i++) {
		value b = Field(a, 0);
		array[i * 2] = dup_String_val(gc, Field(b, 0));
		array[i * 2 + 1] = dup_String_val(gc, Field(b, 1));
	}
	*c_val = array;
	CAMLreturn(0);
}
/* external _create_logger: (string * string) -> handle = "stub_xtl_create_logger" */
CAMLprim value stub_xtl_create_logger(value cbs)
{
	CAMLparam1(cbs);
	CAMLlocal1(handle);
	struct caml_xtl *xtl = malloc(sizeof(*xtl));
	if (xtl == NULL)
		caml_raise_out_of_memory();

	memset(xtl, 0, sizeof(*xtl));

	xtl->vtable.vmessage = &stub_xtl_ocaml_vmessage;
	xtl->vtable.progress = &stub_xtl_ocaml_progress;
	xtl->vtable.destroy = &xtl_destroy;

	xtl->vmessage_cb = dup_String_val(Field(cbs, 0));
	xtl->progress_cb = dup_String_val(Field(cbs, 1));

	handle = caml_alloc_custom(&xentoollogger_custom_operations, sizeof(xtl), 0, 1);
	Xtl_val(handle) = xtl;

	CAMLreturn(handle);
}
static int domain_create_info_val (caml_gc *gc, libxl_domain_create_info *c_val, value v)
{
	CAMLparam1(v);
	CAMLlocal1(a);
	uint8_t *uuid = libxl_uuid_bytearray(&c_val->uuid);
	int i;

	c_val->hvm = Bool_val(Field(v, 0));
	c_val->hap = Bool_val(Field(v, 1));
	c_val->oos = Bool_val(Field(v, 2));
	c_val->ssidref = Int32_val(Field(v, 3));
	c_val->name = dup_String_val(gc, Field(v, 4));
	a = Field(v, 5);
	for (i = 0; i < 16; i++)
		uuid[i] = Int_val(Field(a, i));
	string_string_tuple_array_val(gc, &(c_val->xsdata), Field(v, 6));
	string_string_tuple_array_val(gc, &(c_val->platformdata), Field(v, 7));

	c_val->poolid = Int32_val(Field(v, 8));
	c_val->poolname = dup_String_val(gc, Field(v, 9));

	CAMLreturn(0);
}
value stub_xl_send_debug_keys(value keys)
{
	CAMLparam1(keys);
	int ret;
	char *c_keys;
	INIT_STRUCT();

	c_keys = dup_String_val(&gc, keys);

	INIT_CTX();
	ret = libxl_send_debug_keys(&ctx, c_keys);
	if (ret != 0)
		failwith_xl("send_debug_keys", &lg);
	FREE_CTX();
	CAMLreturn(Val_unit);
}
value stub_xl_send_trigger(value domid, value trigger, value vcpuid)
{
	CAMLparam3(domid, trigger, vcpuid);
	int ret;
	char *c_trigger;
	INIT_STRUCT();

	c_trigger = dup_String_val(&gc, trigger);

	INIT_CTX();
	ret = libxl_send_trigger(&ctx, Int_val(domid), c_trigger, Int_val(vcpuid));
	if (ret != 0)
		failwith_xl("send_trigger", &lg);
	FREE_CTX();
	CAMLreturn(Val_unit);
}