mm: fix exec activate_mm vs TLB shootdown and lazy tlb switching race
[linux/fpc-iii.git] / arch / tile / kernel / relocate_kernel_64.S
blobd9d8cf6176e887af1bb3ef283e0727a997608c59
1 /*
2  * Copyright 2011 Tilera Corporation. All Rights Reserved.
3  *
4  *   This program is free software; you can redistribute it and/or
5  *   modify it under the terms of the GNU General Public License
6  *   as published by the Free Software Foundation, version 2.
7  *
8  *   This program is distributed in the hope that it will be useful, but
9  *   WITHOUT ANY WARRANTY; without even the implied warranty of
10  *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11  *   NON INFRINGEMENT.  See the GNU General Public License for
12  *   more details.
13  *
14  * copy new kernel into place and then call hv_reexec
15  *
16  */
18 #include <linux/linkage.h>
19 #include <arch/chip.h>
20 #include <asm/page.h>
21 #include <hv/hypervisor.h>
23 #undef RELOCATE_NEW_KERNEL_VERBOSE
25 STD_ENTRY(relocate_new_kernel)
27         move    r30, r0         /* page list */
28         move    r31, r1         /* address of page we are on */
29         move    r32, r2         /* start address of new kernel */
31         shrui   r1, r1, PAGE_SHIFT
32         addi    r1, r1, 1
33         shli    sp, r1, PAGE_SHIFT
34         addi    sp, sp, -8
35         /* we now have a stack (whether we need one or not) */
37 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
38         moveli  r40, hw2_last(hv_console_putc)
39         shl16insli r40, r40, hw1(hv_console_putc)
40         shl16insli r40, r40, hw0(hv_console_putc)
42         moveli  r0, 'r'
43         jalr    r40
45         moveli  r0, '_'
46         jalr    r40
48         moveli  r0, 'n'
49         jalr    r40
51         moveli  r0, '_'
52         jalr    r40
54         moveli  r0, 'k'
55         jalr    r40
57         moveli  r0, '\n'
58         jalr    r40
59 #endif
61         /*
62          * Throughout this code r30 is pointer to the element of page
63          * list we are working on.
64          *
65          * Normally we get to the next element of the page list by
66          * incrementing r30 by eight.  The exception is if the element
67          * on the page list is an IND_INDIRECTION in which case we use
68          * the element with the low bits masked off as the new value
69          * of r30.
70          *
71          * To get this started, we need the value passed to us (which
72          * will always be an IND_INDIRECTION) in memory somewhere with
73          * r30 pointing at it.  To do that, we push the value passed
74          * to us on the stack and make r30 point to it.
75          */
77         st      sp, r30
78         move    r30, sp
79         addi    sp, sp, -16
81         /*
82          * On TILE-GX, we need to flush all tiles' caches, since we may
83          * have been doing hash-for-home caching there.  Note that we
84          * must do this _after_ we're completely done modifying any memory
85          * other than our output buffer (which we know is locally cached).
86          * We want the caches to be fully clean when we do the reexec,
87          * because the hypervisor is going to do this flush again at that
88          * point, and we don't want that second flush to overwrite any memory.
89          */
90         {
91          move   r0, zero         /* cache_pa */
92          moveli r1, hw2_last(HV_FLUSH_EVICT_L2)
93         }
94         {
95          shl16insli     r1, r1, hw1(HV_FLUSH_EVICT_L2)
96          movei  r2, -1           /* cache_cpumask; -1 means all client tiles */
97         }
98         {
99          shl16insli     r1, r1, hw0(HV_FLUSH_EVICT_L2)  /* cache_control */
100          move   r3, zero         /* tlb_va */
101         }
102         {
103          move   r4, zero         /* tlb_length */
104          move   r5, zero         /* tlb_pgsize */
105         }
106         {
107          move   r6, zero         /* tlb_cpumask */
108          move   r7, zero         /* asids */
109         }
110         {
111          moveli r20, hw2_last(hv_flush_remote)
112          move   r8, zero         /* asidcount */
113         }
114         shl16insli      r20, r20, hw1(hv_flush_remote)
115         shl16insli      r20, r20, hw0(hv_flush_remote)
117         jalr    r20
119         /* r33 is destination pointer, default to zero */
121         moveli  r33, 0
123 .Lloop: ld      r10, r30
125         andi    r9, r10, 0xf    /* low 4 bits tell us what type it is */
126         xor     r10, r10, r9    /* r10 is now value with low 4 bits stripped */
128         cmpeqi  r0, r9, 0x1     /* IND_DESTINATION */
129         beqzt   r0, .Ltry2
131         move    r33, r10
133 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
134         moveli  r0, 'd'
135         jalr    r40
136 #endif
138         addi    r30, r30, 8
139         j       .Lloop
141 .Ltry2:
142         cmpeqi  r0, r9, 0x2     /* IND_INDIRECTION */
143         beqzt   r0, .Ltry4
145         move    r30, r10
147 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
148         moveli  r0, 'i'
149         jalr    r40
150 #endif
152         j       .Lloop
154 .Ltry4:
155         cmpeqi  r0, r9, 0x4     /* IND_DONE */
156         beqzt   r0, .Ltry8
158         mf
160 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
161         moveli  r0, 'D'
162         jalr    r40
163         moveli  r0, '\n'
164         jalr    r40
165 #endif
167         move    r0, r32
169         moveli  r41, hw2_last(hv_reexec)
170         shl16insli      r41, r41, hw1(hv_reexec)
171         shl16insli      r41, r41, hw0(hv_reexec)
173         jalr    r41
175         /* we should not get here */
177 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
178         moveli  r0, '?'
179         jalr    r40
180         moveli  r0, '\n'
181         jalr    r40
182 #endif
184         j       .Lhalt
186 .Ltry8: cmpeqi  r0, r9, 0x8     /* IND_SOURCE */
187         beqz    r0, .Lerr       /* unknown type */
189         /* copy page at r10 to page at r33 */
191         move    r11, r33
193         moveli  r0, hw2_last(PAGE_SIZE)
194         shl16insli      r0, r0, hw1(PAGE_SIZE)
195         shl16insli      r0, r0, hw0(PAGE_SIZE)
196         add     r33, r33, r0
198         /* copy word at r10 to word at r11 until r11 equals r33 */
200         /* We know page size must be multiple of 8, so we can unroll
201          * 8 times safely without any edge case checking.
202          *
203          * Issue a flush of the destination every 8 words to avoid
204          * incoherence when starting the new kernel.  (Now this is
205          * just good paranoia because the hv_reexec call will also
206          * take care of this.)
207          */
210         { ld    r0, r10; addi   r10, r10, 8 }
211         { st    r11, r0; addi   r11, r11, 8 }
212         { ld    r0, r10; addi   r10, r10, 8 }
213         { st    r11, r0; addi   r11, r11, 8 }
214         { ld    r0, r10; addi   r10, r10, 8 }
215         { st    r11, r0; addi   r11, r11, 8 }
216         { ld    r0, r10; addi   r10, r10, 8 }
217         { st    r11, r0; addi   r11, r11, 8 }
218         { ld    r0, r10; addi   r10, r10, 8 }
219         { st    r11, r0; addi   r11, r11, 8 }
220         { ld    r0, r10; addi   r10, r10, 8 }
221         { st    r11, r0; addi   r11, r11, 8 }
222         { ld    r0, r10; addi   r10, r10, 8 }
223         { st    r11, r0; addi   r11, r11, 8 }
224         { ld    r0, r10; addi   r10, r10, 8 }
225         { st    r11, r0 }
226         { flush r11    ; addi   r11, r11, 8 }
228         cmpeq   r0, r33, r11
229         beqzt   r0, 1b
231 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
232         moveli  r0, 's'
233         jalr    r40
234 #endif
236         addi    r30, r30, 8
237         j       .Lloop
240 .Lerr:
241 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
242         moveli  r0, 'e'
243         jalr    r40
244         moveli  r0, 'r'
245         jalr    r40
246         moveli  r0, 'r'
247         jalr    r40
248         moveli  r0, '\n'
249         jalr    r40
250 #endif
251 .Lhalt:
252         moveli r41, hw2_last(hv_halt)
253         shl16insli r41, r41, hw1(hv_halt)
254         shl16insli r41, r41, hw0(hv_halt)
256         jalr    r41
257         STD_ENDPROC(relocate_new_kernel)
259         .section .rodata,"a"
261         .globl relocate_new_kernel_size
262 relocate_new_kernel_size:
263         .long .Lend_relocate_new_kernel - relocate_new_kernel