]> Pileus Git - ~andy/linux/blob - arch/mips/kvm/kvm_locore.S
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
[~andy/linux] / arch / mips / kvm / kvm_locore.S
1 /*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License.  See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Main entry point for the guest, exception handling.
7 *
8 * Copyright (C) 2012  MIPS Technologies, Inc.  All rights reserved.
9 * Authors: Sanjay Lal <sanjayl@kymasys.com>
10 */
11
12 #include <asm/asm.h>
13 #include <asm/asmmacro.h>
14 #include <asm/regdef.h>
15 #include <asm/mipsregs.h>
16 #include <asm/stackframe.h>
17 #include <asm/asm-offsets.h>
18
19
20 #define _C_LABEL(x)     x
21 #define MIPSX(name)     mips32_ ## name
22 #define CALLFRAME_SIZ   32
23
24 /*
25  * VECTOR
26  *  exception vector entrypoint
27  */
28 #define VECTOR(x, regmask)      \
29     .ent    _C_LABEL(x),0;      \
30     EXPORT(x);
31
32 #define VECTOR_END(x)      \
33     EXPORT(x);
34
35 /* Overload, Danger Will Robinson!! */
36 #define PT_HOST_ASID        PT_BVADDR
37 #define PT_HOST_USERLOCAL   PT_EPC
38
39 #define CP0_DDATA_LO        $28,3
40 #define CP0_EBASE           $15,1
41
42 #define CP0_INTCTL          $12,1
43 #define CP0_SRSCTL          $12,2
44 #define CP0_SRSMAP          $12,3
45 #define CP0_HWRENA          $7,0
46
47 /* Resume Flags */
48 #define RESUME_FLAG_HOST        (1<<1)  /* Resume host? */
49
50 #define RESUME_GUEST            0
51 #define RESUME_HOST             RESUME_FLAG_HOST
52
53 /*
54  * __kvm_mips_vcpu_run: entry point to the guest
55  * a0: run
56  * a1: vcpu
57  */
58
59 FEXPORT(__kvm_mips_vcpu_run)
60     .set    push
61     .set    noreorder
62     .set    noat
63
64     /* k0/k1 not being used in host kernel context */
65         addiu           k1,sp, -PT_SIZE
66     LONG_S          $0, PT_R0(k1)
67     LONG_S      $1, PT_R1(k1)
68     LONG_S      $2, PT_R2(k1)
69     LONG_S      $3, PT_R3(k1)
70
71     LONG_S      $4, PT_R4(k1)
72     LONG_S      $5, PT_R5(k1)
73     LONG_S      $6, PT_R6(k1)
74     LONG_S      $7, PT_R7(k1)
75
76     LONG_S      $8,  PT_R8(k1)
77     LONG_S      $9,  PT_R9(k1)
78     LONG_S      $10, PT_R10(k1)
79     LONG_S      $11, PT_R11(k1)
80     LONG_S      $12, PT_R12(k1)
81     LONG_S      $13, PT_R13(k1)
82     LONG_S      $14, PT_R14(k1)
83     LONG_S      $15, PT_R15(k1)
84     LONG_S      $16, PT_R16(k1)
85     LONG_S      $17, PT_R17(k1)
86
87     LONG_S      $18, PT_R18(k1)
88     LONG_S      $19, PT_R19(k1)
89     LONG_S      $20, PT_R20(k1)
90     LONG_S      $21, PT_R21(k1)
91     LONG_S      $22, PT_R22(k1)
92     LONG_S      $23, PT_R23(k1)
93     LONG_S      $24, PT_R24(k1)
94     LONG_S      $25, PT_R25(k1)
95
96         /* XXXKYMA k0/k1 not saved, not being used if we got here through an ioctl() */
97
98     LONG_S      $28, PT_R28(k1)
99     LONG_S      $29, PT_R29(k1)
100     LONG_S      $30, PT_R30(k1)
101     LONG_S      $31, PT_R31(k1)
102
103     /* Save hi/lo */
104         mflo            v0
105         LONG_S          v0, PT_LO(k1)
106         mfhi            v1
107         LONG_S          v1, PT_HI(k1)
108
109         /* Save host status */
110         mfc0            v0, CP0_STATUS
111         LONG_S          v0, PT_STATUS(k1)
112
113         /* Save host ASID, shove it into the BVADDR location */
114         mfc0            v1,CP0_ENTRYHI
115         andi            v1, 0xff
116         LONG_S          v1, PT_HOST_ASID(k1)
117
118     /* Save DDATA_LO, will be used to store pointer to vcpu */
119     mfc0        v1, CP0_DDATA_LO
120     LONG_S      v1, PT_HOST_USERLOCAL(k1)
121
122     /* DDATA_LO has pointer to vcpu */
123     mtc0        a1,CP0_DDATA_LO
124
125     /* Offset into vcpu->arch */
126         addiu           k1, a1, VCPU_HOST_ARCH
127
128     /* Save the host stack to VCPU, used for exception processing when we exit from the Guest */
129     LONG_S      sp, VCPU_HOST_STACK(k1)
130
131     /* Save the kernel gp as well */
132     LONG_S      gp, VCPU_HOST_GP(k1)
133
134         /* Setup status register for running the guest in UM, interrupts are disabled */
135         li                      k0,(ST0_EXL | KSU_USER| ST0_BEV)
136         mtc0            k0,CP0_STATUS
137     ehb
138
139     /* load up the new EBASE */
140     LONG_L      k0, VCPU_GUEST_EBASE(k1)
141     mtc0        k0,CP0_EBASE
142
143     /* Now that the new EBASE has been loaded, unset BEV, set interrupt mask as it was
144      * but make sure that timer interrupts are enabled
145      */
146     li          k0,(ST0_EXL | KSU_USER | ST0_IE)
147     andi        v0, v0, ST0_IM
148     or          k0, k0, v0
149     mtc0        k0,CP0_STATUS
150     ehb
151
152
153         /* Set Guest EPC */
154         LONG_L          t0, VCPU_PC(k1)
155         mtc0            t0, CP0_EPC
156
157 FEXPORT(__kvm_mips_load_asid)
158     /* Set the ASID for the Guest Kernel */
159     sll         t0, t0, 1                       /* with kseg0 @ 0x40000000, kernel */
160                                                 /* addresses shift to 0x80000000 */
161     bltz        t0, 1f                          /* If kernel */
162         addiu       t1, k1, VCPU_GUEST_KERNEL_ASID  /* (BD)  */
163     addiu       t1, k1, VCPU_GUEST_USER_ASID    /* else user */
164 1:
165     /* t1: contains the base of the ASID array, need to get the cpu id  */
166     LONG_L      t2, TI_CPU($28)             /* smp_processor_id */
167     sll         t2, t2, 2                   /* x4 */
168     addu        t3, t1, t2
169     LONG_L      k0, (t3)
170     andi        k0, k0, 0xff
171         mtc0            k0,CP0_ENTRYHI
172     ehb
173
174     /* Disable RDHWR access */
175     mtc0    zero,  CP0_HWRENA
176
177     /* Now load up the Guest Context from VCPU */
178     LONG_L      $1, VCPU_R1(k1)
179     LONG_L      $2, VCPU_R2(k1)
180     LONG_L      $3, VCPU_R3(k1)
181
182     LONG_L      $4, VCPU_R4(k1)
183     LONG_L      $5, VCPU_R5(k1)
184     LONG_L      $6, VCPU_R6(k1)
185     LONG_L      $7, VCPU_R7(k1)
186
187     LONG_L      $8,  VCPU_R8(k1)
188     LONG_L      $9,  VCPU_R9(k1)
189     LONG_L      $10, VCPU_R10(k1)
190     LONG_L      $11, VCPU_R11(k1)
191     LONG_L      $12, VCPU_R12(k1)
192     LONG_L      $13, VCPU_R13(k1)
193     LONG_L      $14, VCPU_R14(k1)
194     LONG_L      $15, VCPU_R15(k1)
195     LONG_L      $16, VCPU_R16(k1)
196     LONG_L      $17, VCPU_R17(k1)
197     LONG_L      $18, VCPU_R18(k1)
198     LONG_L      $19, VCPU_R19(k1)
199     LONG_L      $20, VCPU_R20(k1)
200     LONG_L      $21, VCPU_R21(k1)
201     LONG_L      $22, VCPU_R22(k1)
202     LONG_L      $23, VCPU_R23(k1)
203     LONG_L      $24, VCPU_R24(k1)
204     LONG_L      $25, VCPU_R25(k1)
205
206     /* k0/k1 loaded up later */
207
208     LONG_L      $28, VCPU_R28(k1)
209     LONG_L      $29, VCPU_R29(k1)
210     LONG_L      $30, VCPU_R30(k1)
211     LONG_L      $31, VCPU_R31(k1)
212
213     /* Restore hi/lo */
214         LONG_L          k0, VCPU_LO(k1)
215         mtlo            k0
216
217         LONG_L          k0, VCPU_HI(k1)
218         mthi            k0
219
220 FEXPORT(__kvm_mips_load_k0k1)
221         /* Restore the guest's k0/k1 registers */
222     LONG_L      k0, VCPU_R26(k1)
223     LONG_L      k1, VCPU_R27(k1)
224
225     /* Jump to guest */
226         eret
227         .set    pop
228
229 VECTOR(MIPSX(exception), unknown)
230 /*
231  * Find out what mode we came from and jump to the proper handler.
232  */
233     .set    push
234         .set    noat
235     .set    noreorder
236     mtc0    k0, CP0_ERROREPC    #01: Save guest k0
237     ehb                         #02:
238
239     mfc0    k0, CP0_EBASE       #02: Get EBASE
240     srl     k0, k0, 10          #03: Get rid of CPUNum
241     sll     k0, k0, 10          #04
242     LONG_S  k1, 0x3000(k0)      #05: Save k1 @ offset 0x3000
243     addiu   k0, k0, 0x2000      #06: Exception handler is installed @ offset 0x2000
244         j       k0                                      #07: jump to the function
245         nop                                             #08: branch delay slot
246         .set    push
247 VECTOR_END(MIPSX(exceptionEnd))
248 .end MIPSX(exception)
249
250 /*
251  * Generic Guest exception handler. We end up here when the guest
252  * does something that causes a trap to kernel mode.
253  *
254  */
255 NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra)
256     .set    push
257     .set    noat
258     .set    noreorder
259
260     /* Get the VCPU pointer from DDTATA_LO */
261     mfc0        k1, CP0_DDATA_LO
262         addiu           k1, k1, VCPU_HOST_ARCH
263
264     /* Start saving Guest context to VCPU */
265     LONG_S  $0, VCPU_R0(k1)
266     LONG_S  $1, VCPU_R1(k1)
267     LONG_S  $2, VCPU_R2(k1)
268     LONG_S  $3, VCPU_R3(k1)
269     LONG_S  $4, VCPU_R4(k1)
270     LONG_S  $5, VCPU_R5(k1)
271     LONG_S  $6, VCPU_R6(k1)
272     LONG_S  $7, VCPU_R7(k1)
273     LONG_S  $8, VCPU_R8(k1)
274     LONG_S  $9, VCPU_R9(k1)
275     LONG_S  $10, VCPU_R10(k1)
276     LONG_S  $11, VCPU_R11(k1)
277     LONG_S  $12, VCPU_R12(k1)
278     LONG_S  $13, VCPU_R13(k1)
279     LONG_S  $14, VCPU_R14(k1)
280     LONG_S  $15, VCPU_R15(k1)
281     LONG_S  $16, VCPU_R16(k1)
282     LONG_S  $17,VCPU_R17(k1)
283     LONG_S  $18, VCPU_R18(k1)
284     LONG_S  $19, VCPU_R19(k1)
285     LONG_S  $20, VCPU_R20(k1)
286     LONG_S  $21, VCPU_R21(k1)
287     LONG_S  $22, VCPU_R22(k1)
288     LONG_S  $23, VCPU_R23(k1)
289     LONG_S  $24, VCPU_R24(k1)
290     LONG_S  $25, VCPU_R25(k1)
291
292     /* Guest k0/k1 saved later */
293
294     LONG_S  $28, VCPU_R28(k1)
295     LONG_S  $29, VCPU_R29(k1)
296     LONG_S  $30, VCPU_R30(k1)
297     LONG_S  $31, VCPU_R31(k1)
298
299     /* We need to save hi/lo and restore them on
300      * the way out
301      */
302     mfhi    t0
303     LONG_S  t0, VCPU_HI(k1)
304
305     mflo    t0
306     LONG_S  t0, VCPU_LO(k1)
307
308     /* Finally save guest k0/k1 to VCPU */
309     mfc0    t0, CP0_ERROREPC
310     LONG_S  t0, VCPU_R26(k1)
311
312     /* Get GUEST k1 and save it in VCPU */
313     la      t1, ~0x2ff
314     mfc0    t0, CP0_EBASE
315     and     t0, t0, t1
316     LONG_L  t0, 0x3000(t0)
317     LONG_S  t0, VCPU_R27(k1)
318
319     /* Now that context has been saved, we can use other registers */
320
321     /* Restore vcpu */
322     mfc0        a1, CP0_DDATA_LO
323     move        s1, a1
324
325    /* Restore run (vcpu->run) */
326     LONG_L      a0, VCPU_RUN(a1)
327     /* Save pointer to run in s0, will be saved by the compiler */
328     move        s0, a0
329
330
331     /* Save Host level EPC, BadVaddr and Cause to VCPU, useful to process the exception */
332     mfc0    k0,CP0_EPC
333     LONG_S  k0, VCPU_PC(k1)
334
335     mfc0    k0, CP0_BADVADDR
336     LONG_S  k0, VCPU_HOST_CP0_BADVADDR(k1)
337
338     mfc0    k0, CP0_CAUSE
339     LONG_S  k0, VCPU_HOST_CP0_CAUSE(k1)
340
341     mfc0    k0, CP0_ENTRYHI
342     LONG_S  k0, VCPU_HOST_ENTRYHI(k1)
343
344     /* Now restore the host state just enough to run the handlers */
345
346     /* Swtich EBASE to the one used by Linux */
347     /* load up the host EBASE */
348     mfc0        v0, CP0_STATUS
349
350     .set at
351         or          k0, v0, ST0_BEV
352     .set noat
353
354     mtc0        k0, CP0_STATUS
355     ehb
356
357     LONG_L      k0, VCPU_HOST_EBASE(k1)
358     mtc0        k0,CP0_EBASE
359
360
361     /* Now that the new EBASE has been loaded, unset BEV and KSU_USER */
362     .set at
363         and         v0, v0, ~(ST0_EXL | KSU_USER | ST0_IE)
364     or          v0, v0, ST0_CU0
365     .set noat
366     mtc0        v0, CP0_STATUS
367     ehb
368
369     /* Load up host GP */
370     LONG_L  gp, VCPU_HOST_GP(k1)
371
372     /* Need a stack before we can jump to "C" */
373     LONG_L  sp, VCPU_HOST_STACK(k1)
374
375     /* Saved host state */
376     addiu   sp,sp, -PT_SIZE
377
378     /* XXXKYMA do we need to load the host ASID, maybe not because the
379      * kernel entries are marked GLOBAL, need to verify
380      */
381
382     /* Restore host DDATA_LO */
383     LONG_L      k0, PT_HOST_USERLOCAL(sp)
384     mtc0        k0, CP0_DDATA_LO
385
386     /* Restore RDHWR access */
387     la      k0, 0x2000000F
388     mtc0    k0,  CP0_HWRENA
389
390     /* Jump to handler */
391 FEXPORT(__kvm_mips_jump_to_handler)
392     /* XXXKYMA: not sure if this is safe, how large is the stack?? */
393     /* Now jump to the kvm_mips_handle_exit() to see if we can deal with this in the kernel */
394     la          t9,kvm_mips_handle_exit
395     jalr.hb     t9
396     addiu       sp,sp, -CALLFRAME_SIZ           /* BD Slot */
397
398     /* Return from handler Make sure interrupts are disabled */
399     di
400     ehb
401
402     /* XXXKYMA: k0/k1 could have been blown away if we processed an exception
403      * while we were handling the exception from the guest, reload k1
404      */
405     move        k1, s1
406         addiu           k1, k1, VCPU_HOST_ARCH
407
408     /* Check return value, should tell us if we are returning to the host (handle I/O etc)
409      * or resuming the guest
410      */
411     andi        t0, v0, RESUME_HOST
412     bnez        t0, __kvm_mips_return_to_host
413     nop
414
415 __kvm_mips_return_to_guest:
416     /* Put the saved pointer to vcpu (s1) back into the DDATA_LO Register */
417     mtc0        s1, CP0_DDATA_LO
418
419     /* Load up the Guest EBASE to minimize the window where BEV is set */
420     LONG_L      t0, VCPU_GUEST_EBASE(k1)
421
422     /* Switch EBASE back to the one used by KVM */
423     mfc0        v1, CP0_STATUS
424     .set at
425         or          k0, v1, ST0_BEV
426     .set noat
427     mtc0        k0, CP0_STATUS
428     ehb
429     mtc0        t0,CP0_EBASE
430
431     /* Setup status register for running guest in UM */
432     .set at
433     or     v1, v1, (ST0_EXL | KSU_USER | ST0_IE)
434     and     v1, v1, ~ST0_CU0
435     .set noat
436     mtc0    v1, CP0_STATUS
437     ehb
438
439
440         /* Set Guest EPC */
441         LONG_L          t0, VCPU_PC(k1)
442         mtc0            t0, CP0_EPC
443
444     /* Set the ASID for the Guest Kernel */
445     sll         t0, t0, 1                       /* with kseg0 @ 0x40000000, kernel */
446                                                 /* addresses shift to 0x80000000 */
447     bltz        t0, 1f                          /* If kernel */
448         addiu       t1, k1, VCPU_GUEST_KERNEL_ASID  /* (BD)  */
449     addiu       t1, k1, VCPU_GUEST_USER_ASID    /* else user */
450 1:
451     /* t1: contains the base of the ASID array, need to get the cpu id  */
452     LONG_L      t2, TI_CPU($28)             /* smp_processor_id */
453     sll         t2, t2, 2                   /* x4 */
454     addu        t3, t1, t2
455     LONG_L      k0, (t3)
456     andi        k0, k0, 0xff
457         mtc0            k0,CP0_ENTRYHI
458     ehb
459
460     /* Disable RDHWR access */
461     mtc0    zero,  CP0_HWRENA
462
463     /* load the guest context from VCPU and return */
464     LONG_L  $0, VCPU_R0(k1)
465     LONG_L  $1, VCPU_R1(k1)
466     LONG_L  $2, VCPU_R2(k1)
467     LONG_L  $3, VCPU_R3(k1)
468     LONG_L  $4, VCPU_R4(k1)
469     LONG_L  $5, VCPU_R5(k1)
470     LONG_L  $6, VCPU_R6(k1)
471     LONG_L  $7, VCPU_R7(k1)
472     LONG_L  $8, VCPU_R8(k1)
473     LONG_L  $9, VCPU_R9(k1)
474     LONG_L  $10, VCPU_R10(k1)
475     LONG_L  $11, VCPU_R11(k1)
476     LONG_L  $12, VCPU_R12(k1)
477     LONG_L  $13, VCPU_R13(k1)
478     LONG_L  $14, VCPU_R14(k1)
479     LONG_L  $15, VCPU_R15(k1)
480     LONG_L  $16, VCPU_R16(k1)
481     LONG_L  $17, VCPU_R17(k1)
482     LONG_L  $18, VCPU_R18(k1)
483     LONG_L  $19, VCPU_R19(k1)
484     LONG_L  $20, VCPU_R20(k1)
485     LONG_L  $21, VCPU_R21(k1)
486     LONG_L  $22, VCPU_R22(k1)
487     LONG_L  $23, VCPU_R23(k1)
488     LONG_L  $24, VCPU_R24(k1)
489     LONG_L  $25, VCPU_R25(k1)
490
491     /* $/k1 loaded later */
492     LONG_L  $28, VCPU_R28(k1)
493     LONG_L  $29, VCPU_R29(k1)
494     LONG_L  $30, VCPU_R30(k1)
495     LONG_L  $31, VCPU_R31(k1)
496
497 FEXPORT(__kvm_mips_skip_guest_restore)
498     LONG_L  k0, VCPU_HI(k1)
499     mthi    k0
500
501     LONG_L  k0, VCPU_LO(k1)
502     mtlo    k0
503
504     LONG_L  k0, VCPU_R26(k1)
505     LONG_L  k1, VCPU_R27(k1)
506
507     eret
508
509 __kvm_mips_return_to_host:
510     /* EBASE is already pointing to Linux */
511     LONG_L  k1, VCPU_HOST_STACK(k1)
512         addiu   k1,k1, -PT_SIZE
513
514     /* Restore host DDATA_LO */
515     LONG_L      k0, PT_HOST_USERLOCAL(k1)
516     mtc0        k0, CP0_DDATA_LO
517
518     /* Restore host ASID */
519     LONG_L      k0, PT_HOST_ASID(sp)
520     andi        k0, 0xff
521     mtc0        k0,CP0_ENTRYHI
522     ehb
523
524     /* Load context saved on the host stack */
525     LONG_L  $0, PT_R0(k1)
526     LONG_L  $1, PT_R1(k1)
527
528     /* r2/v0 is the return code, shift it down by 2 (arithmetic) to recover the err code  */
529     sra     k0, v0, 2
530     move    $2, k0
531
532     LONG_L  $3, PT_R3(k1)
533     LONG_L  $4, PT_R4(k1)
534     LONG_L  $5, PT_R5(k1)
535     LONG_L  $6, PT_R6(k1)
536     LONG_L  $7, PT_R7(k1)
537     LONG_L  $8, PT_R8(k1)
538     LONG_L  $9, PT_R9(k1)
539     LONG_L  $10, PT_R10(k1)
540     LONG_L  $11, PT_R11(k1)
541     LONG_L  $12, PT_R12(k1)
542     LONG_L  $13, PT_R13(k1)
543     LONG_L  $14, PT_R14(k1)
544     LONG_L  $15, PT_R15(k1)
545     LONG_L  $16, PT_R16(k1)
546     LONG_L  $17, PT_R17(k1)
547     LONG_L  $18, PT_R18(k1)
548     LONG_L  $19, PT_R19(k1)
549     LONG_L  $20, PT_R20(k1)
550     LONG_L  $21, PT_R21(k1)
551     LONG_L  $22, PT_R22(k1)
552     LONG_L  $23, PT_R23(k1)
553     LONG_L  $24, PT_R24(k1)
554     LONG_L  $25, PT_R25(k1)
555
556     /* Host k0/k1 were not saved */
557
558     LONG_L  $28, PT_R28(k1)
559     LONG_L  $29, PT_R29(k1)
560     LONG_L  $30, PT_R30(k1)
561
562     LONG_L  k0, PT_HI(k1)
563     mthi    k0
564
565     LONG_L  k0, PT_LO(k1)
566     mtlo    k0
567
568     /* Restore RDHWR access */
569     la      k0, 0x2000000F
570     mtc0    k0,  CP0_HWRENA
571
572
573     /* Restore RA, which is the address we will return to */
574     LONG_L  ra, PT_R31(k1)
575     j       ra
576     nop
577
578     .set    pop
579 VECTOR_END(MIPSX(GuestExceptionEnd))
580 .end MIPSX(GuestException)
581
582 MIPSX(exceptions):
583         ####
584         ##### The exception handlers.
585         #####
586         .word _C_LABEL(MIPSX(GuestException))   #  0
587         .word _C_LABEL(MIPSX(GuestException))   #  1
588         .word _C_LABEL(MIPSX(GuestException))   #  2
589         .word _C_LABEL(MIPSX(GuestException))   #  3
590         .word _C_LABEL(MIPSX(GuestException))   #  4
591         .word _C_LABEL(MIPSX(GuestException))   #  5
592         .word _C_LABEL(MIPSX(GuestException))   #  6
593         .word _C_LABEL(MIPSX(GuestException))   #  7
594         .word _C_LABEL(MIPSX(GuestException))   #  8
595         .word _C_LABEL(MIPSX(GuestException))   #  9
596         .word _C_LABEL(MIPSX(GuestException))   # 10
597         .word _C_LABEL(MIPSX(GuestException))   # 11
598         .word _C_LABEL(MIPSX(GuestException))   # 12
599         .word _C_LABEL(MIPSX(GuestException))   # 13
600         .word _C_LABEL(MIPSX(GuestException))   # 14
601         .word _C_LABEL(MIPSX(GuestException))   # 15
602         .word _C_LABEL(MIPSX(GuestException))   # 16
603         .word _C_LABEL(MIPSX(GuestException))   # 17
604         .word _C_LABEL(MIPSX(GuestException))   # 18
605         .word _C_LABEL(MIPSX(GuestException))   # 19
606         .word _C_LABEL(MIPSX(GuestException))   # 20
607         .word _C_LABEL(MIPSX(GuestException))   # 21
608         .word _C_LABEL(MIPSX(GuestException))   # 22
609         .word _C_LABEL(MIPSX(GuestException))   # 23
610         .word _C_LABEL(MIPSX(GuestException))   # 24
611         .word _C_LABEL(MIPSX(GuestException))   # 25
612         .word _C_LABEL(MIPSX(GuestException))   # 26
613         .word _C_LABEL(MIPSX(GuestException))   # 27
614         .word _C_LABEL(MIPSX(GuestException))   # 28
615         .word _C_LABEL(MIPSX(GuestException))   # 29
616         .word _C_LABEL(MIPSX(GuestException))   # 30
617         .word _C_LABEL(MIPSX(GuestException))   # 31
618
619
620 /* This routine makes changes to the instruction stream effective to the hardware.
621  * It should be called after the instruction stream is written.
622  * On return, the new instructions are effective.
623  * Inputs:
624  * a0 = Start address of new instruction stream
625  * a1 = Size, in bytes, of new instruction stream
626  */
627
628 #define HW_SYNCI_Step       $1
629 LEAF(MIPSX(SyncICache))
630     .set    push
631         .set    mips32r2
632     beq     a1, zero, 20f
633     nop
634     addu    a1, a0, a1
635     rdhwr   v0, HW_SYNCI_Step
636     beq     v0, zero, 20f
637     nop
638
639 10:
640     synci   0(a0)
641     addu    a0, a0, v0
642     sltu    v1, a0, a1
643     bne     v1, zero, 10b
644     nop
645     sync
646 20:
647     jr.hb   ra
648     nop
649     .set pop
650 END(MIPSX(SyncICache))