diff options
-rw-r--r-- | arch/powerpc/include/asm/kvm_e500.h | 8 | ||||
-rw-r--r-- | arch/powerpc/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/asm-offsets.c | 1 | ||||
-rw-r--r-- | arch/powerpc/kvm/44x_tlb.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kvm/booke.c | 11 | ||||
-rw-r--r-- | arch/powerpc/kvm/booke.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kvm/booke_interrupts.S | 11 | ||||
-rw-r--r-- | arch/powerpc/kvm/e500_emulate.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kvm/e500_tlb.c | 312 | ||||
-rw-r--r-- | arch/powerpc/kvm/e500_tlb.h | 13 |
10 files changed, 334 insertions, 32 deletions
diff --git a/arch/powerpc/include/asm/kvm_e500.h b/arch/powerpc/include/asm/kvm_e500.h index 4a6d77a8b8a0..adbfca9dd100 100644 --- a/arch/powerpc/include/asm/kvm_e500.h +++ b/arch/powerpc/include/asm/kvm_e500.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | 2 | * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved. |
3 | * | 3 | * |
4 | * Author: Yu Liu, <yu.liu@freescale.com> | 4 | * Author: Yu Liu, <yu.liu@freescale.com> |
5 | * | 5 | * |
@@ -37,6 +37,8 @@ struct tlbe_priv { | |||
37 | unsigned int flags; /* E500_TLB_* */ | 37 | unsigned int flags; /* E500_TLB_* */ |
38 | }; | 38 | }; |
39 | 39 | ||
40 | struct vcpu_id_table; | ||
41 | |||
40 | struct kvmppc_vcpu_e500 { | 42 | struct kvmppc_vcpu_e500 { |
41 | /* Unmodified copy of the guest's TLB. */ | 43 | /* Unmodified copy of the guest's TLB. */ |
42 | struct tlbe *gtlb_arch[E500_TLB_NUM]; | 44 | struct tlbe *gtlb_arch[E500_TLB_NUM]; |
@@ -59,6 +61,10 @@ struct kvmppc_vcpu_e500 { | |||
59 | u32 mas5; | 61 | u32 mas5; |
60 | u32 mas6; | 62 | u32 mas6; |
61 | u32 mas7; | 63 | u32 mas7; |
64 | |||
65 | /* vcpu id table */ | ||
66 | struct vcpu_id_table *idt; | ||
67 | |||
62 | u32 l1csr0; | 68 | u32 l1csr0; |
63 | u32 l1csr1; | 69 | u32 l1csr1; |
64 | u32 hid0; | 70 | u32 hid0; |
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index c4ce1054b866..6e05b2d13683 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h | |||
@@ -255,6 +255,7 @@ struct kvm_vcpu_arch { | |||
255 | u32 pvr; | 255 | u32 pvr; |
256 | 256 | ||
257 | u32 shadow_pid; | 257 | u32 shadow_pid; |
258 | u32 shadow_pid1; | ||
258 | u32 pid; | 259 | u32 pid; |
259 | u32 swap_pid; | 260 | u32 swap_pid; |
260 | 261 | ||
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index ecd2b3ad7ff6..faf846131f45 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -402,6 +402,7 @@ int main(void) | |||
402 | DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6)); | 402 | DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6)); |
403 | DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7)); | 403 | DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7)); |
404 | DEFINE(VCPU_SHADOW_PID, offsetof(struct kvm_vcpu, arch.shadow_pid)); | 404 | DEFINE(VCPU_SHADOW_PID, offsetof(struct kvm_vcpu, arch.shadow_pid)); |
405 | DEFINE(VCPU_SHADOW_PID1, offsetof(struct kvm_vcpu, arch.shadow_pid1)); | ||
405 | DEFINE(VCPU_SHARED, offsetof(struct kvm_vcpu, arch.shared)); | 406 | DEFINE(VCPU_SHARED, offsetof(struct kvm_vcpu, arch.shared)); |
406 | DEFINE(VCPU_SHARED_MSR, offsetof(struct kvm_vcpu_arch_shared, msr)); | 407 | DEFINE(VCPU_SHARED_MSR, offsetof(struct kvm_vcpu_arch_shared, msr)); |
407 | DEFINE(VCPU_SHADOW_MSR, offsetof(struct kvm_vcpu, arch.shadow_msr)); | 408 | DEFINE(VCPU_SHADOW_MSR, offsetof(struct kvm_vcpu, arch.shadow_msr)); |
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c index 5f3cff83e089..33aa715dab28 100644 --- a/arch/powerpc/kvm/44x_tlb.c +++ b/arch/powerpc/kvm/44x_tlb.c | |||
@@ -387,8 +387,10 @@ static void kvmppc_44x_invalidate(struct kvm_vcpu *vcpu, | |||
387 | } | 387 | } |
388 | } | 388 | } |
389 | 389 | ||
390 | void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode) | 390 | void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr) |
391 | { | 391 | { |
392 | int usermode = vcpu->arch.shared->msr & MSR_PR; | ||
393 | |||
392 | vcpu->arch.shadow_pid = !usermode; | 394 | vcpu->arch.shadow_pid = !usermode; |
393 | } | 395 | } |
394 | 396 | ||
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 4538956daecf..9f2e4a5e1c4d 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c | |||
@@ -113,15 +113,18 @@ static void kvmppc_vcpu_sync_spe(struct kvm_vcpu *vcpu) | |||
113 | } | 113 | } |
114 | #endif | 114 | #endif |
115 | 115 | ||
116 | /* Helper function for "full" MSR writes. No need to call this if only EE is | 116 | /* |
117 | * changing. */ | 117 | * Helper function for "full" MSR writes. No need to call this if only |
118 | * EE/CE/ME/DE/RI are changing. | ||
119 | */ | ||
118 | void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr) | 120 | void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr) |
119 | { | 121 | { |
120 | if ((new_msr & MSR_PR) != (vcpu->arch.shared->msr & MSR_PR)) | 122 | u32 old_msr = vcpu->arch.shared->msr; |
121 | kvmppc_mmu_priv_switch(vcpu, new_msr & MSR_PR); | ||
122 | 123 | ||
123 | vcpu->arch.shared->msr = new_msr; | 124 | vcpu->arch.shared->msr = new_msr; |
124 | 125 | ||
126 | kvmppc_mmu_msr_notify(vcpu, old_msr); | ||
127 | |||
125 | if (vcpu->arch.shared->msr & MSR_WE) { | 128 | if (vcpu->arch.shared->msr & MSR_WE) { |
126 | kvm_vcpu_block(vcpu); | 129 | kvm_vcpu_block(vcpu); |
127 | kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS); | 130 | kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS); |
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h index 0fa1732ddcb7..8e1fe33d64e5 100644 --- a/arch/powerpc/kvm/booke.h +++ b/arch/powerpc/kvm/booke.h | |||
@@ -53,6 +53,7 @@ | |||
53 | extern unsigned long kvmppc_booke_handlers; | 53 | extern unsigned long kvmppc_booke_handlers; |
54 | 54 | ||
55 | void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr); | 55 | void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr); |
56 | void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr); | ||
56 | 57 | ||
57 | int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | 58 | int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, |
58 | unsigned int inst, int *advance); | 59 | unsigned int inst, int *advance); |
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S index 8cb3dfe29f75..42f2fb1f66e9 100644 --- a/arch/powerpc/kvm/booke_interrupts.S +++ b/arch/powerpc/kvm/booke_interrupts.S | |||
@@ -191,6 +191,12 @@ _GLOBAL(kvmppc_resume_host) | |||
191 | lwz r3, VCPU_HOST_PID(r4) | 191 | lwz r3, VCPU_HOST_PID(r4) |
192 | mtspr SPRN_PID, r3 | 192 | mtspr SPRN_PID, r3 |
193 | 193 | ||
194 | #ifdef CONFIG_FSL_BOOKE | ||
195 | /* we cheat and know that Linux doesn't use PID1 which is always 0 */ | ||
196 | lis r3, 0 | ||
197 | mtspr SPRN_PID1, r3 | ||
198 | #endif | ||
199 | |||
194 | /* Restore host IVPR before re-enabling interrupts. We cheat and know | 200 | /* Restore host IVPR before re-enabling interrupts. We cheat and know |
195 | * that Linux IVPR is always 0xc0000000. */ | 201 | * that Linux IVPR is always 0xc0000000. */ |
196 | lis r3, 0xc000 | 202 | lis r3, 0xc000 |
@@ -365,6 +371,11 @@ lightweight_exit: | |||
365 | lwz r3, VCPU_SHADOW_PID(r4) | 371 | lwz r3, VCPU_SHADOW_PID(r4) |
366 | mtspr SPRN_PID, r3 | 372 | mtspr SPRN_PID, r3 |
367 | 373 | ||
374 | #ifdef CONFIG_FSL_BOOKE | ||
375 | lwz r3, VCPU_SHADOW_PID1(r4) | ||
376 | mtspr SPRN_PID1, r3 | ||
377 | #endif | ||
378 | |||
368 | #ifdef CONFIG_44x | 379 | #ifdef CONFIG_44x |
369 | iccci 0, 0 /* XXX hack */ | 380 | iccci 0, 0 /* XXX hack */ |
370 | #endif | 381 | #endif |
diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c index 69cd665a0caf..d48ae396f41e 100644 --- a/arch/powerpc/kvm/e500_emulate.c +++ b/arch/powerpc/kvm/e500_emulate.c | |||
@@ -81,8 +81,12 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | |||
81 | kvmppc_set_pid(vcpu, spr_val); | 81 | kvmppc_set_pid(vcpu, spr_val); |
82 | break; | 82 | break; |
83 | case SPRN_PID1: | 83 | case SPRN_PID1: |
84 | if (spr_val != 0) | ||
85 | return EMULATE_FAIL; | ||
84 | vcpu_e500->pid[1] = spr_val; break; | 86 | vcpu_e500->pid[1] = spr_val; break; |
85 | case SPRN_PID2: | 87 | case SPRN_PID2: |
88 | if (spr_val != 0) | ||
89 | return EMULATE_FAIL; | ||
86 | vcpu_e500->pid[2] = spr_val; break; | 90 | vcpu_e500->pid[2] = spr_val; break; |
87 | case SPRN_MAS0: | 91 | case SPRN_MAS0: |
88 | vcpu_e500->mas0 = spr_val; break; | 92 | vcpu_e500->mas0 = spr_val; break; |
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c index 9d1e28d443c4..ea394571bbb6 100644 --- a/arch/powerpc/kvm/e500_tlb.c +++ b/arch/powerpc/kvm/e500_tlb.c | |||
@@ -28,8 +28,196 @@ | |||
28 | 28 | ||
29 | #define to_htlb1_esel(esel) (tlb1_entry_num - (esel) - 1) | 29 | #define to_htlb1_esel(esel) (tlb1_entry_num - (esel) - 1) |
30 | 30 | ||
31 | struct id { | ||
32 | unsigned long val; | ||
33 | struct id **pentry; | ||
34 | }; | ||
35 | |||
36 | #define NUM_TIDS 256 | ||
37 | |||
38 | /* | ||
39 | * This table provide mappings from: | ||
40 | * (guestAS,guestTID,guestPR) --> ID of physical cpu | ||
41 | * guestAS [0..1] | ||
42 | * guestTID [0..255] | ||
43 | * guestPR [0..1] | ||
44 | * ID [1..255] | ||
45 | * Each vcpu keeps one vcpu_id_table. | ||
46 | */ | ||
47 | struct vcpu_id_table { | ||
48 | struct id id[2][NUM_TIDS][2]; | ||
49 | }; | ||
50 | |||
51 | /* | ||
52 | * This table provide reversed mappings of vcpu_id_table: | ||
53 | * ID --> address of vcpu_id_table item. | ||
54 | * Each physical core has one pcpu_id_table. | ||
55 | */ | ||
56 | struct pcpu_id_table { | ||
57 | struct id *entry[NUM_TIDS]; | ||
58 | }; | ||
59 | |||
60 | static DEFINE_PER_CPU(struct pcpu_id_table, pcpu_sids); | ||
61 | |||
62 | /* This variable keeps last used shadow ID on local core. | ||
63 | * The valid range of shadow ID is [1..255] */ | ||
64 | static DEFINE_PER_CPU(unsigned long, pcpu_last_used_sid); | ||
65 | |||
31 | static unsigned int tlb1_entry_num; | 66 | static unsigned int tlb1_entry_num; |
32 | 67 | ||
68 | /* | ||
69 | * Allocate a free shadow id and setup a valid sid mapping in given entry. | ||
70 | * A mapping is only valid when vcpu_id_table and pcpu_id_table are match. | ||
71 | * | ||
72 | * The caller must have preemption disabled, and keep it that way until | ||
73 | * it has finished with the returned shadow id (either written into the | ||
74 | * TLB or arch.shadow_pid, or discarded). | ||
75 | */ | ||
76 | static inline int local_sid_setup_one(struct id *entry) | ||
77 | { | ||
78 | unsigned long sid; | ||
79 | int ret = -1; | ||
80 | |||
81 | sid = ++(__get_cpu_var(pcpu_last_used_sid)); | ||
82 | if (sid < NUM_TIDS) { | ||
83 | __get_cpu_var(pcpu_sids).entry[sid] = entry; | ||
84 | entry->val = sid; | ||
85 | entry->pentry = &__get_cpu_var(pcpu_sids).entry[sid]; | ||
86 | ret = sid; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * If sid == NUM_TIDS, we've run out of sids. We return -1, and | ||
91 | * the caller will invalidate everything and start over. | ||
92 | * | ||
93 | * sid > NUM_TIDS indicates a race, which we disable preemption to | ||
94 | * avoid. | ||
95 | */ | ||
96 | WARN_ON(sid > NUM_TIDS); | ||
97 | |||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * Check if given entry contain a valid shadow id mapping. | ||
103 | * An ID mapping is considered valid only if | ||
104 | * both vcpu and pcpu know this mapping. | ||
105 | * | ||
106 | * The caller must have preemption disabled, and keep it that way until | ||
107 | * it has finished with the returned shadow id (either written into the | ||
108 | * TLB or arch.shadow_pid, or discarded). | ||
109 | */ | ||
110 | static inline int local_sid_lookup(struct id *entry) | ||
111 | { | ||
112 | if (entry && entry->val != 0 && | ||
113 | __get_cpu_var(pcpu_sids).entry[entry->val] == entry && | ||
114 | entry->pentry == &__get_cpu_var(pcpu_sids).entry[entry->val]) | ||
115 | return entry->val; | ||
116 | return -1; | ||
117 | } | ||
118 | |||
119 | /* Invalidate all id mappings on local core */ | ||
120 | static inline void local_sid_destroy_all(void) | ||
121 | { | ||
122 | preempt_disable(); | ||
123 | __get_cpu_var(pcpu_last_used_sid) = 0; | ||
124 | memset(&__get_cpu_var(pcpu_sids), 0, sizeof(__get_cpu_var(pcpu_sids))); | ||
125 | preempt_enable(); | ||
126 | } | ||
127 | |||
128 | static void *kvmppc_e500_id_table_alloc(struct kvmppc_vcpu_e500 *vcpu_e500) | ||
129 | { | ||
130 | vcpu_e500->idt = kzalloc(sizeof(struct vcpu_id_table), GFP_KERNEL); | ||
131 | return vcpu_e500->idt; | ||
132 | } | ||
133 | |||
134 | static void kvmppc_e500_id_table_free(struct kvmppc_vcpu_e500 *vcpu_e500) | ||
135 | { | ||
136 | kfree(vcpu_e500->idt); | ||
137 | } | ||
138 | |||
139 | /* Invalidate all mappings on vcpu */ | ||
140 | static void kvmppc_e500_id_table_reset_all(struct kvmppc_vcpu_e500 *vcpu_e500) | ||
141 | { | ||
142 | memset(vcpu_e500->idt, 0, sizeof(struct vcpu_id_table)); | ||
143 | |||
144 | /* Update shadow pid when mappings are changed */ | ||
145 | kvmppc_e500_recalc_shadow_pid(vcpu_e500); | ||
146 | } | ||
147 | |||
148 | /* Invalidate one ID mapping on vcpu */ | ||
149 | static inline void kvmppc_e500_id_table_reset_one( | ||
150 | struct kvmppc_vcpu_e500 *vcpu_e500, | ||
151 | int as, int pid, int pr) | ||
152 | { | ||
153 | struct vcpu_id_table *idt = vcpu_e500->idt; | ||
154 | |||
155 | BUG_ON(as >= 2); | ||
156 | BUG_ON(pid >= NUM_TIDS); | ||
157 | BUG_ON(pr >= 2); | ||
158 | |||
159 | idt->id[as][pid][pr].val = 0; | ||
160 | idt->id[as][pid][pr].pentry = NULL; | ||
161 | |||
162 | /* Update shadow pid when mappings are changed */ | ||
163 | kvmppc_e500_recalc_shadow_pid(vcpu_e500); | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * Map guest (vcpu,AS,ID,PR) to physical core shadow id. | ||
168 | * This function first lookup if a valid mapping exists, | ||
169 | * if not, then creates a new one. | ||
170 | * | ||
171 | * The caller must have preemption disabled, and keep it that way until | ||
172 | * it has finished with the returned shadow id (either written into the | ||
173 | * TLB or arch.shadow_pid, or discarded). | ||
174 | */ | ||
175 | static unsigned int kvmppc_e500_get_sid(struct kvmppc_vcpu_e500 *vcpu_e500, | ||
176 | unsigned int as, unsigned int gid, | ||
177 | unsigned int pr, int avoid_recursion) | ||
178 | { | ||
179 | struct vcpu_id_table *idt = vcpu_e500->idt; | ||
180 | int sid; | ||
181 | |||
182 | BUG_ON(as >= 2); | ||
183 | BUG_ON(gid >= NUM_TIDS); | ||
184 | BUG_ON(pr >= 2); | ||
185 | |||
186 | sid = local_sid_lookup(&idt->id[as][gid][pr]); | ||
187 | |||
188 | while (sid <= 0) { | ||
189 | /* No mapping yet */ | ||
190 | sid = local_sid_setup_one(&idt->id[as][gid][pr]); | ||
191 | if (sid <= 0) { | ||
192 | _tlbil_all(); | ||
193 | local_sid_destroy_all(); | ||
194 | } | ||
195 | |||
196 | /* Update shadow pid when mappings are changed */ | ||
197 | if (!avoid_recursion) | ||
198 | kvmppc_e500_recalc_shadow_pid(vcpu_e500); | ||
199 | } | ||
200 | |||
201 | return sid; | ||
202 | } | ||
203 | |||
204 | /* Map guest pid to shadow. | ||
205 | * We use PID to keep shadow of current guest non-zero PID, | ||
206 | * and use PID1 to keep shadow of guest zero PID. | ||
207 | * So that guest tlbe with TID=0 can be accessed at any time */ | ||
208 | void kvmppc_e500_recalc_shadow_pid(struct kvmppc_vcpu_e500 *vcpu_e500) | ||
209 | { | ||
210 | preempt_disable(); | ||
211 | vcpu_e500->vcpu.arch.shadow_pid = kvmppc_e500_get_sid(vcpu_e500, | ||
212 | get_cur_as(&vcpu_e500->vcpu), | ||
213 | get_cur_pid(&vcpu_e500->vcpu), | ||
214 | get_cur_pr(&vcpu_e500->vcpu), 1); | ||
215 | vcpu_e500->vcpu.arch.shadow_pid1 = kvmppc_e500_get_sid(vcpu_e500, | ||
216 | get_cur_as(&vcpu_e500->vcpu), 0, | ||
217 | get_cur_pr(&vcpu_e500->vcpu), 1); | ||
218 | preempt_enable(); | ||
219 | } | ||
220 | |||
33 | void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu) | 221 | void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu) |
34 | { | 222 | { |
35 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | 223 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); |
@@ -134,14 +322,19 @@ static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
134 | 322 | ||
135 | void kvmppc_map_magic(struct kvm_vcpu *vcpu) | 323 | void kvmppc_map_magic(struct kvm_vcpu *vcpu) |
136 | { | 324 | { |
325 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
137 | struct tlbe magic; | 326 | struct tlbe magic; |
138 | ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK; | 327 | ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK; |
328 | unsigned int stid; | ||
139 | pfn_t pfn; | 329 | pfn_t pfn; |
140 | 330 | ||
141 | pfn = (pfn_t)virt_to_phys((void *)shared_page) >> PAGE_SHIFT; | 331 | pfn = (pfn_t)virt_to_phys((void *)shared_page) >> PAGE_SHIFT; |
142 | get_page(pfn_to_page(pfn)); | 332 | get_page(pfn_to_page(pfn)); |
143 | 333 | ||
144 | magic.mas1 = MAS1_VALID | MAS1_TS | | 334 | preempt_disable(); |
335 | stid = kvmppc_e500_get_sid(vcpu_e500, 0, 0, 0, 0); | ||
336 | |||
337 | magic.mas1 = MAS1_VALID | MAS1_TS | MAS1_TID(stid) | | ||
145 | MAS1_TSIZE(BOOK3E_PAGESZ_4K); | 338 | MAS1_TSIZE(BOOK3E_PAGESZ_4K); |
146 | magic.mas2 = vcpu->arch.magic_page_ea | MAS2_M; | 339 | magic.mas2 = vcpu->arch.magic_page_ea | MAS2_M; |
147 | magic.mas3 = (pfn << PAGE_SHIFT) | | 340 | magic.mas3 = (pfn << PAGE_SHIFT) | |
@@ -149,15 +342,76 @@ void kvmppc_map_magic(struct kvm_vcpu *vcpu) | |||
149 | magic.mas7 = pfn >> (32 - PAGE_SHIFT); | 342 | magic.mas7 = pfn >> (32 - PAGE_SHIFT); |
150 | 343 | ||
151 | __write_host_tlbe(&magic, MAS0_TLBSEL(1) | MAS0_ESEL(tlbcam_index)); | 344 | __write_host_tlbe(&magic, MAS0_TLBSEL(1) | MAS0_ESEL(tlbcam_index)); |
345 | preempt_enable(); | ||
152 | } | 346 | } |
153 | 347 | ||
154 | void kvmppc_e500_tlb_load(struct kvm_vcpu *vcpu, int cpu) | 348 | void kvmppc_e500_tlb_load(struct kvm_vcpu *vcpu, int cpu) |
155 | { | 349 | { |
350 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | ||
351 | |||
352 | /* Shadow PID may be expired on local core */ | ||
353 | kvmppc_e500_recalc_shadow_pid(vcpu_e500); | ||
156 | } | 354 | } |
157 | 355 | ||
158 | void kvmppc_e500_tlb_put(struct kvm_vcpu *vcpu) | 356 | void kvmppc_e500_tlb_put(struct kvm_vcpu *vcpu) |
159 | { | 357 | { |
160 | _tlbil_all(); | 358 | } |
359 | |||
360 | static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, | ||
361 | int tlbsel, int esel) | ||
362 | { | ||
363 | struct tlbe *gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; | ||
364 | struct vcpu_id_table *idt = vcpu_e500->idt; | ||
365 | unsigned int pr, tid, ts, pid; | ||
366 | u32 val, eaddr; | ||
367 | unsigned long flags; | ||
368 | |||
369 | ts = get_tlb_ts(gtlbe); | ||
370 | tid = get_tlb_tid(gtlbe); | ||
371 | |||
372 | preempt_disable(); | ||
373 | |||
374 | /* One guest ID may be mapped to two shadow IDs */ | ||
375 | for (pr = 0; pr < 2; pr++) { | ||
376 | /* | ||
377 | * The shadow PID can have a valid mapping on at most one | ||
378 | * host CPU. In the common case, it will be valid on this | ||
379 | * CPU, in which case (for TLB0) we do a local invalidation | ||
380 | * of the specific address. | ||
381 | * | ||
382 | * If the shadow PID is not valid on the current host CPU, or | ||
383 | * if we're invalidating a TLB1 entry, we invalidate the | ||
384 | * entire shadow PID. | ||
385 | */ | ||
386 | if (tlbsel == 1 || | ||
387 | (pid = local_sid_lookup(&idt->id[ts][tid][pr])) <= 0) { | ||
388 | kvmppc_e500_id_table_reset_one(vcpu_e500, ts, tid, pr); | ||
389 | continue; | ||
390 | } | ||
391 | |||
392 | /* | ||
393 | * The guest is invalidating a TLB0 entry which is in a PID | ||
394 | * that has a valid shadow mapping on this host CPU. We | ||
395 | * search host TLB0 to invalidate it's shadow TLB entry, | ||
396 | * similar to __tlbil_va except that we need to look in AS1. | ||
397 | */ | ||
398 | val = (pid << MAS6_SPID_SHIFT) | MAS6_SAS; | ||
399 | eaddr = get_tlb_eaddr(gtlbe); | ||
400 | |||
401 | local_irq_save(flags); | ||
402 | |||
403 | mtspr(SPRN_MAS6, val); | ||
404 | asm volatile("tlbsx 0, %[eaddr]" : : [eaddr] "r" (eaddr)); | ||
405 | val = mfspr(SPRN_MAS1); | ||
406 | if (val & MAS1_VALID) { | ||
407 | mtspr(SPRN_MAS1, val & ~MAS1_VALID); | ||
408 | asm volatile("tlbwe"); | ||
409 | } | ||
410 | |||
411 | local_irq_restore(flags); | ||
412 | } | ||
413 | |||
414 | preempt_enable(); | ||
161 | } | 415 | } |
162 | 416 | ||
163 | /* Search the guest TLB for a matching entry. */ | 417 | /* Search the guest TLB for a matching entry. */ |
@@ -216,12 +470,6 @@ static inline void kvmppc_e500_priv_release(struct tlbe_priv *priv) | |||
216 | } | 470 | } |
217 | } | 471 | } |
218 | 472 | ||
219 | static void kvmppc_e500_tlb1_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500, | ||
220 | int esel) | ||
221 | { | ||
222 | mtspr(SPRN_MMUCSR0, MMUCSR0_TLB1FI); | ||
223 | } | ||
224 | |||
225 | static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, | 473 | static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu, |
226 | unsigned int eaddr, int as) | 474 | unsigned int eaddr, int as) |
227 | { | 475 | { |
@@ -255,10 +503,15 @@ static inline void kvmppc_e500_setup_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
255 | u64 gvaddr, struct tlbe *stlbe) | 503 | u64 gvaddr, struct tlbe *stlbe) |
256 | { | 504 | { |
257 | pfn_t pfn = priv->pfn; | 505 | pfn_t pfn = priv->pfn; |
506 | unsigned int stid; | ||
507 | |||
508 | stid = kvmppc_e500_get_sid(vcpu_e500, get_tlb_ts(gtlbe), | ||
509 | get_tlb_tid(gtlbe), | ||
510 | get_cur_pr(&vcpu_e500->vcpu), 0); | ||
258 | 511 | ||
259 | /* Force TS=1 IPROT=0 for all guest mappings. */ | 512 | /* Force TS=1 IPROT=0 for all guest mappings. */ |
260 | stlbe->mas1 = MAS1_TSIZE(tsize) | 513 | stlbe->mas1 = MAS1_TSIZE(tsize) |
261 | | MAS1_TID(get_tlb_tid(gtlbe)) | MAS1_TS | MAS1_VALID; | 514 | | MAS1_TID(stid) | MAS1_TS | MAS1_VALID; |
262 | stlbe->mas2 = (gvaddr & MAS2_EPN) | 515 | stlbe->mas2 = (gvaddr & MAS2_EPN) |
263 | | e500_shadow_mas2_attrib(gtlbe->mas2, | 516 | | e500_shadow_mas2_attrib(gtlbe->mas2, |
264 | vcpu_e500->vcpu.arch.shared->msr & MSR_PR); | 517 | vcpu_e500->vcpu.arch.shared->msr & MSR_PR); |
@@ -414,14 +667,12 @@ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
414 | return victim; | 667 | return victim; |
415 | } | 668 | } |
416 | 669 | ||
417 | /* Invalidate all guest kernel mappings when enter usermode, | 670 | void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr) |
418 | * so that when they fault back in they will get the | ||
419 | * proper permission bits. */ | ||
420 | void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode) | ||
421 | { | 671 | { |
422 | if (usermode) { | 672 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); |
423 | _tlbil_all(); | 673 | |
424 | } | 674 | /* Recalc shadow pid since MSR changes */ |
675 | kvmppc_e500_recalc_shadow_pid(vcpu_e500); | ||
425 | } | 676 | } |
426 | 677 | ||
427 | static inline int kvmppc_e500_gtlbe_invalidate( | 678 | static inline int kvmppc_e500_gtlbe_invalidate( |
@@ -449,7 +700,8 @@ int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *vcpu_e500, ulong value) | |||
449 | for (esel = 0; esel < vcpu_e500->gtlb_size[1]; esel++) | 700 | for (esel = 0; esel < vcpu_e500->gtlb_size[1]; esel++) |
450 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, 1, esel); | 701 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, 1, esel); |
451 | 702 | ||
452 | _tlbil_all(); | 703 | /* Invalidate all vcpu id mappings */ |
704 | kvmppc_e500_id_table_reset_all(vcpu_e500); | ||
453 | 705 | ||
454 | return EMULATE_DONE; | 706 | return EMULATE_DONE; |
455 | } | 707 | } |
@@ -480,7 +732,8 @@ int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb) | |||
480 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel); | 732 | kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel); |
481 | } | 733 | } |
482 | 734 | ||
483 | _tlbil_all(); | 735 | /* Invalidate all vcpu id mappings */ |
736 | kvmppc_e500_id_table_reset_all(vcpu_e500); | ||
484 | 737 | ||
485 | return EMULATE_DONE; | 738 | return EMULATE_DONE; |
486 | } | 739 | } |
@@ -564,8 +817,8 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) | |||
564 | 817 | ||
565 | gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; | 818 | gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; |
566 | 819 | ||
567 | if (get_tlb_v(gtlbe) && tlbsel == 1) | 820 | if (get_tlb_v(gtlbe)) |
568 | kvmppc_e500_tlb1_invalidate(vcpu_e500, esel); | 821 | kvmppc_e500_stlbe_invalidate(vcpu_e500, tlbsel, esel); |
569 | 822 | ||
570 | gtlbe->mas1 = vcpu_e500->mas1; | 823 | gtlbe->mas1 = vcpu_e500->mas1; |
571 | gtlbe->mas2 = vcpu_e500->mas2; | 824 | gtlbe->mas2 = vcpu_e500->mas2; |
@@ -582,6 +835,7 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) | |||
582 | u64 eaddr; | 835 | u64 eaddr; |
583 | u64 raddr; | 836 | u64 raddr; |
584 | 837 | ||
838 | preempt_disable(); | ||
585 | switch (tlbsel) { | 839 | switch (tlbsel) { |
586 | case 0: | 840 | case 0: |
587 | /* TLB0 */ | 841 | /* TLB0 */ |
@@ -611,6 +865,7 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) | |||
611 | BUG(); | 865 | BUG(); |
612 | } | 866 | } |
613 | write_host_tlbe(vcpu_e500, stlbsel, sesel, &stlbe); | 867 | write_host_tlbe(vcpu_e500, stlbsel, sesel, &stlbe); |
868 | preempt_enable(); | ||
614 | } | 869 | } |
615 | 870 | ||
616 | kvmppc_set_exit_type(vcpu, EMULATED_TLBWE_EXITS); | 871 | kvmppc_set_exit_type(vcpu, EMULATED_TLBWE_EXITS); |
@@ -672,6 +927,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, | |||
672 | 927 | ||
673 | gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; | 928 | gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel]; |
674 | 929 | ||
930 | preempt_disable(); | ||
675 | switch (tlbsel) { | 931 | switch (tlbsel) { |
676 | case 0: | 932 | case 0: |
677 | stlbsel = 0; | 933 | stlbsel = 0; |
@@ -697,6 +953,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, | |||
697 | } | 953 | } |
698 | 954 | ||
699 | write_host_tlbe(vcpu_e500, stlbsel, sesel, &stlbe); | 955 | write_host_tlbe(vcpu_e500, stlbsel, sesel, &stlbe); |
956 | preempt_enable(); | ||
700 | } | 957 | } |
701 | 958 | ||
702 | int kvmppc_e500_tlb_search(struct kvm_vcpu *vcpu, | 959 | int kvmppc_e500_tlb_search(struct kvm_vcpu *vcpu, |
@@ -718,8 +975,10 @@ void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid) | |||
718 | { | 975 | { |
719 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | 976 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); |
720 | 977 | ||
721 | vcpu_e500->pid[0] = vcpu->arch.shadow_pid = | 978 | if (vcpu->arch.pid != pid) { |
722 | vcpu->arch.pid = pid; | 979 | vcpu_e500->pid[0] = vcpu->arch.pid = pid; |
980 | kvmppc_e500_recalc_shadow_pid(vcpu_e500); | ||
981 | } | ||
723 | } | 982 | } |
724 | 983 | ||
725 | void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *vcpu_e500) | 984 | void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *vcpu_e500) |
@@ -767,6 +1026,9 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500) | |||
767 | if (vcpu_e500->gtlb_priv[1] == NULL) | 1026 | if (vcpu_e500->gtlb_priv[1] == NULL) |
768 | goto err_out_priv0; | 1027 | goto err_out_priv0; |
769 | 1028 | ||
1029 | if (kvmppc_e500_id_table_alloc(vcpu_e500) == NULL) | ||
1030 | goto err_out_priv1; | ||
1031 | |||
770 | /* Init TLB configuration register */ | 1032 | /* Init TLB configuration register */ |
771 | vcpu_e500->tlb0cfg = mfspr(SPRN_TLB0CFG) & ~0xfffUL; | 1033 | vcpu_e500->tlb0cfg = mfspr(SPRN_TLB0CFG) & ~0xfffUL; |
772 | vcpu_e500->tlb0cfg |= vcpu_e500->gtlb_size[0]; | 1034 | vcpu_e500->tlb0cfg |= vcpu_e500->gtlb_size[0]; |
@@ -775,6 +1037,8 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500) | |||
775 | 1037 | ||
776 | return 0; | 1038 | return 0; |
777 | 1039 | ||
1040 | err_out_priv1: | ||
1041 | kfree(vcpu_e500->gtlb_priv[1]); | ||
778 | err_out_priv0: | 1042 | err_out_priv0: |
779 | kfree(vcpu_e500->gtlb_priv[0]); | 1043 | kfree(vcpu_e500->gtlb_priv[0]); |
780 | err_out_guest1: | 1044 | err_out_guest1: |
@@ -797,9 +1061,7 @@ void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500) | |||
797 | kvmppc_e500_priv_release(priv); | 1061 | kvmppc_e500_priv_release(priv); |
798 | } | 1062 | } |
799 | 1063 | ||
800 | /* discard all guest mapping */ | 1064 | kvmppc_e500_id_table_free(vcpu_e500); |
801 | _tlbil_all(); | ||
802 | |||
803 | kfree(vcpu_e500->gtlb_arch[1]); | 1065 | kfree(vcpu_e500->gtlb_arch[1]); |
804 | kfree(vcpu_e500->gtlb_arch[0]); | 1066 | kfree(vcpu_e500->gtlb_arch[0]); |
805 | } | 1067 | } |
diff --git a/arch/powerpc/kvm/e500_tlb.h b/arch/powerpc/kvm/e500_tlb.h index 458946b4775d..59b88e99a235 100644 --- a/arch/powerpc/kvm/e500_tlb.h +++ b/arch/powerpc/kvm/e500_tlb.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | 2 | * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved. |
3 | * | 3 | * |
4 | * Author: Yu Liu, yu.liu@freescale.com | 4 | * Author: Yu Liu, yu.liu@freescale.com |
5 | * | 5 | * |
@@ -55,6 +55,7 @@ extern void kvmppc_e500_tlb_load(struct kvm_vcpu *, int); | |||
55 | extern int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *); | 55 | extern int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *); |
56 | extern void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *); | 56 | extern void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *); |
57 | extern void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *); | 57 | extern void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *); |
58 | extern void kvmppc_e500_recalc_shadow_pid(struct kvmppc_vcpu_e500 *); | ||
58 | 59 | ||
59 | /* TLB helper functions */ | 60 | /* TLB helper functions */ |
60 | static inline unsigned int get_tlb_size(const struct tlbe *tlbe) | 61 | static inline unsigned int get_tlb_size(const struct tlbe *tlbe) |
@@ -110,6 +111,16 @@ static inline unsigned int get_cur_pid(struct kvm_vcpu *vcpu) | |||
110 | return vcpu->arch.pid & 0xff; | 111 | return vcpu->arch.pid & 0xff; |
111 | } | 112 | } |
112 | 113 | ||
114 | static inline unsigned int get_cur_as(struct kvm_vcpu *vcpu) | ||
115 | { | ||
116 | return !!(vcpu->arch.shared->msr & (MSR_IS | MSR_DS)); | ||
117 | } | ||
118 | |||
119 | static inline unsigned int get_cur_pr(struct kvm_vcpu *vcpu) | ||
120 | { | ||
121 | return !!(vcpu->arch.shared->msr & MSR_PR); | ||
122 | } | ||
123 | |||
113 | static inline unsigned int get_cur_spid( | 124 | static inline unsigned int get_cur_spid( |
114 | const struct kvmppc_vcpu_e500 *vcpu_e500) | 125 | const struct kvmppc_vcpu_e500 *vcpu_e500) |
115 | { | 126 | { |