linux/arch/powerpc/kvm/44x.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, version 2, as
   4 * published by the Free Software Foundation.
   5 *
   6 * This program is distributed in the hope that it will be useful,
   7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   9 * GNU General Public License for more details.
  10 *
  11 * You should have received a copy of the GNU General Public License
  12 * along with this program; if not, write to the Free Software
  13 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  14 *
  15 * Copyright IBM Corp. 2008
  16 *
  17 * Authors: Hollis Blanchard <hollisb@us.ibm.com>
  18 */
  19
  20#include <linux/kvm_host.h>
  21#include <linux/slab.h>
  22#include <linux/err.h>
  23#include <linux/export.h>
  24#include <linux/module.h>
  25#include <linux/miscdevice.h>
  26
  27#include <asm/reg.h>
  28#include <asm/cputable.h>
  29#include <asm/tlbflush.h>
  30#include <asm/kvm_44x.h>
  31#include <asm/kvm_ppc.h>
  32
  33#include "44x_tlb.h"
  34#include "booke.h"
  35
  36static void kvmppc_core_vcpu_load_44x(struct kvm_vcpu *vcpu, int cpu)
  37{
  38        kvmppc_booke_vcpu_load(vcpu, cpu);
  39        kvmppc_44x_tlb_load(vcpu);
  40}
  41
  42static void kvmppc_core_vcpu_put_44x(struct kvm_vcpu *vcpu)
  43{
  44        kvmppc_44x_tlb_put(vcpu);
  45        kvmppc_booke_vcpu_put(vcpu);
  46}
  47
  48int kvmppc_core_check_processor_compat(void)
  49{
  50        int r;
  51
  52        if (strncmp(cur_cpu_spec->platform, "ppc440", 6) == 0)
  53                r = 0;
  54        else
  55                r = -ENOTSUPP;
  56
  57        return r;
  58}
  59
  60int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
  61{
  62        struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
  63        struct kvmppc_44x_tlbe *tlbe = &vcpu_44x->guest_tlb[0];
  64        int i;
  65
  66        tlbe->tid = 0;
  67        tlbe->word0 = PPC44x_TLB_16M | PPC44x_TLB_VALID;
  68        tlbe->word1 = 0;
  69        tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR;
  70
  71        tlbe++;
  72        tlbe->tid = 0;
  73        tlbe->word0 = 0xef600000 | PPC44x_TLB_4K | PPC44x_TLB_VALID;
  74        tlbe->word1 = 0xef600000;
  75        tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR
  76                      | PPC44x_TLB_I | PPC44x_TLB_G;
  77
  78        /* Since the guest can directly access the timebase, it must know the
  79         * real timebase frequency. Accordingly, it must see the state of
  80         * CCR1[TCS]. */
  81        /* XXX CCR1 doesn't exist on all 440 SoCs. */
  82        vcpu->arch.ccr1 = mfspr(SPRN_CCR1);
  83
  84        for (i = 0; i < ARRAY_SIZE(vcpu_44x->shadow_refs); i++)
  85                vcpu_44x->shadow_refs[i].gtlb_index = -1;
  86
  87        vcpu->arch.cpu_type = KVM_CPU_440;
  88        vcpu->arch.pvr = mfspr(SPRN_PVR);
  89
  90        return 0;
  91}
  92
  93/* 'linear_address' is actually an encoding of AS|PID|EADDR . */
  94int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu,
  95                               struct kvm_translation *tr)
  96{
  97        int index;
  98        gva_t eaddr;
  99        u8 pid;
 100        u8 as;
 101
 102        eaddr = tr->linear_address;
 103        pid = (tr->linear_address >> 32) & 0xff;
 104        as = (tr->linear_address >> 40) & 0x1;
 105
 106        index = kvmppc_44x_tlb_index(vcpu, eaddr, pid, as);
 107        if (index == -1) {
 108                tr->valid = 0;
 109                return 0;
 110        }
 111
 112        tr->physical_address = kvmppc_mmu_xlate(vcpu, index, eaddr);
 113        /* XXX what does "writeable" and "usermode" even mean? */
 114        tr->valid = 1;
 115
 116        return 0;
 117}
 118
 119static int kvmppc_core_get_sregs_44x(struct kvm_vcpu *vcpu,
 120                                      struct kvm_sregs *sregs)
 121{
 122        return kvmppc_get_sregs_ivor(vcpu, sregs);
 123}
 124
 125static int kvmppc_core_set_sregs_44x(struct kvm_vcpu *vcpu,
 126                                     struct kvm_sregs *sregs)
 127{
 128        return kvmppc_set_sregs_ivor(vcpu, sregs);
 129}
 130
 131static int kvmppc_get_one_reg_44x(struct kvm_vcpu *vcpu, u64 id,
 132                                  union kvmppc_one_reg *val)
 133{
 134        return -EINVAL;
 135}
 136
 137static int kvmppc_set_one_reg_44x(struct kvm_vcpu *vcpu, u64 id,
 138                                  union kvmppc_one_reg *val)
 139{
 140        return -EINVAL;
 141}
 142
 143static struct kvm_vcpu *kvmppc_core_vcpu_create_44x(struct kvm *kvm,
 144                                                    unsigned int id)
 145{
 146        struct kvmppc_vcpu_44x *vcpu_44x;
 147        struct kvm_vcpu *vcpu;
 148        int err;
 149
 150        vcpu_44x = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
 151        if (!vcpu_44x) {
 152                err = -ENOMEM;
 153                goto out;
 154        }
 155
 156        vcpu = &vcpu_44x->vcpu;
 157        err = kvm_vcpu_init(vcpu, kvm, id);
 158        if (err)
 159                goto free_vcpu;
 160
 161        vcpu->arch.shared = (void*)__get_free_page(GFP_KERNEL|__GFP_ZERO);
 162        if (!vcpu->arch.shared)
 163                goto uninit_vcpu;
 164
 165        return vcpu;
 166
 167uninit_vcpu:
 168        kvm_vcpu_uninit(vcpu);
 169free_vcpu:
 170        kmem_cache_free(kvm_vcpu_cache, vcpu_44x);
 171out:
 172        return ERR_PTR(err);
 173}
 174
 175static void kvmppc_core_vcpu_free_44x(struct kvm_vcpu *vcpu)
 176{
 177        struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
 178
 179        free_page((unsigned long)vcpu->arch.shared);
 180        kvm_vcpu_uninit(vcpu);
 181        kmem_cache_free(kvm_vcpu_cache, vcpu_44x);
 182}
 183
 184static int kvmppc_core_init_vm_44x(struct kvm *kvm)
 185{
 186        return 0;
 187}
 188
 189static void kvmppc_core_destroy_vm_44x(struct kvm *kvm)
 190{
 191}
 192
 193static struct kvmppc_ops kvm_ops_44x = {
 194        .get_sregs = kvmppc_core_get_sregs_44x,
 195        .set_sregs = kvmppc_core_set_sregs_44x,
 196        .get_one_reg = kvmppc_get_one_reg_44x,
 197        .set_one_reg = kvmppc_set_one_reg_44x,
 198        .vcpu_load   = kvmppc_core_vcpu_load_44x,
 199        .vcpu_put    = kvmppc_core_vcpu_put_44x,
 200        .vcpu_create = kvmppc_core_vcpu_create_44x,
 201        .vcpu_free   = kvmppc_core_vcpu_free_44x,
 202        .mmu_destroy  = kvmppc_mmu_destroy_44x,
 203        .init_vm = kvmppc_core_init_vm_44x,
 204        .destroy_vm = kvmppc_core_destroy_vm_44x,
 205        .emulate_op = kvmppc_core_emulate_op_44x,
 206        .emulate_mtspr = kvmppc_core_emulate_mtspr_44x,
 207        .emulate_mfspr = kvmppc_core_emulate_mfspr_44x,
 208};
 209
 210static int __init kvmppc_44x_init(void)
 211{
 212        int r;
 213
 214        r = kvmppc_booke_init();
 215        if (r)
 216                goto err_out;
 217
 218        r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_44x), 0, THIS_MODULE);
 219        if (r)
 220                goto err_out;
 221        kvm_ops_44x.owner = THIS_MODULE;
 222        kvmppc_pr_ops = &kvm_ops_44x;
 223
 224err_out:
 225        return r;
 226}
 227
 228static void __exit kvmppc_44x_exit(void)
 229{
 230        kvmppc_pr_ops = NULL;
 231        kvmppc_booke_exit();
 232}
 233
 234module_init(kvmppc_44x_init);
 235module_exit(kvmppc_44x_exit);
 236MODULE_ALIAS_MISCDEV(KVM_MINOR);
 237MODULE_ALIAS("devname:kvm");
 238