static int
privcmd_HYPERVISOR_mmu_update(mmu_update_t *ureq, int count, int *scount,
    domid_t domid)
{
	mmu_update_t *kreq, single_kreq;
	import_export_t cnt_ie, req_ie;
	int error, kscount, bytes;

	bytes = count * sizeof (*kreq);
	kreq = (count == 1) ? &single_kreq : kmem_alloc(bytes, KM_SLEEP);

	error = import_buffer(&cnt_ie, scount, &kscount, sizeof (kscount),
	    IE_IMPEXP);
	if (error != 0)
		req_ie = null_ie;
	else
		error = import_buffer(&req_ie, ureq, kreq, bytes, IE_IMPEXP);

	DTRACE_XPV3(mmu__update__start, int, domid, int, count, mmu_update_t *,
	    ((error == -X_EFAULT) ? ureq : kreq));

	if (error == 0)
		error = HYPERVISOR_mmu_update(kreq, count, &kscount, domid);
	export_buffer(&cnt_ie, &error);
	export_buffer(&req_ie, &error);
	if (count != 1)
		kmem_free(kreq, bytes);

	DTRACE_XPV1(mmu__update__end, int, error);
	return (error);
}
static int
privcmd_HYPERVISOR_sched_op(int cmd, void *arg)
{
	int error;
	int size = 0;
	import_export_t op_ie;
	struct sched_remote_shutdown op;

	switch (cmd) {
	case SCHEDOP_remote_shutdown:
		size = sizeof (struct sched_remote_shutdown);
		break;
	default:
#ifdef DEBUG
		printf("unrecognized sched op 0x%x\n", cmd);
#endif
		return (-X_EINVAL);
	}

	error = import_buffer(&op_ie, arg, &op, size, IE_IMPORT);
	if (error == 0)
		error = HYPERVISOR_sched_op(cmd, (arg == NULL) ? NULL : &op);
	export_buffer(&op_ie, &error);

	return (error);
}
static int
privcmd_HYPERVISOR_xen_version(int cmd, void *arg)
{
	int error;
	int size = 0;
	import_export_t op_ie;
	uint32_t flags = IE_EXPORT;

	switch (cmd) {
	case XENVER_version:
		break;
	case XENVER_extraversion:
		size = sizeof (xen_extraversion_t);
		break;
	case XENVER_compile_info:
		size = sizeof (xen_compile_info_t);
		break;
	case XENVER_capabilities:
		size = sizeof (xen_capabilities_info_t);
		break;
	case XENVER_changeset:
		size = sizeof (xen_changeset_info_t);
		break;
	case XENVER_platform_parameters:
		size = sizeof (xen_platform_parameters_t);
		break;
	case XENVER_get_features:
		flags = IE_IMPEXP;
		size = sizeof (xen_feature_info_t);
		break;
	case XENVER_pagesize:
		break;
	case XENVER_guest_handle:
		size = sizeof (xen_domain_handle_t);
		break;

	default:
#ifdef DEBUG
		printf("unrecognized HYPERVISOR_xen_version op %d\n", cmd);
#endif
		return (-X_EINVAL);
	}

	error = import_buffer(&op_ie, arg, NULL, size, flags);
	if (error == 0)
		error = HYPERVISOR_xen_version(cmd, op_ie.ie_kaddr);
	export_buffer(&op_ie, &error);

	return (error);
}
static int
privcmd_HYPERVISOR_xsm_op(void *uacmctl)
{
	int error;
	struct xen_acmctl *acmctl;
	import_export_t op_ie;

	error = import_buffer(&op_ie, uacmctl, NULL, sizeof (*acmctl),
	    IE_IMPEXP);
	if (error != 0)
		return (error);

	acmctl = op_ie.ie_kaddr;

	if (acmctl->interface_version != ACM_INTERFACE_VERSION) {
#ifdef DEBUG
		printf("acm vers mismatch (cmd %d, found 0x%x, need 0x%x\n",
		    acmctl->cmd, acmctl->interface_version,
		    ACM_INTERFACE_VERSION);
#endif
		error = -X_EACCES;
		export_buffer(&op_ie, &error);
		return (error);
	}

	/* FIXME: flask ops??? */

	switch (acmctl->cmd) {
	case ACMOP_setpolicy:
	case ACMOP_getpolicy:
	case ACMOP_dumpstats:
	case ACMOP_getssid:
	case ACMOP_getdecision:
	case ACMOP_chgpolicy:
	case ACMOP_relabeldoms:
		/* flags = IE_IMPEXP; */
		break;
	default:
#ifdef DEBUG
		printf("unrecognized HYPERVISOR_xsm_op op %d\n", acmctl->cmd);
#endif
		return (-X_EINVAL);
	}

	if (error == 0)
		error = HYPERVISOR_xsm_op(acmctl);
	export_buffer(&op_ie, &error);

	return (error);
}
/*
 * Xen 'op' structures often include pointers disguised as 'handles', which
 * refer to addresses in user space.  This routine copies a buffer
 * associated with an embedded pointer into kernel space, and replaces the
 * pointer to userspace with a pointer to the new kernel buffer.
 *
 * Note: if Xen ever redefines the structure of a 'handle', this routine
 * (specifically the definition of 'hdl') will need to be updated.
 */
static int
import_handle(import_export_t *iep, void *field, size_t size, int flags)
{
	struct { void *p; } *hdl = field;
	void *ptr;
	int err;

	ptr = uaddr_from_handle(field);
	err = import_buffer(iep, ptr, NULL, size, (flags));
	if (err == 0) {
		/*LINTED: constant in conditional context*/
		set_xen_guest_handle((*hdl), (void *)((iep)->ie_kaddr));
	}
	return (err);
}
static int
privcmd_HYPERVISOR_mmuext_op(struct mmuext_op *op, int count, uint_t *scount,
    domid_t domid)
{
	int error, bytes;
	uint_t kscount;
	struct mmuext_op *kop, single_kop;
	import_export_t op_ie, scnt_ie;

	op_ie = scnt_ie = null_ie;
	error = 0;

	if (count >= 1) {
		bytes = count * sizeof (*kop);
		kop = (count == 1) ? &single_kop : kmem_alloc(bytes, KM_SLEEP);
		error = import_buffer(&op_ie, op, kop, bytes, IE_IMPORT);
	}

	DTRACE_XPV2(mmu__ext__op__start, int, count, struct mmuext_op *,
	    ((error == -X_EFAULT) ? op : kop));

	if (scount != NULL && error == 0)
		error = import_buffer(&scnt_ie, scount, &kscount,
		    sizeof (kscount), IE_EXPORT);

	if (error == 0)
		error = HYPERVISOR_mmuext_op(kop, count, &kscount, domid);
	export_buffer(&op_ie, &error);
	export_buffer(&scnt_ie, &error);

	DTRACE_XPV1(mmu__ext__op__end, int, error);

	if (count > 1)
		kmem_free(kop, bytes);
	return (error);
}
static int
privcmd_HYPERVISOR_hvm_op(int cmd, void *arg)
{
	int error;
	int size = 0;
	import_export_t arg_ie;
	uint32_t flags = IE_IMPORT;

	switch (cmd) {
	case HVMOP_set_param:
	case HVMOP_get_param:
		size = sizeof (struct xen_hvm_param);
		flags = IE_IMPEXP;
		break;
	case HVMOP_set_pci_intx_level:
		size = sizeof (struct xen_hvm_set_pci_intx_level);
		break;
	case HVMOP_set_isa_irq_level:
		size = sizeof (struct xen_hvm_set_isa_irq_level);
		break;
	case HVMOP_set_pci_link_route:
		size = sizeof (struct xen_hvm_set_pci_link_route);
		break;
	case HVMOP_track_dirty_vram:
		size = sizeof (struct xen_hvm_track_dirty_vram);
		break;
	case HVMOP_modified_memory:
		size = sizeof (struct xen_hvm_modified_memory);
		break;
	case HVMOP_set_mem_type:
		size = sizeof (struct xen_hvm_set_mem_type);
		break;

	default:
#ifdef DEBUG
		printf("unrecognized HVM op 0x%x\n", cmd);
#endif
		return (-X_EINVAL);
	}

	error = import_buffer(&arg_ie, arg, NULL, size, flags);
	if (error == 0)
		error = HYPERVISOR_hvm_op(cmd, arg_ie.ie_kaddr);
	export_buffer(&arg_ie, &error);

	return (error);
}
static struct pipe_resource *
android_display_import_buffer(struct native_display *ndpy,
                              struct native_buffer *nbuf)
{
   struct android_display *adpy = android_display(ndpy);
   ANativeWindowBuffer *abuf;
   enum pipe_format format;
   struct pipe_resource templ;

   if (nbuf->type != NATIVE_BUFFER_ANDROID)
      return NULL;

   abuf = nbuf->u.android;

   if (!abuf || abuf->common.magic != ANDROID_NATIVE_BUFFER_MAGIC ||
       abuf->common.version != sizeof(*abuf)) {
      LOGE("invalid android native buffer");
      return NULL;
   }

   format = get_pipe_format(abuf->format);
   if (format == PIPE_FORMAT_NONE)
      return NULL;

   memset(&templ, 0, sizeof(templ));
   templ.target = PIPE_TEXTURE_2D;
   templ.format = format;
   /* assume for texturing only */
   templ.bind = PIPE_BIND_SAMPLER_VIEW;
   templ.width0 = abuf->width;
   templ.height0 = abuf->height;
   templ.depth0 = 1;
   templ.array_size = 1;

   return import_buffer(adpy, &templ, abuf);
}
static struct pipe_resource *
android_surface_add_cache(struct native_surface *nsurf,
                          ANativeWindowBuffer *abuf)
{
   struct android_surface *asurf = android_surface(nsurf);
   void *handle;
   int idx;

   /* how about abuf->usage? */
   if (asurf->cache_key.width != abuf->width ||
       asurf->cache_key.height != abuf->height ||
       asurf->cache_key.format != abuf->format)
      android_surface_clear_cache(&asurf->base);

   if (asurf->adpy->use_drm)
      handle = (void *) get_handle_name(abuf->handle);
   else
      handle = (void *) abuf->handle;
   /* NULL is invalid */
   if (!handle) {
      LOGE("invalid buffer native buffer %p", abuf);
      return NULL;
   }

   /* find the slot to use */
   for (idx = 0; idx < Elements(asurf->cache_handles); idx++) {
      if (asurf->cache_handles[idx] == handle || !asurf->cache_handles[idx])
         break;
   }
   if (idx == Elements(asurf->cache_handles)) {
      LOGW("cache full: buf %p, width %d, height %d, format %d, usage 0x%x",
            abuf, abuf->width, abuf->height, abuf->format, abuf->usage);
      android_surface_clear_cache(&asurf->base);
      idx = 0;
   }

   if (idx == 0) {
      asurf->cache_key.width = abuf->width;
      asurf->cache_key.height = abuf->height;
      asurf->cache_key.format = abuf->format;
   }

   if (!asurf->cache_handles[idx]) {
      struct pipe_resource templ;

      assert(!asurf->cache_resources[idx]);

      memset(&templ, 0, sizeof(templ));
      templ.target = PIPE_TEXTURE_2D;
      templ.format = get_pipe_format(asurf->buf->format);
      templ.bind = PIPE_BIND_RENDER_TARGET;
      if (!asurf->adpy->use_drm) {
         templ.bind |= PIPE_BIND_TRANSFER_WRITE |
                       PIPE_BIND_TRANSFER_READ;
      }

      templ.width0 = asurf->buf->width;
      templ.height0 = asurf->buf->height;
      templ.depth0 = 1;
      templ.array_size = 1;

      if (templ.format != PIPE_FORMAT_NONE) {
         asurf->cache_resources[idx] =
            import_buffer(asurf->adpy, &templ, asurf->buf);
      }
      else {
         asurf->cache_resources[idx] = NULL;
      }

      asurf->cache_handles[idx] = handle;
   }

   return asurf->cache_resources[idx];
}
static int
privcmd_HYPERVISOR_event_channel_op(int cmd, void *arg)
{
	int error;
	size_t size;
	import_export_t op_ie;
	uint32_t flags;

	switch (cmd) {
	case EVTCHNOP_alloc_unbound:
		size = sizeof (evtchn_alloc_unbound_t);
		flags = IE_IMPEXP;
		break;
	case EVTCHNOP_bind_interdomain:
		size = sizeof (evtchn_bind_interdomain_t);
		flags = IE_IMPEXP;
		break;
	case EVTCHNOP_bind_virq:
		size = sizeof (evtchn_bind_virq_t);
		flags = IE_IMPEXP;
		break;
	case EVTCHNOP_bind_pirq:
		size = sizeof (evtchn_bind_pirq_t);
		flags = IE_IMPEXP;
		break;
	case EVTCHNOP_bind_ipi:
		size = sizeof (evtchn_bind_ipi_t);
		flags = IE_IMPEXP;
		break;
	case EVTCHNOP_close:
		size = sizeof (evtchn_close_t);
		flags = IE_IMPORT;
		break;
	case EVTCHNOP_send:
		size = sizeof (evtchn_send_t);
		flags = IE_IMPORT;
		break;
	case EVTCHNOP_status:
		size = sizeof (evtchn_status_t);
		flags = IE_IMPEXP;
		break;
	case EVTCHNOP_bind_vcpu:
		size = sizeof (evtchn_bind_vcpu_t);
		flags = IE_IMPORT;
		break;
	case EVTCHNOP_unmask:
		size = sizeof (evtchn_unmask_t);
		flags = IE_IMPORT;
		break;
	case EVTCHNOP_reset:
		size = sizeof (evtchn_reset_t);
		flags = IE_IMPORT;
		break;

	default:
#ifdef DEBUG
		printf("unrecognized HYPERVISOR_event_channel op %d\n", cmd);
#endif
		return (-X_EINVAL);
	}

	error = import_buffer(&op_ie, arg, NULL, size, flags);

	/*
	 * If there is sufficient demand, we can replace this void * with
	 * the proper op structure pointer.
	 */
	DTRACE_XPV2(evtchn__op__start, int, cmd, void *,
	    ((error == -X_EFAULT) ? arg : op_ie.ie_kaddr));

	if (error == 0)
		error = HYPERVISOR_event_channel_op(cmd, op_ie.ie_kaddr);
	export_buffer(&op_ie, &error);

	DTRACE_XPV1(evtchn__op__end, int, error);

	return (error);
}
static int
privcmd_HYPERVISOR_memory_op(int cmd, void *arg)
{
	int error = 0;
	import_export_t op_ie, sub_ie, gpfn_ie, mfn_ie;
	union {
		domid_t domid;
		struct xen_memory_reservation resv;
		struct xen_machphys_mfn_list xmml;
		struct xen_add_to_physmap xatp;
		struct xen_memory_map mm;
		struct xen_foreign_memory_map fmm;
	} op_arg;

	op_ie = sub_ie = gpfn_ie = mfn_ie = null_ie;

	switch (cmd) {
	case XENMEM_increase_reservation:
	case XENMEM_decrease_reservation:
	case XENMEM_populate_physmap: {
		ulong_t *taddr;

		if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.resv),
		    IE_IMPEXP) != 0)
			return (-X_EFAULT);

		error = import_handle(&sub_ie, &op_arg.resv.extent_start,
		    (op_arg.resv.nr_extents * sizeof (ulong_t)), IE_IMPEXP);

		if (error == -X_EFAULT)
			/*LINTED: constant in conditional context*/
			get_xen_guest_handle(taddr, op_arg.resv.extent_start);
		else
			taddr = sub_ie.ie_kaddr;

		switch (cmd) {
		case XENMEM_increase_reservation:
			DTRACE_XPV4(increase__reservation__start,
			    domid_t, op_arg.resv.domid,
			    ulong_t, op_arg.resv.nr_extents,
			    uint_t, op_arg.resv.extent_order,
			    ulong_t *, taddr);
			break;
		case XENMEM_decrease_reservation:
			DTRACE_XPV4(decrease__reservation__start,
			    domid_t, op_arg.resv.domid,
			    ulong_t, op_arg.resv.nr_extents,
			    uint_t, op_arg.resv.extent_order,
			    ulong_t *, taddr);
			break;
		case XENMEM_populate_physmap:
			DTRACE_XPV3(populate__physmap__start,
			    domid_t, op_arg.resv.domid,
			    ulong_t, op_arg.resv.nr_extents,
			    ulong_t *, taddr);
			break;
		}

		break;
	}

	case XENMEM_maximum_ram_page:
		break;

	case XENMEM_current_reservation:
	case XENMEM_maximum_reservation:
	case XENMEM_maximum_gpfn:
		if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.domid),
		    IE_IMPEXP) != 0)
			return (-X_EFAULT);
		break;

	case XENMEM_machphys_mfn_list: {
		if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.xmml),
		    IE_IMPEXP) != 0)
			return (-X_EFAULT);

		error = import_handle(&sub_ie, &op_arg.xmml.extent_start,
		    (op_arg.xmml.max_extents * sizeof (ulong_t)), IE_IMPEXP);
		break;
	}

	case XENMEM_add_to_physmap:
		if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.xatp),
		    IE_IMPEXP) != 0)
			return (-X_EFAULT);
		DTRACE_XPV4(add__to__physmap__start, domid_t,
		    op_arg.xatp.domid, uint_t, op_arg.xatp.space, ulong_t,
		    op_arg.xatp.idx, ulong_t, op_arg.xatp.gpfn);
		break;

	case XENMEM_memory_map:
	case XENMEM_machine_memory_map: {
		if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.mm),
		    IE_EXPORT) != 0)
			return (-X_EFAULT);

		/*
		 * XXPV: ugh. e820entry is packed, but not in the kernel, since
		 * we remove all attributes; seems like this is a nice way to
		 * break mysteriously.
		 */
		error = import_handle(&sub_ie, &op_arg.mm.buffer,
		    (op_arg.mm.nr_entries * 20), IE_IMPEXP);
		break;
	}

	case XENMEM_set_memory_map: {
		struct xen_memory_map *taddr;
		if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.fmm),
		    IE_IMPORT) != 0)
			return (-X_EFAULT);

		/*
		 * As above.
		 */
		error = import_handle(&sub_ie, &op_arg.fmm.map.buffer,
		    (op_arg.fmm.map.nr_entries * 20), IE_IMPEXP);

		if (error == -X_EFAULT)
			/*LINTED: constant in conditional context*/
			get_xen_guest_handle(taddr, op_arg.fmm.map.buffer);
		else
			taddr = sub_ie.ie_kaddr;
		DTRACE_XPV3(set__memory__map__start, domid_t,
		    op_arg.fmm.domid, int, op_arg.fmm.map.nr_entries,
		    struct xen_memory_map *, taddr);
		break;
	}

	default:
#ifdef DEBUG
		printf("unrecognized HYPERVISOR_memory_op %d\n", cmd);
#endif
		return (-X_EINVAL);
	}

	if (error == 0)
		error = HYPERVISOR_memory_op(cmd,
		    (arg == NULL) ? NULL: &op_arg);

	export_buffer(&op_ie, &error);
	export_buffer(&sub_ie, &error);
	export_buffer(&gpfn_ie, &error);
	export_buffer(&mfn_ie, &error);

	switch (cmd) {
	case XENMEM_increase_reservation:
		DTRACE_XPV1(increase__reservation__end, int, error);
		break;
	case XENMEM_decrease_reservation:
		DTRACE_XPV1(decrease__reservation__end, int, error);
		break;
	case XENMEM_populate_physmap:
		DTRACE_XPV1(populate__physmap__end, int, error);
		break;
	case XENMEM_add_to_physmap:
		DTRACE_XPV1(add__to__physmap__end, int, error);
		break;
	case XENMEM_set_memory_map:
		DTRACE_XPV1(set__memory__map__end, int, error);
		break;
	}
	return (error);
}
static int
privcmd_HYPERVISOR_platform_op(xen_platform_op_t *opp)
{
	import_export_t op_ie, sub_ie, sub2_ie;
	xen_platform_op_t op;
	int error;

	if (import_buffer(&op_ie, opp, &op, sizeof (op), IE_IMPEXP) != 0)
		return (-X_EFAULT);

	sub_ie = null_ie;
	sub2_ie = null_ie;

	/*
	 * Check this first because our wrapper will forcibly overwrite it.
	 */
	if (op.interface_version != XENPF_INTERFACE_VERSION) {
		error = -X_EACCES;
		export_buffer(&op_ie, &error);
		return (error);
	}

	/*
	 * Now handle any platform ops with embedded pointers elsewhere
	 * in the user address space that also need to be tacked down
	 * while the hypervisor futzes with them.
	 */
	switch (op.cmd) {
	case XENPF_settime:
	case XENPF_add_memtype:
	case XENPF_del_memtype:
	case XENPF_read_memtype:
	case XENPF_platform_quirk:
	case XENPF_enter_acpi_sleep:
	case XENPF_change_freq:
	case XENPF_panic_init:
		break;

	case XENPF_microcode_update:
		error = import_handle(&sub_ie, &op.u.microcode.data,
		    op.u.microcode.length, IE_IMPORT);
		break;
	case XENPF_getidletime:
		error = import_handle(&sub_ie, &op.u.getidletime.cpumap_bitmap,
		    op.u.getidletime.cpumap_nr_cpus, IE_IMPEXP);
		if (error != 0)
			break;

		error = import_handle(&sub2_ie, &op.u.getidletime.idletime,
		    op.u.getidletime.cpumap_nr_cpus * sizeof (uint64_t),
		    IE_EXPORT);
		break;

	case XENPF_set_processor_pminfo: {
		size_t s;

		switch (op.u.set_pminfo.type) {
		case XEN_PM_PX:
			s = op.u.set_pminfo.u.perf.state_count *
			    sizeof (xen_processor_px_t);
			if (op.u.set_pminfo.u.perf.flags & XEN_PX_PSS) {
				error = import_handle(&sub_ie,
				    &op.u.set_pminfo.u.perf.states, s,
				    IE_IMPORT);
			}
			break;
		case XEN_PM_CX:
			s = op.u.set_pminfo.u.power.count *
			    sizeof (xen_processor_cx_t);
			error = import_handle(&sub_ie,
			    &op.u.set_pminfo.u.power.states, s, IE_IMPORT);
			break;
		case XEN_PM_TX:
			break;
		default:
			error = -X_EINVAL;
			break;
		}
		break;
	}
	case XENPF_firmware_info: {
		uint16_t len;
		void *uaddr;

		switch (op.u.firmware_info.type) {
		case XEN_FW_DISK_INFO:
			/*
			 * Ugh.. another hokey interface. The first 16 bits
			 * of the buffer are also used as the (input) length.
			 */
			uaddr = uaddr_from_handle(
			    &op.u.firmware_info.u.disk_info.edd_params);
			error = ddi_copyin(uaddr, &len, sizeof (len), 0);
			if (error != 0)
				break;
			error = import_handle(&sub_ie,
			    &op.u.firmware_info.u.disk_info.edd_params, len,
			    IE_IMPEXP);
			break;
		case XEN_FW_VBEDDC_INFO:
			error = import_handle(&sub_ie,
			    &op.u.firmware_info.u.vbeddc_info.edid, 128,
			    IE_EXPORT);
			break;
		case XEN_FW_DISK_MBR_SIGNATURE:
		default:
			break;
		}
		break;
	}
	default:
		/* FIXME: see this with non-existed ID 38 ???? */
#ifdef DEBUG
		printf("unrecognized HYPERVISOR_platform_op %d pid %d\n",
		    op.cmd, curthread->t_procp->p_pid);
#endif
		return (-X_EINVAL);
	}

	if (error == 0)
		error = HYPERVISOR_platform_op(&op);

	export_buffer(&op_ie, &error);
	export_buffer(&sub_ie, &error);
	export_buffer(&sub2_ie, &error);

	return (error);
}
static int
privcmd_HYPERVISOR_sysctl(xen_sysctl_t *opp)
{
	xen_sysctl_t op, dop;
	import_export_t op_ie, sub_ie, sub2_ie;
	int error = 0;

	if (import_buffer(&op_ie, opp, &op, sizeof (op), IE_IMPEXP) != 0)
		return (-X_EFAULT);

	sub_ie = null_ie;
	sub2_ie = null_ie;

	/*
	 * Check this first because our wrapper will forcibly overwrite it.
	 */
	if (op.interface_version != XEN_SYSCTL_INTERFACE_VERSION) {
		error = -X_EACCES;
		export_buffer(&op_ie, &error);
		return (error);
	}

	switch (op.cmd) {
	case XEN_SYSCTL_readconsole: {
		error = import_handle(&sub_ie, &op.u.readconsole.buffer,
		    op.u.readconsole.count, IE_EXPORT);
		break;
	}

	case XEN_SYSCTL_debug_keys: {
		error = import_handle(&sub_ie, &op.u.debug_keys.keys,
		    op.u.debug_keys.nr_keys, IE_IMPORT);
		break;
	}

	case XEN_SYSCTL_tbuf_op:
	case XEN_SYSCTL_physinfo: {
		if (uaddr_from_handle(&op.u.physinfo.cpu_to_node) != NULL &&
		    op.u.physinfo.max_cpu_id != 0) {
			error = import_handle(&sub_ie,
			    &op.u.physinfo.cpu_to_node,
			    op.u.physinfo.max_cpu_id * sizeof (uint32_t),
			    IE_EXPORT);
		}
		break;
	}
	case XEN_SYSCTL_sched_id:
	case XEN_SYSCTL_availheap:
	case XEN_SYSCTL_cpu_hotplug:
		break;
	case XEN_SYSCTL_get_pmstat: {
		unsigned int maxs;

		switch (op.u.get_pmstat.type) {
		case PMSTAT_get_pxstat:
			/*
			 * This interface is broken. Xen always copies out
			 * all the state information, and the interface
			 * does not specify how much space the caller has
			 * reserved. So, the only thing to do is just mirror
			 * the hypervisor and libxc behavior, and use the
			 * maximum amount of data.
			 */
			dop.cmd = XEN_SYSCTL_get_pmstat;
			dop.interface_version = XEN_SYSCTL_INTERFACE_VERSION;
			dop.u.get_pmstat.cpuid = op.u.get_pmstat.cpuid;
			dop.u.get_pmstat.type = PMSTAT_get_max_px;
			error = HYPERVISOR_sysctl(&dop);
			if (error != 0)
				break;

			maxs = dop.u.get_pmstat.u.getpx.total;
			if (maxs == 0) {
				error = -X_EINVAL;
				break;
			}

			error = import_handle(&sub_ie,
			    &op.u.get_pmstat.u.getpx.trans_pt,
			    maxs * maxs * sizeof (uint64_t), IE_EXPORT);
			if (error != 0)
				break;

			error = import_handle(&sub2_ie,
			    &op.u.get_pmstat.u.getpx.pt,
			    maxs * sizeof (pm_px_val_t), IE_EXPORT);
			break;
		case PMSTAT_get_cxstat:
			/* See above */
			dop.cmd = XEN_SYSCTL_get_pmstat;
			dop.interface_version = XEN_SYSCTL_INTERFACE_VERSION;
			dop.u.get_pmstat.cpuid = op.u.get_pmstat.cpuid;
			dop.u.get_pmstat.type = PMSTAT_get_max_cx;
			error = HYPERVISOR_sysctl(&dop);
			if (error != 0)
				break;

			maxs = dop.u.get_pmstat.u.getcx.nr;
			if (maxs == 0) {
				error = -X_EINVAL;
				break;
			}

			error = import_handle(&sub_ie,
			    &op.u.get_pmstat.u.getcx.triggers,
			    maxs * sizeof (uint64_t), IE_EXPORT);
			if (error != 0)
				break;
			error = import_handle(&sub2_ie,
			    &op.u.get_pmstat.u.getcx.residencies,
			    maxs * sizeof (uint64_t), IE_EXPORT);
			break;

		case PMSTAT_get_max_px:
		case PMSTAT_reset_pxstat:
		case PMSTAT_get_max_cx:
		case PMSTAT_reset_cxstat:
			break;
		default:
			error = -X_EINVAL;
			break;
		}
		break;
	}

	case XEN_SYSCTL_perfc_op: {
		xen_sysctl_perfc_desc_t *scdp;
		/*
		 * If 'desc' is NULL, then the caller is asking for
		 * the number of counters.  If 'desc' is non-NULL,
		 * then we need to know how many counters there are
		 * before wiring down the output buffer appropriately.
		 */
		/*LINTED: constant in conditional context*/
		get_xen_guest_handle_u(scdp, op.u.perfc_op.desc);
		if (scdp != NULL) {
			static int numcounters = -1;
			static int numvals = -1;

			if (numcounters == -1) {
				dop.cmd = XEN_SYSCTL_perfc_op;
				dop.interface_version =
				    XEN_SYSCTL_INTERFACE_VERSION;
				dop.u.perfc_op.cmd = XEN_SYSCTL_PERFCOP_query;
				/*LINTED: constant in conditional context*/
				set_xen_guest_handle_u(dop.u.perfc_op.desc,
				    NULL);
				/*LINTED: constant in conditional context*/
				set_xen_guest_handle_u(dop.u.perfc_op.val,
				    NULL);

				error = HYPERVISOR_sysctl(&dop);
				if (error != 0)
					break;
				numcounters = dop.u.perfc_op.nr_counters;
				numvals = dop.u.perfc_op.nr_vals;
			}
			ASSERT(numcounters != -1);
			ASSERT(numvals != -1);
			error = import_handle(&sub_ie, &op.u.perfc_op.desc,
			    (sizeof (xen_sysctl_perfc_desc_t) * numcounters),
			    IE_EXPORT);
			error = import_handle(&sub2_ie, &op.u.perfc_op.val,
			    (sizeof (xen_sysctl_perfc_val_t) * numvals),
			    IE_EXPORT);
		}
		break;
	}

	case XEN_SYSCTL_getdomaininfolist: {
		error = import_handle(&sub_ie, &op.u.getdomaininfolist.buffer,
		    (op.u.getdomaininfolist.max_domains *
		    sizeof (xen_domctl_getdomaininfo_t)), IE_EXPORT);
		break;
	}

	case XEN_SYSCTL_getcpuinfo:
		error = import_handle(&sub_ie, &op.u.getcpuinfo.info,
		    op.u.getcpuinfo.max_cpus *
		    sizeof (xen_sysctl_cpuinfo_t), IE_EXPORT);
		break;
	default:
#ifdef DEBUG
		printf("unrecognized HYPERVISOR_sysctl %d\n", op.cmd);
#endif
		error = -X_EINVAL;
	}

	if (error == 0)
		error = HYPERVISOR_sysctl(&op);

	export_buffer(&op_ie, &error);
	export_buffer(&sub_ie, &error);
	export_buffer(&sub2_ie, &error);

	return (error);
}
static int
privcmd_HYPERVISOR_domctl(xen_domctl_t *opp)
{
	xen_domctl_t op;
	import_export_t op_ie, sub_ie;
	int error = 0;

	if ((error = import_buffer(&op_ie, opp, &op, sizeof (op),
	    IE_IMPEXP)) != 0)
		return (error);

	sub_ie = null_ie;

	/*
	 * Check this first because our wrapper will forcibly overwrite it.
	 */
	if (op.interface_version != XEN_DOMCTL_INTERFACE_VERSION) {
#ifdef DEBUG
		printf("domctl vers mismatch (cmd %d, found 0x%x, need 0x%x\n",
		    op.cmd, op.interface_version, XEN_DOMCTL_INTERFACE_VERSION);
#endif
		error = -X_EACCES;
		export_buffer(&op_ie, &error);
		return (error);
	}

	/*
	 * Now handle any domctl ops with embedded pointers elsewhere
	 * in the user address space that also need to be tacked down
	 * while the hypervisor futzes with them.
	 */
	switch (op.cmd) {
	case XEN_DOMCTL_createdomain:
		DTRACE_XPV1(dom__create__start, xen_domctl_t *,
		    &op.u.createdomain);
		break;

	case XEN_DOMCTL_destroydomain:
		DTRACE_XPV1(dom__destroy__start, domid_t, op.domain);
		break;

	case XEN_DOMCTL_pausedomain:
		DTRACE_XPV1(dom__pause__start, domid_t, op.domain);
		break;

	case XEN_DOMCTL_unpausedomain:
		DTRACE_XPV1(dom__unpause__start, domid_t, op.domain);
		break;

	case XEN_DOMCTL_getmemlist: {
		error = import_handle(&sub_ie, &op.u.getmemlist.buffer,
		    op.u.getmemlist.max_pfns * sizeof (xen_pfn_t), IE_EXPORT);
		break;
	}

	case XEN_DOMCTL_getpageframeinfo2: {
		error = import_handle(&sub_ie, &op.u.getpageframeinfo2.array,
		    op.u.getpageframeinfo2.num * sizeof (ulong_t), IE_IMPEXP);
		break;
	}

	case XEN_DOMCTL_shadow_op: {
		size_t size;

		size = roundup(howmany(op.u.shadow_op.pages, NBBY),
		    sizeof (ulong_t));
		error = import_handle(&sub_ie,
		    &op.u.shadow_op.dirty_bitmap, size, IE_IMPEXP);
		break;
	}

	case XEN_DOMCTL_setvcpucontext: {
		vcpu_guest_context_t *taddr;
		error = import_handle(&sub_ie, &op.u.vcpucontext.ctxt,
		    sizeof (vcpu_guest_context_t), IE_IMPORT);
		if (error == -X_EFAULT)
			/*LINTED: constant in conditional context*/
			get_xen_guest_handle_u(taddr, op.u.vcpucontext.ctxt);
		else
			taddr = sub_ie.ie_kaddr;
		DTRACE_XPV2(setvcpucontext__start, domid_t, op.domain,
		    vcpu_guest_context_t *, taddr);
		break;
	}

	case XEN_DOMCTL_getvcpucontext: {
		error = import_handle(&sub_ie, &op.u.vcpucontext.ctxt,
		    sizeof (vcpu_guest_context_t), IE_EXPORT);
		break;
	}


	case XEN_DOMCTL_sethvmcontext: {
		error = import_handle(&sub_ie, &op.u.hvmcontext.buffer,
		    op.u.hvmcontext.size, IE_IMPORT);
		break;
	}

	case XEN_DOMCTL_gethvmcontext: {
#if !defined(__GNUC__) && defined(__i386__)
		if (op.u.hvmcontext.buffer.u.p != NULL)
#else
		if (op.u.hvmcontext.buffer.p != NULL)
#endif
			error = import_handle(&sub_ie, &op.u.hvmcontext.buffer,
			    op.u.hvmcontext.size, IE_EXPORT);
		break;
	}

	case XEN_DOMCTL_getdomaininfo:
	case XEN_DOMCTL_getpageframeinfo:
	case XEN_DOMCTL_max_mem:
	case XEN_DOMCTL_resumedomain:
	case XEN_DOMCTL_getvcpuinfo:
	case XEN_DOMCTL_setvcpuaffinity:
	case XEN_DOMCTL_getvcpuaffinity:
	case XEN_DOMCTL_max_vcpus:
	case XEN_DOMCTL_scheduler_op:
	case XEN_DOMCTL_setdomainhandle:
	case XEN_DOMCTL_setdebugging:
	case XEN_DOMCTL_irq_permission:
	case XEN_DOMCTL_iomem_permission:
	case XEN_DOMCTL_ioport_permission:
	case XEN_DOMCTL_hypercall_init:
	case XEN_DOMCTL_arch_setup:
	case XEN_DOMCTL_settimeoffset:
	case XEN_DOMCTL_real_mode_area:
	case XEN_DOMCTL_sendtrigger:
	case XEN_DOMCTL_assign_device:
	case XEN_DOMCTL_bind_pt_irq:
	case XEN_DOMCTL_get_address_size:
	case XEN_DOMCTL_set_address_size:
	case XEN_DOMCTL_get_ext_vcpucontext:
	case XEN_DOMCTL_set_ext_vcpucontext:
	case XEN_DOMCTL_set_opt_feature:
	case XEN_DOMCTL_memory_mapping:
	case XEN_DOMCTL_ioport_mapping:
	case XEN_DOMCTL_pin_mem_cacheattr:
	case XEN_DOMCTL_test_assign_device:
	case XEN_DOMCTL_set_target:
	case XEN_DOMCTL_deassign_device:
	case XEN_DOMCTL_set_cpuid:
	case XEN_DOMCTL_get_device_group:
	case XEN_DOMCTL_get_machine_address_size:
	case XEN_DOMCTL_set_machine_address_size:
	case XEN_DOMCTL_suppress_spurious_page_faults:
		break;

	default:
#ifdef DEBUG
		printf("unrecognized HYPERVISOR_domctl %d\n", op.cmd);
#endif
		error = -X_EINVAL;
	}

	if (error == 0)
		error = HYPERVISOR_domctl(&op);

	export_buffer(&op_ie, &error);
	export_buffer(&sub_ie, &error);

	switch (op.cmd) {
	case XEN_DOMCTL_createdomain:
		DTRACE_XPV1(dom__create__end, int, error);
		break;
	case XEN_DOMCTL_destroydomain:
		DTRACE_XPV1(dom__destroy__end, int, error);
		break;
	case XEN_DOMCTL_pausedomain:
		DTRACE_XPV1(dom__pause__end, int, error);
		break;
	case XEN_DOMCTL_unpausedomain:
		DTRACE_XPV1(dom__unpause__end, int, error);
		break;
	case XEN_DOMCTL_setvcpucontext:
		DTRACE_XPV1(setvcpucontext__end, int, error);
		break;
	default:
		;
	}

	return (error);
}
Exemple #15
0
//
//	sequence::insert_worker
//
bool sequence::insert_worker (size_w index, const seqchar *buf, size_w length, action act)
{
	span *		sptr;
	size_w		spanindex;
	size_t		modbuf_offset;
	span_range	newspans;
	size_w		insoffset;

	if(index > sequence_length)
		return false;

	// find the span that the insertion starts at
	if((sptr = spanfromindex(index, &spanindex)) == 0)
		return false;

	// ensure there is room in the modify buffer...
	// allocate a new buffer if necessary and then invalidate span cache
	// to prevent a span using two buffers of data
	if(!import_buffer(buf, length, &modbuf_offset))
		return false;

	debug("Inserting: idx=%d len=%d %.*s\n", index, length, length, buf);

	clearstack(redostack);
	insoffset = index - spanindex;

	// special-case #1: inserting at the end of a prior insertion, at a span-boundary
	if(insoffset == 0 && can_optimize(act, index))
	{
		// simply extend the last span's length
		span_range *event = undostack.back();
		sptr->prev->length	+= length;
		event->length		+= length;
	}
	// general-case #1: inserting at a span boundary?
	else if(insoffset == 0)
	{
		//
		// Create a new undo event; because we are inserting at a span
		// boundary there are no spans to replace, so use a "span boundary"
		//
		span_range *oldspans = initundo(index, length, act);
		oldspans->spanboundary(sptr->prev, sptr);
		
		// allocate new span in the modify buffer
		newspans.append(new span(
			modbuf_offset, 
			length, 
			modifybuffer_id)
			);
		
		// link the span into the sequence
		swap_spanrange(oldspans, &newspans);
	}
	// general-case #2: inserting in the middle of a span
	else
	{
		//
		//	Create a new undo event and add the span
		//  that we will be "splitting" in half
		//
		span_range *oldspans = initundo(index, length, act);
		oldspans->append(sptr);

		//	span for the existing data before the insertion
		newspans.append(new span(
							sptr->offset, 
							insoffset, 
							sptr->buffer)
						);

		// make a span for the inserted data
		newspans.append(new span(
							modbuf_offset, 
							length, 
							modifybuffer_id)
						);

		// span for the existing data after the insertion
		newspans.append(new span(
							sptr->offset + insoffset, 
							sptr->length - insoffset, 
							sptr->buffer)
						);

		swap_spanrange(oldspans, &newspans);
	}

	sequence_length += length;

	return true;
}