linux/arch/ia64/xen/xcom_hcall.c
<<
>>
Prefs
   1/*
   2 * This program is free software; you can redistribute it and/or modify
   3 * it under the terms of the GNU General Public License as published by
   4 * the Free Software Foundation; either version 2 of the License, or
   5 * (at your option) any later version.
   6 *
   7 * This program is distributed in the hope that it will be useful,
   8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10 * GNU General Public License for more details.
  11 *
  12 * You should have received a copy of the GNU General Public License
  13 * along with this program; if not, write to the Free Software
  14 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  15 *
  16 *          Tristan Gingold <tristan.gingold@bull.net>
  17 *
  18 *          Copyright (c) 2007
  19 *          Isaku Yamahata <yamahata at valinux co jp>
  20 *                          VA Linux Systems Japan K.K.
  21 *          consolidate mini and inline version.
  22 */
  23
  24#include <linux/module.h>
  25#include <xen/interface/xen.h>
  26#include <xen/interface/memory.h>
  27#include <xen/interface/grant_table.h>
  28#include <xen/interface/callback.h>
  29#include <xen/interface/vcpu.h>
  30#include <asm/xen/hypervisor.h>
  31#include <asm/xen/xencomm.h>
  32
  33/* Xencomm notes:
  34 * This file defines hypercalls to be used by xencomm.  The hypercalls simply
  35 * create inlines or mini descriptors for pointers and then call the raw arch
  36 * hypercall xencomm_arch_hypercall_XXX
  37 *
  38 * If the arch wants to directly use these hypercalls, simply define macros
  39 * in asm/xen/hypercall.h, eg:
  40 *  #define HYPERVISOR_sched_op xencomm_hypercall_sched_op
  41 *
  42 * The arch may also define HYPERVISOR_xxx as a function and do more operations
  43 * before/after doing the hypercall.
  44 *
  45 * Note: because only inline or mini descriptors are created these functions
  46 * must only be called with in kernel memory parameters.
  47 */
  48
  49int
  50xencomm_hypercall_console_io(int cmd, int count, char *str)
  51{
  52        /* xen early printk uses console io hypercall before
  53         * xencomm initialization. In that case, we just ignore it.
  54         */
  55        if (!xencomm_is_initialized())
  56                return 0;
  57
  58        return xencomm_arch_hypercall_console_io
  59                (cmd, count, xencomm_map_no_alloc(str, count));
  60}
  61EXPORT_SYMBOL_GPL(xencomm_hypercall_console_io);
  62
  63int
  64xencomm_hypercall_event_channel_op(int cmd, void *op)
  65{
  66        struct xencomm_handle *desc;
  67        desc = xencomm_map_no_alloc(op, sizeof(struct evtchn_op));
  68        if (desc == NULL)
  69                return -EINVAL;
  70
  71        return xencomm_arch_hypercall_event_channel_op(cmd, desc);
  72}
  73EXPORT_SYMBOL_GPL(xencomm_hypercall_event_channel_op);
  74
  75int
  76xencomm_hypercall_xen_version(int cmd, void *arg)
  77{
  78        struct xencomm_handle *desc;
  79        unsigned int argsize;
  80
  81        switch (cmd) {
  82        case XENVER_version:
  83                /* do not actually pass an argument */
  84                return xencomm_arch_hypercall_xen_version(cmd, 0);
  85        case XENVER_extraversion:
  86                argsize = sizeof(struct xen_extraversion);
  87                break;
  88        case XENVER_compile_info:
  89                argsize = sizeof(struct xen_compile_info);
  90                break;
  91        case XENVER_capabilities:
  92                argsize = sizeof(struct xen_capabilities_info);
  93                break;
  94        case XENVER_changeset:
  95                argsize = sizeof(struct xen_changeset_info);
  96                break;
  97        case XENVER_platform_parameters:
  98                argsize = sizeof(struct xen_platform_parameters);
  99                break;
 100        case XENVER_get_features:
 101                argsize = (arg == NULL) ? 0 : sizeof(struct xen_feature_info);
 102                break;
 103
 104        default:
 105                printk(KERN_DEBUG
 106                       "%s: unknown version op %d\n", __func__, cmd);
 107                return -ENOSYS;
 108        }
 109
 110        desc = xencomm_map_no_alloc(arg, argsize);
 111        if (desc == NULL)
 112                return -EINVAL;
 113
 114        return xencomm_arch_hypercall_xen_version(cmd, desc);
 115}
 116EXPORT_SYMBOL_GPL(xencomm_hypercall_xen_version);
 117
 118int
 119xencomm_hypercall_physdev_op(int cmd, void *op)
 120{
 121        unsigned int argsize;
 122
 123        switch (cmd) {
 124        case PHYSDEVOP_apic_read:
 125        case PHYSDEVOP_apic_write:
 126                argsize = sizeof(struct physdev_apic);
 127                break;
 128        case PHYSDEVOP_alloc_irq_vector:
 129        case PHYSDEVOP_free_irq_vector:
 130                argsize = sizeof(struct physdev_irq);
 131                break;
 132        case PHYSDEVOP_irq_status_query:
 133                argsize = sizeof(struct physdev_irq_status_query);
 134                break;
 135
 136        default:
 137                printk(KERN_DEBUG
 138                       "%s: unknown physdev op %d\n", __func__, cmd);
 139                return -ENOSYS;
 140        }
 141
 142        return xencomm_arch_hypercall_physdev_op
 143                (cmd, xencomm_map_no_alloc(op, argsize));
 144}
 145
 146static int
 147xencommize_grant_table_op(struct xencomm_mini **xc_area,
 148                          unsigned int cmd, void *op, unsigned int count,
 149                          struct xencomm_handle **desc)
 150{
 151        struct xencomm_handle *desc1;
 152        unsigned int argsize;
 153
 154        switch (cmd) {
 155        case GNTTABOP_map_grant_ref:
 156                argsize = sizeof(struct gnttab_map_grant_ref);
 157                break;
 158        case GNTTABOP_unmap_grant_ref:
 159                argsize = sizeof(struct gnttab_unmap_grant_ref);
 160                break;
 161        case GNTTABOP_setup_table:
 162        {
 163                struct gnttab_setup_table *setup = op;
 164
 165                argsize = sizeof(*setup);
 166
 167                if (count != 1)
 168                        return -EINVAL;
 169                desc1 = __xencomm_map_no_alloc
 170                        (xen_guest_handle(setup->frame_list),
 171                         setup->nr_frames *
 172                         sizeof(*xen_guest_handle(setup->frame_list)),
 173                         *xc_area);
 174                if (desc1 == NULL)
 175                        return -EINVAL;
 176                (*xc_area)++;
 177                set_xen_guest_handle(setup->frame_list, (void *)desc1);
 178                break;
 179        }
 180        case GNTTABOP_dump_table:
 181                argsize = sizeof(struct gnttab_dump_table);
 182                break;
 183        case GNTTABOP_transfer:
 184                argsize = sizeof(struct gnttab_transfer);
 185                break;
 186        case GNTTABOP_copy:
 187                argsize = sizeof(struct gnttab_copy);
 188                break;
 189        case GNTTABOP_query_size:
 190                argsize = sizeof(struct gnttab_query_size);
 191                break;
 192        default:
 193                printk(KERN_DEBUG "%s: unknown hypercall grant table op %d\n",
 194                       __func__, cmd);
 195                BUG();
 196        }
 197
 198        *desc = __xencomm_map_no_alloc(op, count * argsize, *xc_area);
 199        if (*desc == NULL)
 200                return -EINVAL;
 201        (*xc_area)++;
 202
 203        return 0;
 204}
 205
 206int
 207xencomm_hypercall_grant_table_op(unsigned int cmd, void *op,
 208                                 unsigned int count)
 209{
 210        int rc;
 211        struct xencomm_handle *desc;
 212        XENCOMM_MINI_ALIGNED(xc_area, 2);
 213
 214        rc = xencommize_grant_table_op(&xc_area, cmd, op, count, &desc);
 215        if (rc)
 216                return rc;
 217
 218        return xencomm_arch_hypercall_grant_table_op(cmd, desc, count);
 219}
 220EXPORT_SYMBOL_GPL(xencomm_hypercall_grant_table_op);
 221
 222int
 223xencomm_hypercall_sched_op(int cmd, void *arg)
 224{
 225        struct xencomm_handle *desc;
 226        unsigned int argsize;
 227
 228        switch (cmd) {
 229        case SCHEDOP_yield:
 230        case SCHEDOP_block:
 231                argsize = 0;
 232                break;
 233        case SCHEDOP_shutdown:
 234                argsize = sizeof(struct sched_shutdown);
 235                break;
 236        case SCHEDOP_poll:
 237        {
 238                struct sched_poll *poll = arg;
 239                struct xencomm_handle *ports;
 240
 241                argsize = sizeof(struct sched_poll);
 242                ports = xencomm_map_no_alloc(xen_guest_handle(poll->ports),
 243                                     sizeof(*xen_guest_handle(poll->ports)));
 244
 245                set_xen_guest_handle(poll->ports, (void *)ports);
 246                break;
 247        }
 248        default:
 249                printk(KERN_DEBUG "%s: unknown sched op %d\n", __func__, cmd);
 250                return -ENOSYS;
 251        }
 252
 253        desc = xencomm_map_no_alloc(arg, argsize);
 254        if (desc == NULL)
 255                return -EINVAL;
 256
 257        return xencomm_arch_hypercall_sched_op(cmd, desc);
 258}
 259EXPORT_SYMBOL_GPL(xencomm_hypercall_sched_op);
 260
 261int
 262xencomm_hypercall_multicall(void *call_list, int nr_calls)
 263{
 264        int rc;
 265        int i;
 266        struct multicall_entry *mce;
 267        struct xencomm_handle *desc;
 268        XENCOMM_MINI_ALIGNED(xc_area, nr_calls * 2);
 269
 270        for (i = 0; i < nr_calls; i++) {
 271                mce = (struct multicall_entry *)call_list + i;
 272
 273                switch (mce->op) {
 274                case __HYPERVISOR_update_va_mapping:
 275                case __HYPERVISOR_mmu_update:
 276                        /* No-op on ia64.  */
 277                        break;
 278                case __HYPERVISOR_grant_table_op:
 279                        rc = xencommize_grant_table_op
 280                                (&xc_area,
 281                                 mce->args[0], (void *)mce->args[1],
 282                                 mce->args[2], &desc);
 283                        if (rc)
 284                                return rc;
 285                        mce->args[1] = (unsigned long)desc;
 286                        break;
 287                case __HYPERVISOR_memory_op:
 288                default:
 289                        printk(KERN_DEBUG
 290                               "%s: unhandled multicall op entry op %lu\n",
 291                               __func__, mce->op);
 292                        return -ENOSYS;
 293                }
 294        }
 295
 296        desc = xencomm_map_no_alloc(call_list,
 297                                    nr_calls * sizeof(struct multicall_entry));
 298        if (desc == NULL)
 299                return -EINVAL;
 300
 301        return xencomm_arch_hypercall_multicall(desc, nr_calls);
 302}
 303EXPORT_SYMBOL_GPL(xencomm_hypercall_multicall);
 304
 305int
 306xencomm_hypercall_callback_op(int cmd, void *arg)
 307{
 308        unsigned int argsize;
 309        switch (cmd) {
 310        case CALLBACKOP_register:
 311                argsize = sizeof(struct callback_register);
 312                break;
 313        case CALLBACKOP_unregister:
 314                argsize = sizeof(struct callback_unregister);
 315                break;
 316        default:
 317                printk(KERN_DEBUG
 318                       "%s: unknown callback op %d\n", __func__, cmd);
 319                return -ENOSYS;
 320        }
 321
 322        return xencomm_arch_hypercall_callback_op
 323                (cmd, xencomm_map_no_alloc(arg, argsize));
 324}
 325
 326static int
 327xencommize_memory_reservation(struct xencomm_mini *xc_area,
 328                              struct xen_memory_reservation *mop)
 329{
 330        struct xencomm_handle *desc;
 331
 332        desc = __xencomm_map_no_alloc(xen_guest_handle(mop->extent_start),
 333                        mop->nr_extents *
 334                        sizeof(*xen_guest_handle(mop->extent_start)),
 335                        xc_area);
 336        if (desc == NULL)
 337                return -EINVAL;
 338
 339        set_xen_guest_handle(mop->extent_start, (void *)desc);
 340        return 0;
 341}
 342
 343int
 344xencomm_hypercall_memory_op(unsigned int cmd, void *arg)
 345{
 346        GUEST_HANDLE(xen_pfn_t) extent_start_va[2] = { {NULL}, {NULL} };
 347        struct xen_memory_reservation *xmr = NULL;
 348        int rc;
 349        struct xencomm_handle *desc;
 350        unsigned int argsize;
 351        XENCOMM_MINI_ALIGNED(xc_area, 2);
 352
 353        switch (cmd) {
 354        case XENMEM_increase_reservation:
 355        case XENMEM_decrease_reservation:
 356        case XENMEM_populate_physmap:
 357                xmr = (struct xen_memory_reservation *)arg;
 358                set_xen_guest_handle(extent_start_va[0],
 359                                     xen_guest_handle(xmr->extent_start));
 360
 361                argsize = sizeof(*xmr);
 362                rc = xencommize_memory_reservation(xc_area, xmr);
 363                if (rc)
 364                        return rc;
 365                xc_area++;
 366                break;
 367
 368        case XENMEM_maximum_ram_page:
 369                argsize = 0;
 370                break;
 371
 372        case XENMEM_add_to_physmap:
 373                argsize = sizeof(struct xen_add_to_physmap);
 374                break;
 375
 376        default:
 377                printk(KERN_DEBUG "%s: unknown memory op %d\n", __func__, cmd);
 378                return -ENOSYS;
 379        }
 380
 381        desc = xencomm_map_no_alloc(arg, argsize);
 382        if (desc == NULL)
 383                return -EINVAL;
 384
 385        rc = xencomm_arch_hypercall_memory_op(cmd, desc);
 386
 387        switch (cmd) {
 388        case XENMEM_increase_reservation:
 389        case XENMEM_decrease_reservation:
 390        case XENMEM_populate_physmap:
 391                set_xen_guest_handle(xmr->extent_start,
 392                                     xen_guest_handle(extent_start_va[0]));
 393                break;
 394        }
 395
 396        return rc;
 397}
 398EXPORT_SYMBOL_GPL(xencomm_hypercall_memory_op);
 399
 400int
 401xencomm_hypercall_suspend(unsigned long srec)
 402{
 403        struct sched_shutdown arg;
 404
 405        arg.reason = SHUTDOWN_suspend;
 406
 407        return xencomm_arch_hypercall_sched_op(
 408                SCHEDOP_shutdown, xencomm_map_no_alloc(&arg, sizeof(arg)));
 409}
 410
 411long
 412xencomm_hypercall_vcpu_op(int cmd, int cpu, void *arg)
 413{
 414        unsigned int argsize;
 415        switch (cmd) {
 416        case VCPUOP_register_runstate_memory_area: {
 417                struct vcpu_register_runstate_memory_area *area =
 418                        (struct vcpu_register_runstate_memory_area *)arg;
 419                argsize = sizeof(*arg);
 420                set_xen_guest_handle(area->addr.h,
 421                     (void *)xencomm_map_no_alloc(area->addr.v,
 422                                                  sizeof(area->addr.v)));
 423                break;
 424        }
 425
 426        default:
 427                printk(KERN_DEBUG "%s: unknown vcpu op %d\n", __func__, cmd);
 428                return -ENOSYS;
 429        }
 430
 431        return xencomm_arch_hypercall_vcpu_op(cmd, cpu,
 432                                        xencomm_map_no_alloc(arg, argsize));
 433}
 434
 435long
 436xencomm_hypercall_opt_feature(void *arg)
 437{
 438        return xencomm_arch_hypercall_opt_feature(
 439                xencomm_map_no_alloc(arg,
 440                                     sizeof(struct xen_ia64_opt_feature)));
 441}
 442