linux/arch/powerpc/kvm/e500.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
   3 *
   4 * Author: Yu Liu, <yu.liu@freescale.com>
   5 *
   6 * Description:
   7 * This file is derived from arch/powerpc/kvm/44x.c,
   8 * by Hollis Blanchard <hollisb@us.ibm.com>.
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License, version 2, as
  12 * published by the Free Software Foundation.
  13 */
  14
  15#include <linux/kvm_host.h>
  16#include <linux/err.h>
  17
  18#include <asm/reg.h>
  19#include <asm/cputable.h>
  20#include <asm/tlbflush.h>
  21#include <asm/kvm_e500.h>
  22#include <asm/kvm_ppc.h>
  23
  24#include "booke.h"
  25#include "e500_tlb.h"
  26
  27void kvmppc_core_load_host_debugstate(struct kvm_vcpu *vcpu)
  28{
  29}
  30
  31void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu)
  32{
  33}
  34
  35void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
  36{
  37        kvmppc_e500_tlb_load(vcpu, cpu);
  38}
  39
  40void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
  41{
  42        kvmppc_e500_tlb_put(vcpu);
  43}
  44
  45int kvmppc_core_check_processor_compat(void)
  46{
  47        int r;
  48
  49        if (strcmp(cur_cpu_spec->cpu_name, "e500v2") == 0)
  50                r = 0;
  51        else
  52                r = -ENOTSUPP;
  53
  54        return r;
  55}
  56
  57int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
  58{
  59        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
  60
  61        kvmppc_e500_tlb_setup(vcpu_e500);
  62
  63        /* Use the same core vertion as host's */
  64        vcpu->arch.pvr = mfspr(SPRN_PVR);
  65
  66        return 0;
  67}
  68
  69/* 'linear_address' is actually an encoding of AS|PID|EADDR . */
  70int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu,
  71                               struct kvm_translation *tr)
  72{
  73        int index;
  74        gva_t eaddr;
  75        u8 pid;
  76        u8 as;
  77
  78        eaddr = tr->linear_address;
  79        pid = (tr->linear_address >> 32) & 0xff;
  80        as = (tr->linear_address >> 40) & 0x1;
  81
  82        index = kvmppc_e500_tlb_search(vcpu, eaddr, pid, as);
  83        if (index < 0) {
  84                tr->valid = 0;
  85                return 0;
  86        }
  87
  88        tr->physical_address = kvmppc_mmu_xlate(vcpu, index, eaddr);
  89        /* XXX what does "writeable" and "usermode" even mean? */
  90        tr->valid = 1;
  91
  92        return 0;
  93}
  94
  95struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
  96{
  97        struct kvmppc_vcpu_e500 *vcpu_e500;
  98        struct kvm_vcpu *vcpu;
  99        int err;
 100
 101        vcpu_e500 = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
 102        if (!vcpu_e500) {
 103                err = -ENOMEM;
 104                goto out;
 105        }
 106
 107        vcpu = &vcpu_e500->vcpu;
 108        err = kvm_vcpu_init(vcpu, kvm, id);
 109        if (err)
 110                goto free_vcpu;
 111
 112        err = kvmppc_e500_tlb_init(vcpu_e500);
 113        if (err)
 114                goto uninit_vcpu;
 115
 116        return vcpu;
 117
 118uninit_vcpu:
 119        kvm_vcpu_uninit(vcpu);
 120free_vcpu:
 121        kmem_cache_free(kvm_vcpu_cache, vcpu_e500);
 122out:
 123        return ERR_PTR(err);
 124}
 125
 126void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
 127{
 128        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
 129
 130        kvmppc_e500_tlb_uninit(vcpu_e500);
 131        kvm_vcpu_uninit(vcpu);
 132        kmem_cache_free(kvm_vcpu_cache, vcpu_e500);
 133}
 134
 135static int kvmppc_e500_init(void)
 136{
 137        int r, i;
 138        unsigned long ivor[3];
 139        unsigned long max_ivor = 0;
 140
 141        r = kvmppc_booke_init();
 142        if (r)
 143                return r;
 144
 145        /* copy extra E500 exception handlers */
 146        ivor[0] = mfspr(SPRN_IVOR32);
 147        ivor[1] = mfspr(SPRN_IVOR33);
 148        ivor[2] = mfspr(SPRN_IVOR34);
 149        for (i = 0; i < 3; i++) {
 150                if (ivor[i] > max_ivor)
 151                        max_ivor = ivor[i];
 152
 153                memcpy((void *)kvmppc_booke_handlers + ivor[i],
 154                       kvmppc_handlers_start + (i + 16) * kvmppc_handler_len,
 155                       kvmppc_handler_len);
 156        }
 157        flush_icache_range(kvmppc_booke_handlers,
 158                        kvmppc_booke_handlers + max_ivor + kvmppc_handler_len);
 159
 160        return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), THIS_MODULE);
 161}
 162
 163static void kvmppc_e500_exit(void)
 164{
 165        kvmppc_booke_exit();
 166}
 167
 168module_init(kvmppc_e500_init);
 169module_exit(kvmppc_e500_exit);
 170