privcmd_hcall.c revision ad09f8b827db90c9a0093f0b6382803fa64a5fd1
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/xpv_user.h>
#include <sys/hypervisor.h>
#include <sys/xen_errno.h>
#include <sys/sysmacros.h>
#include <sys/privcmd_impl.h>
typedef struct import_export {
void * ie_uaddr;
void * ie_kaddr;
#define IE_FREE 0x0004
static void *
uaddr_from_handle(void *field)
{
void *ptr;
/*LINTED: constant in conditional context*/
return (ptr);
}
/*
* Import a buffer from user-space. If the caller provides a kernel
* address, we import to that address. If not, we kmem_alloc() the space
* ourselves.
*/
static int
{
return (0);
}
} else {
}
}
return (-X_EFAULT);
}
return (0);
}
static void
{
int copy_err = 0;
return;
/*
* If the buffer was marked for export initially, and if the
* hypercall completed successfully, resync the user-space buffer
* with our in-kernel buffer.
*/
}
}
/*
* 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
{
void *ptr;
int err;
if (err == 0) {
/*LINTED: constant in conditional context*/
}
return (err);
}
static int
{
if (error != 0)
else
if (error == 0)
if (count != 1)
return (error);
}
static int
{
int error = 0;
IE_IMPEXP)) != 0)
return (error);
/*
* Check this first because our wrapper will forcibly overwrite it.
*/
#ifdef DEBUG
printf("domctl vers mismatch (cmd %d, found 0x%x, need 0x%x\n",
#endif
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.
*/
case XEN_DOMCTL_createdomain:
&op.u.createdomain);
break;
case XEN_DOMCTL_destroydomain:
break;
case XEN_DOMCTL_pausedomain:
break;
case XEN_DOMCTL_unpausedomain:
break;
case XEN_DOMCTL_getmemlist: {
break;
}
case XEN_DOMCTL_getpageframeinfo2: {
break;
}
case XEN_DOMCTL_shadow_op: {
sizeof (ulong_t));
break;
}
case XEN_DOMCTL_setvcpucontext: {
sizeof (vcpu_guest_context_t), IE_IMPORT);
/*LINTED: constant in conditional context*/
else
break;
}
case XEN_DOMCTL_getvcpucontext: {
sizeof (vcpu_guest_context_t), IE_EXPORT);
break;
}
case XEN_DOMCTL_sethvmcontext: {
break;
}
case XEN_DOMCTL_gethvmcontext: {
#else
#endif
break;
}
case XEN_DOMCTL_getdomaininfo:
case XEN_DOMCTL_max_mem:
case XEN_DOMCTL_resumedomain:
case XEN_DOMCTL_getvcpuinfo:
case XEN_DOMCTL_max_vcpus:
case XEN_DOMCTL_scheduler_op:
case XEN_DOMCTL_setdebugging:
case XEN_DOMCTL_arch_setup:
case XEN_DOMCTL_settimeoffset:
case XEN_DOMCTL_sendtrigger:
case XEN_DOMCTL_assign_device:
case XEN_DOMCTL_bind_pt_irq:
case XEN_DOMCTL_set_target:
case XEN_DOMCTL_set_cpuid:
break;
default:
#ifdef DEBUG
#endif
}
if (error == 0)
case XEN_DOMCTL_createdomain:
break;
case XEN_DOMCTL_destroydomain:
break;
case XEN_DOMCTL_pausedomain:
break;
case XEN_DOMCTL_unpausedomain:
break;
break;
default:
;
}
return (error);
}
static int
{
int error = 0;
return (-X_EFAULT);
/*
* Check this first because our wrapper will forcibly overwrite it.
*/
return (error);
}
case XEN_SYSCTL_readconsole: {
break;
}
case XEN_SYSCTL_debug_keys: {
break;
}
case XEN_SYSCTL_tbuf_op:
case XEN_SYSCTL_physinfo: {
}
break;
}
case XEN_SYSCTL_sched_id:
case XEN_SYSCTL_availheap:
case XEN_SYSCTL_cpu_hotplug:
break;
case XEN_SYSCTL_get_pmstat: {
unsigned int maxs;
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.
*/
if (error != 0)
break;
if (maxs == 0) {
break;
}
if (error != 0)
break;
break;
case PMSTAT_get_cxstat:
/* See above */
if (error != 0)
break;
if (maxs == 0) {
break;
}
if (error != 0)
break;
break;
case PMSTAT_get_max_px:
case PMSTAT_reset_pxstat:
case PMSTAT_get_max_cx:
case PMSTAT_reset_cxstat:
break;
default:
break;
}
break;
}
case XEN_SYSCTL_perfc_op: {
/*
* 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*/
static int numcounters = -1;
static int numvals = -1;
if (numcounters == -1) {
/*LINTED: constant in conditional context*/
NULL);
/*LINTED: constant in conditional context*/
NULL);
if (error != 0)
break;
}
(sizeof (xen_sysctl_perfc_desc_t) * numcounters),
(sizeof (xen_sysctl_perfc_val_t) * numvals),
}
break;
}
case XEN_SYSCTL_getdomaininfolist: {
sizeof (xen_domctl_getdomaininfo_t)), IE_EXPORT);
break;
}
case XEN_SYSCTL_getcpuinfo:
sizeof (xen_sysctl_cpuinfo_t), IE_EXPORT);
break;
default:
#ifdef DEBUG
#endif
}
if (error == 0)
return (error);
}
static int
{
int error;
return (-X_EFAULT);
/*
* Check this first because our wrapper will forcibly overwrite it.
*/
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.
*/
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:
break;
case XENPF_getidletime:
if (error != 0)
break;
break;
case XENPF_set_processor_pminfo: {
size_t s;
case XEN_PM_PX:
sizeof (xen_processor_px_t);
}
break;
case XEN_PM_CX:
sizeof (xen_processor_cx_t);
break;
case XEN_PM_TX:
break;
default:
break;
}
break;
}
case XENPF_firmware_info: {
void *uaddr;
case XEN_FW_DISK_INFO:
/*
* Ugh.. another hokey interface. The first 16 bits
* of the buffer are also used as the (input) length.
*/
if (error != 0)
break;
break;
case XEN_FW_VBEDDC_INFO:
break;
default:
break;
}
break;
}
default:
/* FIXME: see this with non-existed ID 38 ???? */
#ifdef DEBUG
printf("unrecognized HYPERVISOR_platform_op %d pid %d\n",
#endif
return (-X_EINVAL);
}
if (error == 0)
return (error);
}
static int
{
int error = 0;
union {
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;
switch (cmd) {
case XENMEM_populate_physmap: {
IE_IMPEXP) != 0)
return (-X_EFAULT);
/*LINTED: constant in conditional context*/
else
switch (cmd) {
break;
break;
case XENMEM_populate_physmap:
break;
}
break;
}
case XENMEM_maximum_ram_page:
break;
case XENMEM_maximum_gpfn:
IE_IMPEXP) != 0)
return (-X_EFAULT);
break;
case XENMEM_machphys_mfn_list: {
IE_IMPEXP) != 0)
return (-X_EFAULT);
break;
}
case XENMEM_add_to_physmap:
IE_IMPEXP) != 0)
return (-X_EFAULT);
break;
case XENMEM_memory_map:
case XENMEM_machine_memory_map: {
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.
*/
break;
}
case XENMEM_set_memory_map: {
struct xen_memory_map *taddr;
IE_IMPORT) != 0)
return (-X_EFAULT);
/*
* As above.
*/
/*LINTED: constant in conditional context*/
else
struct xen_memory_map *, taddr);
break;
}
default:
#ifdef DEBUG
#endif
return (-X_EINVAL);
}
if (error == 0)
switch (cmd) {
break;
break;
case XENMEM_populate_physmap:
break;
case XENMEM_add_to_physmap:
break;
case XENMEM_set_memory_map:
break;
}
return (error);
}
static int
{
int error;
switch (cmd) {
case EVTCHNOP_alloc_unbound:
size = sizeof (evtchn_alloc_unbound_t);
break;
size = sizeof (evtchn_bind_interdomain_t);
break;
case EVTCHNOP_bind_virq:
size = sizeof (evtchn_bind_virq_t);
break;
case EVTCHNOP_bind_pirq:
size = sizeof (evtchn_bind_pirq_t);
break;
case EVTCHNOP_bind_ipi:
size = sizeof (evtchn_bind_ipi_t);
break;
case EVTCHNOP_close:
size = sizeof (evtchn_close_t);
break;
case EVTCHNOP_send:
size = sizeof (evtchn_send_t);
break;
case EVTCHNOP_status:
size = sizeof (evtchn_status_t);
break;
case EVTCHNOP_bind_vcpu:
size = sizeof (evtchn_bind_vcpu_t);
break;
case EVTCHNOP_unmask:
size = sizeof (evtchn_unmask_t);
break;
case EVTCHNOP_reset:
size = sizeof (evtchn_reset_t);
break;
default:
#ifdef DEBUG
#endif
return (-X_EINVAL);
}
/*
* If there is sufficient demand, we can replace this void * with
* the proper op structure pointer.
*/
if (error == 0)
return (error);
}
static int
{
int error;
int size = 0;
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;
size = sizeof (xen_platform_parameters_t);
break;
case XENVER_get_features:
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
#endif
return (-X_EINVAL);
}
if (error == 0)
return (error);
}
static int
privcmd_HYPERVISOR_xsm_op(void *uacmctl)
{
int error;
struct xen_acmctl *acmctl;
if (error != 0)
return (error);
#ifdef DEBUG
printf("acm vers mismatch (cmd %d, found 0x%x, need 0x%x\n",
#endif
return (error);
}
/* FIXME: flask ops??? */
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
#endif
return (-X_EINVAL);
}
if (error == 0)
return (error);
}
static int
{
error = 0;
if (count >= 1) {
}
if (error == 0)
if (count > 1)
return (error);
}
static int
{
int error;
int size = 0;
switch (cmd) {
case HVMOP_set_param:
case HVMOP_get_param:
size = sizeof (struct xen_hvm_param);
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
#endif
return (-X_EINVAL);
}
if (error == 0)
return (error);
}
static int
{
int error;
int size = 0;
struct sched_remote_shutdown op;
switch (cmd) {
case SCHEDOP_remote_shutdown:
size = sizeof (struct sched_remote_shutdown);
break;
default:
#ifdef DEBUG
#endif
return (-X_EINVAL);
}
if (error == 0)
return (error);
}
int allow_all_hypercalls = 0;
int privcmd_efault_debug = 0;
/*ARGSUSED*/
int
{
int error;
return (EFAULT);
case __HYPERVISOR_mmu_update:
break;
case __HYPERVISOR_domctl:
break;
case __HYPERVISOR_sysctl:
break;
case __HYPERVISOR_platform_op:
break;
case __HYPERVISOR_memory_op:
break;
break;
case __HYPERVISOR_xen_version:
break;
case __HYPERVISOR_mmuext_op:
break;
case __HYPERVISOR_xsm_op:
break;
case __HYPERVISOR_hvm_op:
break;
case __HYPERVISOR_sched_op:
break;
default:
if (allow_all_hypercalls)
else {
#ifdef DEBUG
#endif
}
break;
}
if (error > 0) {
error = 0;
} else if (error != 0)
return (error);
}