~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/kvm/emulate.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  *
  4  * Copyright IBM Corp. 2007
  5  * Copyright 2011 Freescale Semiconductor, Inc.
  6  *
  7  * Authors: Hollis Blanchard <hollisb@us.ibm.com>
  8  */
  9 
 10 #include <linux/jiffies.h>
 11 #include <linux/hrtimer.h>
 12 #include <linux/types.h>
 13 #include <linux/string.h>
 14 #include <linux/kvm_host.h>
 15 #include <linux/clockchips.h>
 16 
 17 #include <asm/reg.h>
 18 #include <asm/time.h>
 19 #include <asm/byteorder.h>
 20 #include <asm/kvm_ppc.h>
 21 #include <asm/disassemble.h>
 22 #include <asm/ppc-opcode.h>
 23 #include "timing.h"
 24 #include "trace.h"
 25 
 26 void kvmppc_emulate_dec(struct kvm_vcpu *vcpu)
 27 {
 28         unsigned long dec_nsec;
 29         unsigned long long dec_time;
 30 
 31         pr_debug("mtDEC: %lx\n", vcpu->arch.dec);
 32         hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
 33 
 34 #ifdef CONFIG_PPC_BOOK3S
 35         /* mtdec lowers the interrupt line when positive. */
 36         kvmppc_core_dequeue_dec(vcpu);
 37 #endif
 38 
 39 #ifdef CONFIG_BOOKE
 40         /* On BOOKE, DEC = 0 is as good as decrementer not enabled */
 41         if (vcpu->arch.dec == 0)
 42                 return;
 43 #endif
 44 
 45         /*
 46          * The decrementer ticks at the same rate as the timebase, so
 47          * that's how we convert the guest DEC value to the number of
 48          * host ticks.
 49          */
 50 
 51         dec_time = vcpu->arch.dec;
 52         /*
 53          * Guest timebase ticks at the same frequency as host timebase.
 54          * So use the host timebase calculations for decrementer emulation.
 55          */
 56         dec_time = tb_to_ns(dec_time);
 57         dec_nsec = do_div(dec_time, NSEC_PER_SEC);
 58         hrtimer_start(&vcpu->arch.dec_timer,
 59                 ktime_set(dec_time, dec_nsec), HRTIMER_MODE_REL);
 60         vcpu->arch.dec_jiffies = get_tb();
 61 }
 62 
 63 u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb)
 64 {
 65         u64 jd = tb - vcpu->arch.dec_jiffies;
 66 
 67 #ifdef CONFIG_BOOKE
 68         if (vcpu->arch.dec < jd)
 69                 return 0;
 70 #endif
 71 
 72         return vcpu->arch.dec - jd;
 73 }
 74 
 75 static int kvmppc_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
 76 {
 77         enum emulation_result emulated = EMULATE_DONE;
 78         ulong spr_val = kvmppc_get_gpr(vcpu, rs);
 79 
 80         switch (sprn) {
 81         case SPRN_SRR0:
 82                 kvmppc_set_srr0(vcpu, spr_val);
 83                 break;
 84         case SPRN_SRR1:
 85                 kvmppc_set_srr1(vcpu, spr_val);
 86                 break;
 87 
 88         /* XXX We need to context-switch the timebase for
 89          * watchdog and FIT. */
 90         case SPRN_TBWL: break;
 91         case SPRN_TBWU: break;
 92 
 93         case SPRN_DEC:
 94                 vcpu->arch.dec = (u32) spr_val;
 95                 kvmppc_emulate_dec(vcpu);
 96                 break;
 97 
 98         case SPRN_SPRG0:
 99                 kvmppc_set_sprg0(vcpu, spr_val);
100                 break;
101         case SPRN_SPRG1:
102                 kvmppc_set_sprg1(vcpu, spr_val);
103                 break;
104         case SPRN_SPRG2:
105                 kvmppc_set_sprg2(vcpu, spr_val);
106                 break;
107         case SPRN_SPRG3:
108                 kvmppc_set_sprg3(vcpu, spr_val);
109                 break;
110 
111         /* PIR can legally be written, but we ignore it */
112         case SPRN_PIR: break;
113 
114         default:
115                 emulated = vcpu->kvm->arch.kvm_ops->emulate_mtspr(vcpu, sprn,
116                                                                   spr_val);
117                 if (emulated == EMULATE_FAIL)
118                         printk(KERN_INFO "mtspr: unknown spr "
119                                 "0x%x\n", sprn);
120                 break;
121         }
122 
123         kvmppc_set_exit_type(vcpu, EMULATED_MTSPR_EXITS);
124 
125         return emulated;
126 }
127 
128 static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
129 {
130         enum emulation_result emulated = EMULATE_DONE;
131         ulong spr_val = 0;
132 
133         switch (sprn) {
134         case SPRN_SRR0:
135                 spr_val = kvmppc_get_srr0(vcpu);
136                 break;
137         case SPRN_SRR1:
138                 spr_val = kvmppc_get_srr1(vcpu);
139                 break;
140         case SPRN_PVR:
141                 spr_val = vcpu->arch.pvr;
142                 break;
143         case SPRN_PIR:
144                 spr_val = vcpu->vcpu_id;
145                 break;
146 
147         /* Note: mftb and TBRL/TBWL are user-accessible, so
148          * the guest can always access the real TB anyways.
149          * In fact, we probably will never see these traps. */
150         case SPRN_TBWL:
151                 spr_val = get_tb() >> 32;
152                 break;
153         case SPRN_TBWU:
154                 spr_val = get_tb();
155                 break;
156 
157         case SPRN_SPRG0:
158                 spr_val = kvmppc_get_sprg0(vcpu);
159                 break;
160         case SPRN_SPRG1:
161                 spr_val = kvmppc_get_sprg1(vcpu);
162                 break;
163         case SPRN_SPRG2:
164                 spr_val = kvmppc_get_sprg2(vcpu);
165                 break;
166         case SPRN_SPRG3:
167                 spr_val = kvmppc_get_sprg3(vcpu);
168                 break;
169         /* Note: SPRG4-7 are user-readable, so we don't get
170          * a trap. */
171 
172         case SPRN_DEC:
173                 spr_val = kvmppc_get_dec(vcpu, get_tb());
174                 break;
175         default:
176                 emulated = vcpu->kvm->arch.kvm_ops->emulate_mfspr(vcpu, sprn,
177                                                                   &spr_val);
178                 if (unlikely(emulated == EMULATE_FAIL)) {
179                         printk(KERN_INFO "mfspr: unknown spr "
180                                 "0x%x\n", sprn);
181                 }
182                 break;
183         }
184 
185         if (emulated == EMULATE_DONE)
186                 kvmppc_set_gpr(vcpu, rt, spr_val);
187         kvmppc_set_exit_type(vcpu, EMULATED_MFSPR_EXITS);
188 
189         return emulated;
190 }
191 
192 /* XXX Should probably auto-generate instruction decoding for a particular core
193  * from opcode tables in the future. */
194 int kvmppc_emulate_instruction(struct kvm_vcpu *vcpu)
195 {
196         u32 inst;
197         ppc_inst_t pinst;
198         int rs, rt, sprn;
199         enum emulation_result emulated;
200         int advance = 1;
201 
202         /* this default type might be overwritten by subcategories */
203         kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS);
204 
205         emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &pinst);
206         inst = ppc_inst_val(pinst);
207         if (emulated != EMULATE_DONE)
208                 return emulated;
209 
210         pr_debug("Emulating opcode %d / %d\n", get_op(inst), get_xop(inst));
211 
212         rs = get_rs(inst);
213         rt = get_rt(inst);
214         sprn = get_sprn(inst);
215 
216         switch (get_op(inst)) {
217         case OP_TRAP:
218 #ifdef CONFIG_PPC_BOOK3S
219         case OP_TRAP_64:
220                 kvmppc_core_queue_program(vcpu, SRR1_PROGTRAP);
221 #else
222                 kvmppc_core_queue_program(vcpu,
223                                           vcpu->arch.shared->esr | ESR_PTR);
224 #endif
225                 advance = 0;
226                 break;
227 
228         case 31:
229                 switch (get_xop(inst)) {
230 
231                 case OP_31_XOP_TRAP:
232 #ifdef CONFIG_64BIT
233                 case OP_31_XOP_TRAP_64:
234 #endif
235 #ifdef CONFIG_PPC_BOOK3S
236                         kvmppc_core_queue_program(vcpu, SRR1_PROGTRAP);
237 #else
238                         kvmppc_core_queue_program(vcpu,
239                                         vcpu->arch.shared->esr | ESR_PTR);
240 #endif
241                         advance = 0;
242                         break;
243 
244                 case OP_31_XOP_MFSPR:
245                         emulated = kvmppc_emulate_mfspr(vcpu, sprn, rt);
246                         if (emulated == EMULATE_AGAIN) {
247                                 emulated = EMULATE_DONE;
248                                 advance = 0;
249                         }
250                         break;
251 
252                 case OP_31_XOP_MTSPR:
253                         emulated = kvmppc_emulate_mtspr(vcpu, sprn, rs);
254                         if (emulated == EMULATE_AGAIN) {
255                                 emulated = EMULATE_DONE;
256                                 advance = 0;
257                         }
258                         break;
259 
260                 case OP_31_XOP_TLBSYNC:
261                         break;
262 
263                 default:
264                         /* Attempt core-specific emulation below. */
265                         emulated = EMULATE_FAIL;
266                 }
267                 break;
268 
269         case 0:
270                 /*
271                  * Instruction with primary opcode 0. Based on PowerISA
272                  * these are illegal instructions.
273                  */
274                 if (inst == KVMPPC_INST_SW_BREAKPOINT) {
275                         vcpu->run->exit_reason = KVM_EXIT_DEBUG;
276                         vcpu->run->debug.arch.status = 0;
277                         vcpu->run->debug.arch.address = kvmppc_get_pc(vcpu);
278                         emulated = EMULATE_EXIT_USER;
279                         advance = 0;
280                 } else
281                         emulated = EMULATE_FAIL;
282 
283                 break;
284 
285         default:
286                 emulated = EMULATE_FAIL;
287         }
288 
289         if (emulated == EMULATE_FAIL) {
290                 emulated = vcpu->kvm->arch.kvm_ops->emulate_op(vcpu, inst,
291                                                                &advance);
292                 if (emulated == EMULATE_AGAIN) {
293                         advance = 0;
294                 } else if (emulated == EMULATE_FAIL) {
295                         advance = 0;
296                         printk(KERN_ERR "Couldn't emulate instruction 0x%08x "
297                                "(op %d xop %d)\n", inst, get_op(inst), get_xop(inst));
298                 }
299         }
300 
301         trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated);
302 
303         /* Advance past emulated instruction. */
304         /*
305          * If this ever handles prefixed instructions, the 4
306          * will need to become ppc_inst_len(pinst) instead.
307          */
308         if (advance)
309                 kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4);
310 
311         return emulated;
312 }
313 EXPORT_SYMBOL_GPL(kvmppc_emulate_instruction);
314 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php