linux/arch/powerpc/kvm/book3s_rtas.c
<<
>>
Prefs
   1/*
   2 * Copyright 2012 Michael Ellerman, IBM Corporation.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License, version 2, as
   6 * published by the Free Software Foundation.
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/kvm_host.h>
  11#include <linux/kvm.h>
  12#include <linux/err.h>
  13
  14#include <linux/uaccess.h>
  15#include <asm/kvm_book3s.h>
  16#include <asm/kvm_ppc.h>
  17#include <asm/hvcall.h>
  18#include <asm/rtas.h>
  19#include <asm/xive.h>
  20
  21#ifdef CONFIG_KVM_XICS
  22static void kvm_rtas_set_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
  23{
  24        u32 irq, server, priority;
  25        int rc;
  26
  27        if (be32_to_cpu(args->nargs) != 3 || be32_to_cpu(args->nret) != 1) {
  28                rc = -3;
  29                goto out;
  30        }
  31
  32        irq = be32_to_cpu(args->args[0]);
  33        server = be32_to_cpu(args->args[1]);
  34        priority = be32_to_cpu(args->args[2]);
  35
  36        if (xive_enabled())
  37                rc = kvmppc_xive_set_xive(vcpu->kvm, irq, server, priority);
  38        else
  39                rc = kvmppc_xics_set_xive(vcpu->kvm, irq, server, priority);
  40        if (rc)
  41                rc = -3;
  42out:
  43        args->rets[0] = cpu_to_be32(rc);
  44}
  45
  46static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
  47{
  48        u32 irq, server, priority;
  49        int rc;
  50
  51        if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 3) {
  52                rc = -3;
  53                goto out;
  54        }
  55
  56        irq = be32_to_cpu(args->args[0]);
  57
  58        server = priority = 0;
  59        if (xive_enabled())
  60                rc = kvmppc_xive_get_xive(vcpu->kvm, irq, &server, &priority);
  61        else
  62                rc = kvmppc_xics_get_xive(vcpu->kvm, irq, &server, &priority);
  63        if (rc) {
  64                rc = -3;
  65                goto out;
  66        }
  67
  68        args->rets[1] = cpu_to_be32(server);
  69        args->rets[2] = cpu_to_be32(priority);
  70out:
  71        args->rets[0] = cpu_to_be32(rc);
  72}
  73
  74static void kvm_rtas_int_off(struct kvm_vcpu *vcpu, struct rtas_args *args)
  75{
  76        u32 irq;
  77        int rc;
  78
  79        if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
  80                rc = -3;
  81                goto out;
  82        }
  83
  84        irq = be32_to_cpu(args->args[0]);
  85
  86        if (xive_enabled())
  87                rc = kvmppc_xive_int_off(vcpu->kvm, irq);
  88        else
  89                rc = kvmppc_xics_int_off(vcpu->kvm, irq);
  90        if (rc)
  91                rc = -3;
  92out:
  93        args->rets[0] = cpu_to_be32(rc);
  94}
  95
  96static void kvm_rtas_int_on(struct kvm_vcpu *vcpu, struct rtas_args *args)
  97{
  98        u32 irq;
  99        int rc;
 100
 101        if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
 102                rc = -3;
 103                goto out;
 104        }
 105
 106        irq = be32_to_cpu(args->args[0]);
 107
 108        if (xive_enabled())
 109                rc = kvmppc_xive_int_on(vcpu->kvm, irq);
 110        else
 111                rc = kvmppc_xics_int_on(vcpu->kvm, irq);
 112        if (rc)
 113                rc = -3;
 114out:
 115        args->rets[0] = cpu_to_be32(rc);
 116}
 117#endif /* CONFIG_KVM_XICS */
 118
 119struct rtas_handler {
 120        void (*handler)(struct kvm_vcpu *vcpu, struct rtas_args *args);
 121        char *name;
 122};
 123
 124static struct rtas_handler rtas_handlers[] = {
 125#ifdef CONFIG_KVM_XICS
 126        { .name = "ibm,set-xive", .handler = kvm_rtas_set_xive },
 127        { .name = "ibm,get-xive", .handler = kvm_rtas_get_xive },
 128        { .name = "ibm,int-off",  .handler = kvm_rtas_int_off },
 129        { .name = "ibm,int-on",   .handler = kvm_rtas_int_on },
 130#endif
 131};
 132
 133struct rtas_token_definition {
 134        struct list_head list;
 135        struct rtas_handler *handler;
 136        u64 token;
 137};
 138
 139static int rtas_name_matches(char *s1, char *s2)
 140{
 141        struct kvm_rtas_token_args args;
 142        return !strncmp(s1, s2, sizeof(args.name));
 143}
 144
 145static int rtas_token_undefine(struct kvm *kvm, char *name)
 146{
 147        struct rtas_token_definition *d, *tmp;
 148
 149        lockdep_assert_held(&kvm->lock);
 150
 151        list_for_each_entry_safe(d, tmp, &kvm->arch.rtas_tokens, list) {
 152                if (rtas_name_matches(d->handler->name, name)) {
 153                        list_del(&d->list);
 154                        kfree(d);
 155                        return 0;
 156                }
 157        }
 158
 159        /* It's not an error to undefine an undefined token */
 160        return 0;
 161}
 162
 163static int rtas_token_define(struct kvm *kvm, char *name, u64 token)
 164{
 165        struct rtas_token_definition *d;
 166        struct rtas_handler *h = NULL;
 167        bool found;
 168        int i;
 169
 170        lockdep_assert_held(&kvm->lock);
 171
 172        list_for_each_entry(d, &kvm->arch.rtas_tokens, list) {
 173                if (d->token == token)
 174                        return -EEXIST;
 175        }
 176
 177        found = false;
 178        for (i = 0; i < ARRAY_SIZE(rtas_handlers); i++) {
 179                h = &rtas_handlers[i];
 180                if (rtas_name_matches(h->name, name)) {
 181                        found = true;
 182                        break;
 183                }
 184        }
 185
 186        if (!found)
 187                return -ENOENT;
 188
 189        d = kzalloc(sizeof(*d), GFP_KERNEL);
 190        if (!d)
 191                return -ENOMEM;
 192
 193        d->handler = h;
 194        d->token = token;
 195
 196        list_add_tail(&d->list, &kvm->arch.rtas_tokens);
 197
 198        return 0;
 199}
 200
 201int kvm_vm_ioctl_rtas_define_token(struct kvm *kvm, void __user *argp)
 202{
 203        struct kvm_rtas_token_args args;
 204        int rc;
 205
 206        if (copy_from_user(&args, argp, sizeof(args)))
 207                return -EFAULT;
 208
 209        mutex_lock(&kvm->lock);
 210
 211        if (args.token)
 212                rc = rtas_token_define(kvm, args.name, args.token);
 213        else
 214                rc = rtas_token_undefine(kvm, args.name);
 215
 216        mutex_unlock(&kvm->lock);
 217
 218        return rc;
 219}
 220
 221int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
 222{
 223        struct rtas_token_definition *d;
 224        struct rtas_args args;
 225        rtas_arg_t *orig_rets;
 226        gpa_t args_phys;
 227        int rc;
 228
 229        /*
 230         * r4 contains the guest physical address of the RTAS args
 231         * Mask off the top 4 bits since this is a guest real address
 232         */
 233        args_phys = kvmppc_get_gpr(vcpu, 4) & KVM_PAM;
 234
 235        rc = kvm_read_guest(vcpu->kvm, args_phys, &args, sizeof(args));
 236        if (rc)
 237                goto fail;
 238
 239        /*
 240         * args->rets is a pointer into args->args. Now that we've
 241         * copied args we need to fix it up to point into our copy,
 242         * not the guest args. We also need to save the original
 243         * value so we can restore it on the way out.
 244         */
 245        orig_rets = args.rets;
 246        args.rets = &args.args[be32_to_cpu(args.nargs)];
 247
 248        mutex_lock(&vcpu->kvm->lock);
 249
 250        rc = -ENOENT;
 251        list_for_each_entry(d, &vcpu->kvm->arch.rtas_tokens, list) {
 252                if (d->token == be32_to_cpu(args.token)) {
 253                        d->handler->handler(vcpu, &args);
 254                        rc = 0;
 255                        break;
 256                }
 257        }
 258
 259        mutex_unlock(&vcpu->kvm->lock);
 260
 261        if (rc == 0) {
 262                args.rets = orig_rets;
 263                rc = kvm_write_guest(vcpu->kvm, args_phys, &args, sizeof(args));
 264                if (rc)
 265                        goto fail;
 266        }
 267
 268        return rc;
 269
 270fail:
 271        /*
 272         * We only get here if the guest has called RTAS with a bogus
 273         * args pointer. That means we can't get to the args, and so we
 274         * can't fail the RTAS call. So fail right out to userspace,
 275         * which should kill the guest.
 276         */
 277        return rc;
 278}
 279EXPORT_SYMBOL_GPL(kvmppc_rtas_hcall);
 280
 281void kvmppc_rtas_tokens_free(struct kvm *kvm)
 282{
 283        struct rtas_token_definition *d, *tmp;
 284
 285        lockdep_assert_held(&kvm->lock);
 286
 287        list_for_each_entry_safe(d, tmp, &kvm->arch.rtas_tokens, list) {
 288                list_del(&d->list);
 289                kfree(d);
 290        }
 291}
 292