Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.29 228 lines 5.6 kB view raw
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/err.h> 22 23#include <asm/reg.h> 24#include <asm/cputable.h> 25#include <asm/tlbflush.h> 26#include <asm/kvm_44x.h> 27#include <asm/kvm_ppc.h> 28 29#include "44x_tlb.h" 30 31/* Note: clearing MSR[DE] just means that the debug interrupt will not be 32 * delivered *immediately*. Instead, it simply sets the appropriate DBSR bits. 33 * If those DBSR bits are still set when MSR[DE] is re-enabled, the interrupt 34 * will be delivered as an "imprecise debug event" (which is indicated by 35 * DBSR[IDE]. 36 */ 37static void kvm44x_disable_debug_interrupts(void) 38{ 39 mtmsr(mfmsr() & ~MSR_DE); 40} 41 42void kvmppc_core_load_host_debugstate(struct kvm_vcpu *vcpu) 43{ 44 kvm44x_disable_debug_interrupts(); 45 46 mtspr(SPRN_IAC1, vcpu->arch.host_iac[0]); 47 mtspr(SPRN_IAC2, vcpu->arch.host_iac[1]); 48 mtspr(SPRN_IAC3, vcpu->arch.host_iac[2]); 49 mtspr(SPRN_IAC4, vcpu->arch.host_iac[3]); 50 mtspr(SPRN_DBCR1, vcpu->arch.host_dbcr1); 51 mtspr(SPRN_DBCR2, vcpu->arch.host_dbcr2); 52 mtspr(SPRN_DBCR0, vcpu->arch.host_dbcr0); 53 mtmsr(vcpu->arch.host_msr); 54} 55 56void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu) 57{ 58 struct kvm_guest_debug *dbg = &vcpu->guest_debug; 59 u32 dbcr0 = 0; 60 61 vcpu->arch.host_msr = mfmsr(); 62 kvm44x_disable_debug_interrupts(); 63 64 /* Save host debug register state. */ 65 vcpu->arch.host_iac[0] = mfspr(SPRN_IAC1); 66 vcpu->arch.host_iac[1] = mfspr(SPRN_IAC2); 67 vcpu->arch.host_iac[2] = mfspr(SPRN_IAC3); 68 vcpu->arch.host_iac[3] = mfspr(SPRN_IAC4); 69 vcpu->arch.host_dbcr0 = mfspr(SPRN_DBCR0); 70 vcpu->arch.host_dbcr1 = mfspr(SPRN_DBCR1); 71 vcpu->arch.host_dbcr2 = mfspr(SPRN_DBCR2); 72 73 /* set registers up for guest */ 74 75 if (dbg->bp[0]) { 76 mtspr(SPRN_IAC1, dbg->bp[0]); 77 dbcr0 |= DBCR0_IAC1 | DBCR0_IDM; 78 } 79 if (dbg->bp[1]) { 80 mtspr(SPRN_IAC2, dbg->bp[1]); 81 dbcr0 |= DBCR0_IAC2 | DBCR0_IDM; 82 } 83 if (dbg->bp[2]) { 84 mtspr(SPRN_IAC3, dbg->bp[2]); 85 dbcr0 |= DBCR0_IAC3 | DBCR0_IDM; 86 } 87 if (dbg->bp[3]) { 88 mtspr(SPRN_IAC4, dbg->bp[3]); 89 dbcr0 |= DBCR0_IAC4 | DBCR0_IDM; 90 } 91 92 mtspr(SPRN_DBCR0, dbcr0); 93 mtspr(SPRN_DBCR1, 0); 94 mtspr(SPRN_DBCR2, 0); 95} 96 97void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) 98{ 99 kvmppc_44x_tlb_load(vcpu); 100} 101 102void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) 103{ 104 kvmppc_44x_tlb_put(vcpu); 105} 106 107int kvmppc_core_check_processor_compat(void) 108{ 109 int r; 110 111 if (strcmp(cur_cpu_spec->platform, "ppc440") == 0) 112 r = 0; 113 else 114 r = -ENOTSUPP; 115 116 return r; 117} 118 119int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu) 120{ 121 struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); 122 struct kvmppc_44x_tlbe *tlbe = &vcpu_44x->guest_tlb[0]; 123 int i; 124 125 tlbe->tid = 0; 126 tlbe->word0 = PPC44x_TLB_16M | PPC44x_TLB_VALID; 127 tlbe->word1 = 0; 128 tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR; 129 130 tlbe++; 131 tlbe->tid = 0; 132 tlbe->word0 = 0xef600000 | PPC44x_TLB_4K | PPC44x_TLB_VALID; 133 tlbe->word1 = 0xef600000; 134 tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR 135 | PPC44x_TLB_I | PPC44x_TLB_G; 136 137 /* Since the guest can directly access the timebase, it must know the 138 * real timebase frequency. Accordingly, it must see the state of 139 * CCR1[TCS]. */ 140 vcpu->arch.ccr1 = mfspr(SPRN_CCR1); 141 142 for (i = 0; i < ARRAY_SIZE(vcpu_44x->shadow_refs); i++) 143 vcpu_44x->shadow_refs[i].gtlb_index = -1; 144 145 return 0; 146} 147 148/* 'linear_address' is actually an encoding of AS|PID|EADDR . */ 149int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu, 150 struct kvm_translation *tr) 151{ 152 struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); 153 struct kvmppc_44x_tlbe *gtlbe; 154 int index; 155 gva_t eaddr; 156 u8 pid; 157 u8 as; 158 159 eaddr = tr->linear_address; 160 pid = (tr->linear_address >> 32) & 0xff; 161 as = (tr->linear_address >> 40) & 0x1; 162 163 index = kvmppc_44x_tlb_index(vcpu, eaddr, pid, as); 164 if (index == -1) { 165 tr->valid = 0; 166 return 0; 167 } 168 169 gtlbe = &vcpu_44x->guest_tlb[index]; 170 171 tr->physical_address = tlb_xlate(gtlbe, eaddr); 172 /* XXX what does "writeable" and "usermode" even mean? */ 173 tr->valid = 1; 174 175 return 0; 176} 177 178struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) 179{ 180 struct kvmppc_vcpu_44x *vcpu_44x; 181 struct kvm_vcpu *vcpu; 182 int err; 183 184 vcpu_44x = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); 185 if (!vcpu_44x) { 186 err = -ENOMEM; 187 goto out; 188 } 189 190 vcpu = &vcpu_44x->vcpu; 191 err = kvm_vcpu_init(vcpu, kvm, id); 192 if (err) 193 goto free_vcpu; 194 195 return vcpu; 196 197free_vcpu: 198 kmem_cache_free(kvm_vcpu_cache, vcpu_44x); 199out: 200 return ERR_PTR(err); 201} 202 203void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) 204{ 205 struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); 206 207 kvm_vcpu_uninit(vcpu); 208 kmem_cache_free(kvm_vcpu_cache, vcpu_44x); 209} 210 211static int kvmppc_44x_init(void) 212{ 213 int r; 214 215 r = kvmppc_booke_init(); 216 if (r) 217 return r; 218 219 return kvm_init(NULL, sizeof(struct kvmppc_vcpu_44x), THIS_MODULE); 220} 221 222static void kvmppc_44x_exit(void) 223{ 224 kvmppc_booke_exit(); 225} 226 227module_init(kvmppc_44x_init); 228module_exit(kvmppc_44x_exit);