privcmd_hcall.c revision 349b53dd4e695e3d833b5380540385145b2d3ae8
843e19887f64dde75055cf8842fc4db2171eff45johnlev * CDDL HEADER START
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The contents of this file are subject to the terms of the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Common Development and Distribution License (the "License").
843e19887f64dde75055cf8842fc4db2171eff45johnlev * You may not use this file except in compliance with the License.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
843e19887f64dde75055cf8842fc4db2171eff45johnlev * See the License for the specific language governing permissions
843e19887f64dde75055cf8842fc4db2171eff45johnlev * and limitations under the License.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * When distributing Covered Code, include this CDDL HEADER in each
843e19887f64dde75055cf8842fc4db2171eff45johnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If applicable, add the following below this CDDL HEADER, with the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * fields enclosed by brackets "[]" replaced with your own identifying
843e19887f64dde75055cf8842fc4db2171eff45johnlev * information: Portions Copyright [yyyy] [name of copyright owner]
843e19887f64dde75055cf8842fc4db2171eff45johnlev * CDDL HEADER END
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Use is subject to license terms.
843e19887f64dde75055cf8842fc4db2171eff45johnlevtypedef struct import_export {
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define IE_IMPORT 0x0001 /* Data needs to be copied in */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define IE_EXPORT 0x0002 /* Data needs to be copied out */
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee /*LINTED: constant in conditional context*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Import a buffer from user-space. If the caller provides a kernel
843e19887f64dde75055cf8842fc4db2171eff45johnlev * address, we import to that address. If not, we kmem_alloc() the space
843e19887f64dde75055cf8842fc4db2171eff45johnlev * ourselves.
843e19887f64dde75055cf8842fc4db2171eff45johnlevimport_buffer(import_export_t *iep, void *uaddr, void *kaddr, size_t size,
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If the buffer was marked for export initially, and if the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * hypercall completed successfully, resync the user-space buffer
843e19887f64dde75055cf8842fc4db2171eff45johnlev * with our in-kernel buffer.
843e19887f64dde75055cf8842fc4db2171eff45johnlev (ddi_copyout(iep->ie_kaddr, iep->ie_uaddr, iep->ie_size, 0) != 0))
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Xen 'op' structures often include pointers disguised as 'handles', which
843e19887f64dde75055cf8842fc4db2171eff45johnlev * refer to addresses in user space. This routine copies a buffer
843e19887f64dde75055cf8842fc4db2171eff45johnlev * associated with an embedded pointer into kernel space, and replaces the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * pointer to userspace with a pointer to the new kernel buffer.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Note: if Xen ever redefines the structure of a 'handle', this routine
843e19887f64dde75055cf8842fc4db2171eff45johnlev * (specifically the definition of 'hdl') will need to be updated.
843e19887f64dde75055cf8842fc4db2171eff45johnlevimport_handle(import_export_t *iep, void *field, size_t size, int flags)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (err == 0) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab /*LINTED: constant in conditional context*/
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab set_xen_guest_handle((*hdl), (void *)((iep)->ie_kaddr));
843e19887f64dde75055cf8842fc4db2171eff45johnlevprivcmd_HYPERVISOR_mmu_update(mmu_update_t *ureq, int count, int *scount,
843e19887f64dde75055cf8842fc4db2171eff45johnlev kreq = (count == 1) ? &single_kreq : kmem_alloc(bytes, KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_buffer(&cnt_ie, scount, &kscount, sizeof (kscount),
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_buffer(&req_ie, ureq, kreq, bytes, IE_IMPEXP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DTRACE_XPV3(mmu__update__start, int, domid, int, count, mmu_update_t *,
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = HYPERVISOR_mmu_update(kreq, count, &kscount, domid);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((error = import_buffer(&op_ie, opp, &op, sizeof (op),
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Check this first because our wrapper will forcibly overwrite it.
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (op.interface_version != XEN_DOMCTL_INTERFACE_VERSION) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab printf("domctl vers mismatch (cmd %d, found 0x%x, need 0x%x\n",
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab op.cmd, op.interface_version, XEN_DOMCTL_INTERFACE_VERSION);
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Now handle any domctl ops with embedded pointers elsewhere
843e19887f64dde75055cf8842fc4db2171eff45johnlev * in the user address space that also need to be tacked down
843e19887f64dde75055cf8842fc4db2171eff45johnlev * while the hypervisor futzes with them.
843e19887f64dde75055cf8842fc4db2171eff45johnlev DTRACE_XPV1(dom__destroy__start, domid_t, op.domain);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DTRACE_XPV1(dom__unpause__start, domid_t, op.domain);
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_handle(&sub_ie, &op.u.getmemlist.buffer,
843e19887f64dde75055cf8842fc4db2171eff45johnlev op.u.getmemlist.max_pfns * sizeof (xen_pfn_t), IE_EXPORT);
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_handle(&sub_ie, &op.u.getpageframeinfo2.array,
843e19887f64dde75055cf8842fc4db2171eff45johnlev op.u.getpageframeinfo2.num * sizeof (ulong_t), IE_IMPEXP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_handle(&sub_ie, &op.u.vcpucontext.ctxt,
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*LINTED: constant in conditional context*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev DTRACE_XPV2(setvcpucontext__start, domid_t, op.domain,
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_handle(&sub_ie, &op.u.vcpucontext.ctxt,
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee case XEN_DOMCTL_suppress_spurious_page_faults:
843e19887f64dde75055cf8842fc4db2171eff45johnlev printf("unrecognized HYPERVISOR_domctl %d\n", op.cmd);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (import_buffer(&op_ie, opp, &op, sizeof (op), IE_IMPEXP) != 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Check this first because our wrapper will forcibly overwrite it.
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (op.interface_version != XEN_SYSCTL_INTERFACE_VERSION) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_handle(&sub_ie, &op.u.readconsole.buffer,
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee if (uaddr_from_handle(&op.u.physinfo.cpu_to_node) != NULL &&
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee unsigned int maxs;
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee * This interface is broken. Xen always copies out
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee * all the state information, and the interface
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee * does not specify how much space the caller has
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee * reserved. So, the only thing to do is just mirror
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee * the hypervisor and libxc behavior, and use the
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee * maximum amount of data.
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee dop.interface_version = XEN_SYSCTL_INTERFACE_VERSION;
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee dop.u.get_pmstat.cpuid = op.u.get_pmstat.cpuid;
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee /* See above */
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee dop.interface_version = XEN_SYSCTL_INTERFACE_VERSION;
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee dop.u.get_pmstat.cpuid = op.u.get_pmstat.cpuid;
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If 'desc' is NULL, then the caller is asking for
843e19887f64dde75055cf8842fc4db2171eff45johnlev * the number of counters. If 'desc' is non-NULL,
843e19887f64dde75055cf8842fc4db2171eff45johnlev * then we need to know how many counters there are
843e19887f64dde75055cf8842fc4db2171eff45johnlev * before wiring down the output buffer appropriately.
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*LINTED: constant in conditional context*/
33649781048a478eaa5fa15460fc764530f86c8cmrj /*LINTED: constant in conditional context*/
33649781048a478eaa5fa15460fc764530f86c8cmrj /*LINTED: constant in conditional context*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_handle(&sub_ie, &op.u.getdomaininfolist.buffer,
843e19887f64dde75055cf8842fc4db2171eff45johnlev printf("unrecognized HYPERVISOR_sysctl %d\n", op.cmd);
843e19887f64dde75055cf8842fc4db2171eff45johnlevprivcmd_HYPERVISOR_platform_op(xen_platform_op_t *opp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (import_buffer(&op_ie, opp, &op, sizeof (op), IE_IMPEXP) != 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Check this first because our wrapper will forcibly overwrite it.
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (op.interface_version != XENPF_INTERFACE_VERSION) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Now handle any platform ops with embedded pointers elsewhere
843e19887f64dde75055cf8842fc4db2171eff45johnlev * in the user address space that also need to be tacked down
843e19887f64dde75055cf8842fc4db2171eff45johnlev * while the hypervisor futzes with them.
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_handle(&sub_ie, &op.u.microcode.data,
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee error = import_handle(&sub_ie, &op.u.getidletime.cpumap_bitmap,
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee error = import_handle(&sub2_ie, &op.u.getidletime.idletime,
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee op.u.getidletime.cpumap_nr_cpus * sizeof (uint64_t),
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee if (op.u.set_pminfo.u.perf.flags & XEN_PX_PSS) {
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee &op.u.set_pminfo.u.power.states, s, IE_IMPORT);
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee * Ugh.. another hokey interface. The first 16 bits
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee * of the buffer are also used as the (input) length.
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee error = ddi_copyin(uaddr, &len, sizeof (len), 0);
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee &op.u.firmware_info.u.disk_info.edd_params, len,
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee /* FIXME: see this with non-existed ID 38 ???? */
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee printf("unrecognized HYPERVISOR_platform_op %d pid %d\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.resv),
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_handle(&sub_ie, &op_arg.resv.extent_start,
843e19887f64dde75055cf8842fc4db2171eff45johnlev (op_arg.resv.nr_extents * sizeof (ulong_t)), IE_IMPEXP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*LINTED: constant in conditional context*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev get_xen_guest_handle(taddr, op_arg.resv.extent_start);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.domid),
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.xmml),
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_handle(&sub_ie, &op_arg.xmml.extent_start,
843e19887f64dde75055cf8842fc4db2171eff45johnlev (op_arg.xmml.max_extents * sizeof (ulong_t)), IE_IMPEXP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.xatp),
843e19887f64dde75055cf8842fc4db2171eff45johnlev op_arg.xatp.domid, uint_t, op_arg.xatp.space, ulong_t,
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.tgl),
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_handle(&gpfn_ie, &op_arg.tgl.gpfn_list,
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_handle(&mfn_ie, &op_arg.tgl.mfn_list,
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.mm),
843e19887f64dde75055cf8842fc4db2171eff45johnlev * XXPV: ugh. e820entry is packed, but not in the kernel, since
843e19887f64dde75055cf8842fc4db2171eff45johnlev * we remove all attributes; seems like this is a nice way to
843e19887f64dde75055cf8842fc4db2171eff45johnlev * break mysteriously.
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (import_buffer(&op_ie, arg, &op_arg, sizeof (op_arg.fmm),
843e19887f64dde75055cf8842fc4db2171eff45johnlev * As above.
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_handle(&sub_ie, &op_arg.fmm.map.buffer,
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*LINTED: constant in conditional context*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev printf("unrecognized HYPERVISOR_memory_op %d\n", cmd);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DTRACE_XPV1(increase__reservation__end, int, error);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DTRACE_XPV1(decrease__reservation__end, int, error);
843e19887f64dde75055cf8842fc4db2171eff45johnlevprivcmd_HYPERVISOR_event_channel_op(int cmd, void *arg)
843e19887f64dde75055cf8842fc4db2171eff45johnlev printf("unrecognized HYPERVISOR_event_channel op %d\n", cmd);
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_buffer(&op_ie, arg, NULL, size, flags);
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If there is sufficient demand, we can replace this void * with
843e19887f64dde75055cf8842fc4db2171eff45johnlev * the proper op structure pointer.
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = HYPERVISOR_event_channel_op(cmd, op_ie.ie_kaddr);
843e19887f64dde75055cf8842fc4db2171eff45johnlev printf("unrecognized HYPERVISOR_xen_version op %d\n", cmd);
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_buffer(&op_ie, arg, NULL, size, flags);
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = HYPERVISOR_xen_version(cmd, op_ie.ie_kaddr);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab error = import_buffer(&op_ie, uacmctl, NULL, sizeof (*acmctl),
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (acmctl->interface_version != ACM_INTERFACE_VERSION) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab printf("acm vers mismatch (cmd %d, found 0x%x, need 0x%x\n",
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee /* FIXME: flask ops??? */
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee /* flags = IE_IMPEXP; */
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee printf("unrecognized HYPERVISOR_xsm_op op %d\n", acmctl->cmd);
843e19887f64dde75055cf8842fc4db2171eff45johnlevprivcmd_HYPERVISOR_mmuext_op(struct mmuext_op *op, int count, uint_t *scount,
843e19887f64dde75055cf8842fc4db2171eff45johnlev kop = (count == 1) ? &single_kop : kmem_alloc(bytes, KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_buffer(&op_ie, op, kop, bytes, IE_IMPORT);
843e19887f64dde75055cf8842fc4db2171eff45johnlev DTRACE_XPV2(mmu__ext__op__start, int, count, struct mmuext_op *,
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = HYPERVISOR_mmuext_op(kop, count, &kscount, domid);
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee size = sizeof (struct xen_hvm_track_dirty_vram);
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee size = sizeof (struct xen_hvm_modified_memory);
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_buffer(&arg_ie, arg, NULL, size, flags);
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = import_buffer(&op_ie, arg, &op, size, IE_IMPORT);
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = HYPERVISOR_sched_op(cmd, (arg == NULL) ? NULL : &op);
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevdo_privcmd_hypercall(void *uarg, int mode, cred_t *cr, int *rval)
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee error = privcmd_HYPERVISOR_xsm_op((void *)hc->arg[0]);
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = __hypercall5(hc->op, hc->arg[0], hc->arg[1],
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else if (error != 0)