x86/efi: Enforce CONFIG_RELOCATABLE for EFI boot stub
[linux/fpc-iii.git] / arch / powerpc / mm / hash_low_64.S
blobd3cbda62857b92ffb0867c4fe0ab1deeb0979313
1 /*
2  * ppc64 MMU hashtable management routines
3  *
4  * (c) Copyright IBM Corp. 2003, 2005
5  *
6  * Maintained by: Benjamin Herrenschmidt
7  *                <benh@kernel.crashing.org>
8  *
9  * This file is covered by the GNU Public Licence v2 as
10  * described in the kernel's COPYING file.
11  */
13 #include <asm/reg.h>
14 #include <asm/pgtable.h>
15 #include <asm/mmu.h>
16 #include <asm/page.h>
17 #include <asm/types.h>
18 #include <asm/ppc_asm.h>
19 #include <asm/asm-offsets.h>
20 #include <asm/cputable.h>
22         .text
25  * Stackframe:
26  *              
27  *         +-> Back chain                       (SP + 256)
28  *         |   General register save area       (SP + 112)
29  *         |   Parameter save area              (SP + 48)
30  *         |   TOC save area                    (SP + 40)
31  *         |   link editor doubleword           (SP + 32)
32  *         |   compiler doubleword              (SP + 24)
33  *         |   LR save area                     (SP + 16)
34  *         |   CR save area                     (SP + 8)
35  * SP ---> +-- Back chain                       (SP + 0)
36  */
38 #ifndef CONFIG_PPC_64K_PAGES
40 /*****************************************************************************
41  *                                                                           *
42  *           4K SW & 4K HW pages implementation                              *
43  *                                                                           *
44  *****************************************************************************/
48  * _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
49  *               pte_t *ptep, unsigned long trap, int local, int ssize)
50  *
51  * Adds a 4K page to the hash table in a segment of 4K pages only
52  */
54 _GLOBAL(__hash_page_4K)
55         mflr    r0
56         std     r0,16(r1)
57         stdu    r1,-STACKFRAMESIZE(r1)
58         /* Save all params that we need after a function call */
59         std     r6,STK_PARAM(R6)(r1)
60         std     r8,STK_PARAM(R8)(r1)
61         std     r9,STK_PARAM(R9)(r1)
62         
63         /* Save non-volatile registers.
64          * r31 will hold "old PTE"
65          * r30 is "new PTE"
66          * r29 is vpn
67          * r28 is a hash value
68          * r27 is hashtab mask (maybe dynamic patched instead ?)
69          */
70         std     r27,STK_REG(R27)(r1)
71         std     r28,STK_REG(R28)(r1)
72         std     r29,STK_REG(R29)(r1)
73         std     r30,STK_REG(R30)(r1)
74         std     r31,STK_REG(R31)(r1)
75         
76         /* Step 1:
77          *
78          * Check permissions, atomically mark the linux PTE busy
79          * and hashed.
80          */ 
82         ldarx   r31,0,r6
83         /* Check access rights (access & ~(pte_val(*ptep))) */
84         andc.   r0,r4,r31
85         bne-    htab_wrong_access
86         /* Check if PTE is busy */
87         andi.   r0,r31,_PAGE_BUSY
88         /* If so, just bail out and refault if needed. Someone else
89          * is changing this PTE anyway and might hash it.
90          */
91         bne-    htab_bail_ok
93         /* Prepare new PTE value (turn access RW into DIRTY, then
94          * add BUSY,HASHPTE and ACCESSED)
95          */
96         rlwinm  r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
97         or      r30,r30,r31
98         ori     r30,r30,_PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE
99         /* Write the linux PTE atomically (setting busy) */
100         stdcx.  r30,0,r6
101         bne-    1b
102         isync
104         /* Step 2:
105          *
106          * Insert/Update the HPTE in the hash table. At this point,
107          * r4 (access) is re-useable, we use it for the new HPTE flags
108          */
110 BEGIN_FTR_SECTION
111         cmpdi   r9,0                    /* check segment size */
112         bne     3f
113 END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
114         /* Calc vpn and put it in r29 */
115         sldi    r29,r5,SID_SHIFT - VPN_SHIFT
116         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
117         or      r29,r28,r29
118         /*
119          * Calculate hash value for primary slot and store it in r28
120          * r3 = va, r5 = vsid
121          * r0 = (va >> 12) & ((1ul << (28 - 12)) -1)
122          */
123         rldicl  r0,r3,64-12,48
124         xor     r28,r5,r0               /* hash */
125         b       4f
127 3:      /* Calc vpn and put it in r29 */
128         sldi    r29,r5,SID_SHIFT_1T - VPN_SHIFT
129         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
130         or      r29,r28,r29
132         /*
133          * calculate hash value for primary slot and
134          * store it in r28 for 1T segment
135          * r3 = va, r5 = vsid
136          */
137         sldi    r28,r5,25               /* vsid << 25 */
138         /* r0 =  (va >> 12) & ((1ul << (40 - 12)) -1) */
139         rldicl  r0,r3,64-12,36
140         xor     r28,r28,r5              /* vsid ^ ( vsid << 25) */
141         xor     r28,r28,r0              /* hash */
143         /* Convert linux PTE bits into HW equivalents */
144 4:      andi.   r3,r30,0x1fe            /* Get basic set of flags */
145         xori    r3,r3,HPTE_R_N          /* _PAGE_EXEC -> NOEXEC */
146         rlwinm  r0,r30,32-9+1,30,30     /* _PAGE_RW -> _PAGE_USER (r0) */
147         rlwinm  r4,r30,32-7+1,30,30     /* _PAGE_DIRTY -> _PAGE_USER (r4) */
148         and     r0,r0,r4                /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
149         andc    r0,r30,r0               /* r0 = pte & ~r0 */
150         rlwimi  r3,r0,32-1,31,31        /* Insert result into PP lsb */
151         ori     r3,r3,HPTE_R_C          /* Always add "C" bit for perf. */
153         /* We eventually do the icache sync here (maybe inline that
154          * code rather than call a C function...) 
155          */
156 BEGIN_FTR_SECTION
157         mr      r4,r30
158         mr      r5,r7
159         bl      .hash_page_do_lazy_icache
160 END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
162         /* At this point, r3 contains new PP bits, save them in
163          * place of "access" in the param area (sic)
164          */
165         std     r3,STK_PARAM(R4)(r1)
167         /* Get htab_hash_mask */
168         ld      r4,htab_hash_mask@got(2)
169         ld      r27,0(r4)       /* htab_hash_mask -> r27 */
171         /* Check if we may already be in the hashtable, in this case, we
172          * go to out-of-line code to try to modify the HPTE
173          */
174         andi.   r0,r31,_PAGE_HASHPTE
175         bne     htab_modify_pte
177 htab_insert_pte:
178         /* Clear hpte bits in new pte (we also clear BUSY btw) and
179          * add _PAGE_HASHPTE
180          */
181         lis     r0,_PAGE_HPTEFLAGS@h
182         ori     r0,r0,_PAGE_HPTEFLAGS@l
183         andc    r30,r30,r0
184         ori     r30,r30,_PAGE_HASHPTE
186         /* physical address r5 */
187         rldicl  r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
188         sldi    r5,r5,PAGE_SHIFT
190         /* Calculate primary group hash */
191         and     r0,r28,r27
192         rldicr  r3,r0,3,63-3            /* r3 = (hash & mask) << 3 */
194         /* Call ppc_md.hpte_insert */
195         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
196         mr      r4,r29                  /* Retrieve vpn */
197         li      r7,0                    /* !bolted, !secondary */
198         li      r8,MMU_PAGE_4K          /* page size */
199         li      r9,MMU_PAGE_4K          /* actual page size */
200         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
201 _GLOBAL(htab_call_hpte_insert1)
202         bl      .                       /* Patched by htab_finish_init() */
203         cmpdi   0,r3,0
204         bge     htab_pte_insert_ok      /* Insertion successful */
205         cmpdi   0,r3,-2                 /* Critical failure */
206         beq-    htab_pte_insert_failure
208         /* Now try secondary slot */
209         
210         /* physical address r5 */
211         rldicl  r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
212         sldi    r5,r5,PAGE_SHIFT
214         /* Calculate secondary group hash */
215         andc    r0,r27,r28
216         rldicr  r3,r0,3,63-3    /* r0 = (~hash & mask) << 3 */
217         
218         /* Call ppc_md.hpte_insert */
219         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
220         mr      r4,r29                  /* Retrieve vpn */
221         li      r7,HPTE_V_SECONDARY     /* !bolted, secondary */
222         li      r8,MMU_PAGE_4K          /* page size */
223         li      r9,MMU_PAGE_4K          /* actual page size */
224         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
225 _GLOBAL(htab_call_hpte_insert2)
226         bl      .                       /* Patched by htab_finish_init() */
227         cmpdi   0,r3,0
228         bge+    htab_pte_insert_ok      /* Insertion successful */
229         cmpdi   0,r3,-2                 /* Critical failure */
230         beq-    htab_pte_insert_failure
232         /* Both are full, we need to evict something */
233         mftb    r0
234         /* Pick a random group based on TB */
235         andi.   r0,r0,1
236         mr      r5,r28
237         bne     2f
238         not     r5,r5
239 2:      and     r0,r5,r27
240         rldicr  r3,r0,3,63-3    /* r0 = (hash & mask) << 3 */   
241         /* Call ppc_md.hpte_remove */
242 _GLOBAL(htab_call_hpte_remove)
243         bl      .                       /* Patched by htab_finish_init() */
245         /* Try all again */
246         b       htab_insert_pte 
248 htab_bail_ok:
249         li      r3,0
250         b       htab_bail
252 htab_pte_insert_ok:
253         /* Insert slot number & secondary bit in PTE */
254         rldimi  r30,r3,12,63-15
255                 
256         /* Write out the PTE with a normal write
257          * (maybe add eieio may be good still ?)
258          */
259 htab_write_out_pte:
260         ld      r6,STK_PARAM(R6)(r1)
261         std     r30,0(r6)
262         li      r3, 0
263 htab_bail:
264         ld      r27,STK_REG(R27)(r1)
265         ld      r28,STK_REG(R28)(r1)
266         ld      r29,STK_REG(R29)(r1)
267         ld      r30,STK_REG(R30)(r1)
268         ld      r31,STK_REG(R31)(r1)
269         addi    r1,r1,STACKFRAMESIZE
270         ld      r0,16(r1)
271         mtlr    r0
272         blr
274 htab_modify_pte:
275         /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
276         mr      r4,r3
277         rlwinm  r3,r31,32-12,29,31
279         /* Secondary group ? if yes, get a inverted hash value */
280         mr      r5,r28
281         andi.   r0,r31,_PAGE_SECONDARY
282         beq     1f
283         not     r5,r5
285         /* Calculate proper slot value for ppc_md.hpte_updatepp */
286         and     r0,r5,r27
287         rldicr  r0,r0,3,63-3    /* r0 = (hash & mask) << 3 */
288         add     r3,r0,r3        /* add slot idx */
290         /* Call ppc_md.hpte_updatepp */
291         mr      r5,r29                  /* vpn */
292         li      r6,MMU_PAGE_4K          /* base page size */
293         li      r7,MMU_PAGE_4K          /* actual page size */
294         ld      r8,STK_PARAM(R9)(r1)    /* segment size */
295         ld      r9,STK_PARAM(R8)(r1)    /* get "local" param */
296 _GLOBAL(htab_call_hpte_updatepp)
297         bl      .                       /* Patched by htab_finish_init() */
299         /* if we failed because typically the HPTE wasn't really here
300          * we try an insertion. 
301          */
302         cmpdi   0,r3,-1
303         beq-    htab_insert_pte
305         /* Clear the BUSY bit and Write out the PTE */
306         li      r0,_PAGE_BUSY
307         andc    r30,r30,r0
308         b       htab_write_out_pte
310 htab_wrong_access:
311         /* Bail out clearing reservation */
312         stdcx.  r31,0,r6
313         li      r3,1
314         b       htab_bail
316 htab_pte_insert_failure:
317         /* Bail out restoring old PTE */
318         ld      r6,STK_PARAM(R6)(r1)
319         std     r31,0(r6)
320         li      r3,-1
321         b       htab_bail
324 #else /* CONFIG_PPC_64K_PAGES */
327 /*****************************************************************************
328  *                                                                           *
329  *           64K SW & 4K or 64K HW in a 4K segment pages implementation      *
330  *                                                                           *
331  *****************************************************************************/
333 /* _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
334  *               pte_t *ptep, unsigned long trap, int local, int ssize,
335  *               int subpg_prot)
336  */
339  * For now, we do NOT implement Admixed pages
340  */
341 _GLOBAL(__hash_page_4K)
342         mflr    r0
343         std     r0,16(r1)
344         stdu    r1,-STACKFRAMESIZE(r1)
345         /* Save all params that we need after a function call */
346         std     r6,STK_PARAM(R6)(r1)
347         std     r8,STK_PARAM(R8)(r1)
348         std     r9,STK_PARAM(R9)(r1)
350         /* Save non-volatile registers.
351          * r31 will hold "old PTE"
352          * r30 is "new PTE"
353          * r29 is vpn
354          * r28 is a hash value
355          * r27 is hashtab mask (maybe dynamic patched instead ?)
356          * r26 is the hidx mask
357          * r25 is the index in combo page
358          */
359         std     r25,STK_REG(R25)(r1)
360         std     r26,STK_REG(R26)(r1)
361         std     r27,STK_REG(R27)(r1)
362         std     r28,STK_REG(R28)(r1)
363         std     r29,STK_REG(R29)(r1)
364         std     r30,STK_REG(R30)(r1)
365         std     r31,STK_REG(R31)(r1)
367         /* Step 1:
368          *
369          * Check permissions, atomically mark the linux PTE busy
370          * and hashed.
371          */
373         ldarx   r31,0,r6
374         /* Check access rights (access & ~(pte_val(*ptep))) */
375         andc.   r0,r4,r31
376         bne-    htab_wrong_access
377         /* Check if PTE is busy */
378         andi.   r0,r31,_PAGE_BUSY
379         /* If so, just bail out and refault if needed. Someone else
380          * is changing this PTE anyway and might hash it.
381          */
382         bne-    htab_bail_ok
383         /* Prepare new PTE value (turn access RW into DIRTY, then
384          * add BUSY and ACCESSED)
385          */
386         rlwinm  r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
387         or      r30,r30,r31
388         ori     r30,r30,_PAGE_BUSY | _PAGE_ACCESSED
389         oris    r30,r30,_PAGE_COMBO@h
390         /* Write the linux PTE atomically (setting busy) */
391         stdcx.  r30,0,r6
392         bne-    1b
393         isync
395         /* Step 2:
396          *
397          * Insert/Update the HPTE in the hash table. At this point,
398          * r4 (access) is re-useable, we use it for the new HPTE flags
399          */
401         /* Load the hidx index */
402         rldicl  r25,r3,64-12,60
404 BEGIN_FTR_SECTION
405         cmpdi   r9,0                    /* check segment size */
406         bne     3f
407 END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
408         /* Calc vpn and put it in r29 */
409         sldi    r29,r5,SID_SHIFT - VPN_SHIFT
410         /*
411          * clrldi r3,r3,64 - SID_SHIFT -->  ea & 0xfffffff
412          * srdi  r28,r3,VPN_SHIFT
413          */
414         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
415         or      r29,r28,r29
416         /*
417          * Calculate hash value for primary slot and store it in r28
418          * r3 = va, r5 = vsid
419          * r0 = (va >> 12) & ((1ul << (28 - 12)) -1)
420          */
421         rldicl  r0,r3,64-12,48
422         xor     r28,r5,r0               /* hash */
423         b       4f
425 3:      /* Calc vpn and put it in r29 */
426         sldi    r29,r5,SID_SHIFT_1T - VPN_SHIFT
427         /*
428          * clrldi r3,r3,64 - SID_SHIFT_1T -->  ea & 0xffffffffff
429          * srdi r28,r3,VPN_SHIFT
430          */
431         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
432         or      r29,r28,r29
434         /*
435          * Calculate hash value for primary slot and
436          * store it in r28  for 1T segment
437          * r3 = va, r5 = vsid
438          */
439         sldi    r28,r5,25               /* vsid << 25 */
440         /* r0 = (va >> 12) & ((1ul << (40 - 12)) -1) */
441         rldicl  r0,r3,64-12,36
442         xor     r28,r28,r5              /* vsid ^ ( vsid << 25) */
443         xor     r28,r28,r0              /* hash */
445         /* Convert linux PTE bits into HW equivalents */
447 #ifdef CONFIG_PPC_SUBPAGE_PROT
448         andc    r10,r30,r10
449         andi.   r3,r10,0x1fe            /* Get basic set of flags */
450         rlwinm  r0,r10,32-9+1,30,30     /* _PAGE_RW -> _PAGE_USER (r0) */
451 #else
452         andi.   r3,r30,0x1fe            /* Get basic set of flags */
453         rlwinm  r0,r30,32-9+1,30,30     /* _PAGE_RW -> _PAGE_USER (r0) */
454 #endif
455         xori    r3,r3,HPTE_R_N          /* _PAGE_EXEC -> NOEXEC */
456         rlwinm  r4,r30,32-7+1,30,30     /* _PAGE_DIRTY -> _PAGE_USER (r4) */
457         and     r0,r0,r4                /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
458         andc    r0,r3,r0                /* r0 = pte & ~r0 */
459         rlwimi  r3,r0,32-1,31,31        /* Insert result into PP lsb */
460         ori     r3,r3,HPTE_R_C          /* Always add "C" bit for perf. */
462         /* We eventually do the icache sync here (maybe inline that
463          * code rather than call a C function...)
464          */
465 BEGIN_FTR_SECTION
466         mr      r4,r30
467         mr      r5,r7
468         bl      .hash_page_do_lazy_icache
469 END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
471         /* At this point, r3 contains new PP bits, save them in
472          * place of "access" in the param area (sic)
473          */
474         std     r3,STK_PARAM(R4)(r1)
476         /* Get htab_hash_mask */
477         ld      r4,htab_hash_mask@got(2)
478         ld      r27,0(r4)       /* htab_hash_mask -> r27 */
480         /* Check if we may already be in the hashtable, in this case, we
481          * go to out-of-line code to try to modify the HPTE. We look for
482          * the bit at (1 >> (index + 32))
483          */
484         rldicl. r0,r31,64-12,48
485         li      r26,0                   /* Default hidx */
486         beq     htab_insert_pte
488         /*
489          * Check if the pte was already inserted into the hash table
490          * as a 64k HW page, and invalidate the 64k HPTE if so.
491          */
492         andis.  r0,r31,_PAGE_COMBO@h
493         beq     htab_inval_old_hpte
495         ld      r6,STK_PARAM(R6)(r1)
496         ori     r26,r6,PTE_PAGE_HIDX_OFFSET /* Load the hidx mask. */
497         ld      r26,0(r26)
498         addi    r5,r25,36               /* Check actual HPTE_SUB bit, this */
499         rldcr.  r0,r31,r5,0             /* must match pgtable.h definition */
500         bne     htab_modify_pte
502 htab_insert_pte:
503         /* real page number in r5, PTE RPN value + index */
504         andis.  r0,r31,_PAGE_4K_PFN@h
505         srdi    r5,r31,PTE_RPN_SHIFT
506         bne-    htab_special_pfn
507         sldi    r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
508         add     r5,r5,r25
509 htab_special_pfn:
510         sldi    r5,r5,HW_PAGE_SHIFT
512         /* Calculate primary group hash */
513         and     r0,r28,r27
514         rldicr  r3,r0,3,63-3            /* r0 = (hash & mask) << 3 */
516         /* Call ppc_md.hpte_insert */
517         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
518         mr      r4,r29                  /* Retrieve vpn */
519         li      r7,0                    /* !bolted, !secondary */
520         li      r8,MMU_PAGE_4K          /* page size */
521         li      r9,MMU_PAGE_4K          /* actual page size */
522         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
523 _GLOBAL(htab_call_hpte_insert1)
524         bl      .                       /* patched by htab_finish_init() */
525         cmpdi   0,r3,0
526         bge     htab_pte_insert_ok      /* Insertion successful */
527         cmpdi   0,r3,-2                 /* Critical failure */
528         beq-    htab_pte_insert_failure
530         /* Now try secondary slot */
532         /* real page number in r5, PTE RPN value + index */
533         andis.  r0,r31,_PAGE_4K_PFN@h
534         srdi    r5,r31,PTE_RPN_SHIFT
535         bne-    3f
536         sldi    r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
537         add     r5,r5,r25
538 3:      sldi    r5,r5,HW_PAGE_SHIFT
540         /* Calculate secondary group hash */
541         andc    r0,r27,r28
542         rldicr  r3,r0,3,63-3            /* r0 = (~hash & mask) << 3 */
544         /* Call ppc_md.hpte_insert */
545         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
546         mr      r4,r29                  /* Retrieve vpn */
547         li      r7,HPTE_V_SECONDARY     /* !bolted, secondary */
548         li      r8,MMU_PAGE_4K          /* page size */
549         li      r9,MMU_PAGE_4K          /* actual page size */
550         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
551 _GLOBAL(htab_call_hpte_insert2)
552         bl      .                       /* patched by htab_finish_init() */
553         cmpdi   0,r3,0
554         bge+    htab_pte_insert_ok      /* Insertion successful */
555         cmpdi   0,r3,-2                 /* Critical failure */
556         beq-    htab_pte_insert_failure
558         /* Both are full, we need to evict something */
559         mftb    r0
560         /* Pick a random group based on TB */
561         andi.   r0,r0,1
562         mr      r5,r28
563         bne     2f
564         not     r5,r5
565 2:      and     r0,r5,r27
566         rldicr  r3,r0,3,63-3            /* r0 = (hash & mask) << 3 */
567         /* Call ppc_md.hpte_remove */
568 _GLOBAL(htab_call_hpte_remove)
569         bl      .                       /* patched by htab_finish_init() */
571         /* Try all again */
572         b       htab_insert_pte
574         /*
575          * Call out to C code to invalidate an 64k HW HPTE that is
576          * useless now that the segment has been switched to 4k pages.
577          */
578 htab_inval_old_hpte:
579         mr      r3,r29                  /* vpn */
580         mr      r4,r31                  /* PTE.pte */
581         li      r5,0                    /* PTE.hidx */
582         li      r6,MMU_PAGE_64K         /* psize */
583         ld      r7,STK_PARAM(R9)(r1)    /* ssize */
584         ld      r8,STK_PARAM(R8)(r1)    /* local */
585         bl      .flush_hash_page
586         /* Clear out _PAGE_HPTE_SUB bits in the new linux PTE */
587         lis     r0,_PAGE_HPTE_SUB@h
588         ori     r0,r0,_PAGE_HPTE_SUB@l
589         andc    r30,r30,r0
590         b       htab_insert_pte
591         
592 htab_bail_ok:
593         li      r3,0
594         b       htab_bail
596 htab_pte_insert_ok:
597         /* Insert slot number & secondary bit in PTE second half,
598          * clear _PAGE_BUSY and set approriate HPTE slot bit
599          */
600         ld      r6,STK_PARAM(R6)(r1)
601         li      r0,_PAGE_BUSY
602         andc    r30,r30,r0
603         /* HPTE SUB bit */
604         li      r0,1
605         subfic  r5,r25,27               /* Must match bit position in */
606         sld     r0,r0,r5                /* pgtable.h */
607         or      r30,r30,r0
608         /* hindx */
609         sldi    r5,r25,2
610         sld     r3,r3,r5
611         li      r4,0xf
612         sld     r4,r4,r5
613         andc    r26,r26,r4
614         or      r26,r26,r3
615         ori     r5,r6,PTE_PAGE_HIDX_OFFSET
616         std     r26,0(r5)
617         lwsync
618         std     r30,0(r6)
619         li      r3, 0
620 htab_bail:
621         ld      r25,STK_REG(R25)(r1)
622         ld      r26,STK_REG(R26)(r1)
623         ld      r27,STK_REG(R27)(r1)
624         ld      r28,STK_REG(R28)(r1)
625         ld      r29,STK_REG(R29)(r1)
626         ld      r30,STK_REG(R30)(r1)
627         ld      r31,STK_REG(R31)(r1)
628         addi    r1,r1,STACKFRAMESIZE
629         ld      r0,16(r1)
630         mtlr    r0
631         blr
633 htab_modify_pte:
634         /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
635         mr      r4,r3
636         sldi    r5,r25,2
637         srd     r3,r26,r5
639         /* Secondary group ? if yes, get a inverted hash value */
640         mr      r5,r28
641         andi.   r0,r3,0x8 /* page secondary ? */
642         beq     1f
643         not     r5,r5
644 1:      andi.   r3,r3,0x7 /* extract idx alone */
646         /* Calculate proper slot value for ppc_md.hpte_updatepp */
647         and     r0,r5,r27
648         rldicr  r0,r0,3,63-3    /* r0 = (hash & mask) << 3 */
649         add     r3,r0,r3        /* add slot idx */
651         /* Call ppc_md.hpte_updatepp */
652         mr      r5,r29                  /* vpn */
653         li      r6,MMU_PAGE_4K          /* base page size */
654         li      r7,MMU_PAGE_4K          /* actual page size */
655         ld      r8,STK_PARAM(R9)(r1)    /* segment size */
656         ld      r9,STK_PARAM(R8)(r1)    /* get "local" param */
657 _GLOBAL(htab_call_hpte_updatepp)
658         bl      .                       /* patched by htab_finish_init() */
660         /* if we failed because typically the HPTE wasn't really here
661          * we try an insertion.
662          */
663         cmpdi   0,r3,-1
664         beq-    htab_insert_pte
666         /* Clear the BUSY bit and Write out the PTE */
667         li      r0,_PAGE_BUSY
668         andc    r30,r30,r0
669         ld      r6,STK_PARAM(R6)(r1)
670         std     r30,0(r6)
671         li      r3,0
672         b       htab_bail
674 htab_wrong_access:
675         /* Bail out clearing reservation */
676         stdcx.  r31,0,r6
677         li      r3,1
678         b       htab_bail
680 htab_pte_insert_failure:
681         /* Bail out restoring old PTE */
682         ld      r6,STK_PARAM(R6)(r1)
683         std     r31,0(r6)
684         li      r3,-1
685         b       htab_bail
687 #endif /* CONFIG_PPC_64K_PAGES */
689 #ifdef CONFIG_PPC_HAS_HASH_64K
691 /*****************************************************************************
692  *                                                                           *
693  *           64K SW & 64K HW in a 64K segment pages implementation           *
694  *                                                                           *
695  *****************************************************************************/
697 _GLOBAL(__hash_page_64K)
698         mflr    r0
699         std     r0,16(r1)
700         stdu    r1,-STACKFRAMESIZE(r1)
701         /* Save all params that we need after a function call */
702         std     r6,STK_PARAM(R6)(r1)
703         std     r8,STK_PARAM(R8)(r1)
704         std     r9,STK_PARAM(R9)(r1)
706         /* Save non-volatile registers.
707          * r31 will hold "old PTE"
708          * r30 is "new PTE"
709          * r29 is vpn
710          * r28 is a hash value
711          * r27 is hashtab mask (maybe dynamic patched instead ?)
712          */
713         std     r27,STK_REG(R27)(r1)
714         std     r28,STK_REG(R28)(r1)
715         std     r29,STK_REG(R29)(r1)
716         std     r30,STK_REG(R30)(r1)
717         std     r31,STK_REG(R31)(r1)
719         /* Step 1:
720          *
721          * Check permissions, atomically mark the linux PTE busy
722          * and hashed.
723          */
725         ldarx   r31,0,r6
726         /* Check access rights (access & ~(pte_val(*ptep))) */
727         andc.   r0,r4,r31
728         bne-    ht64_wrong_access
729         /* Check if PTE is busy */
730         andi.   r0,r31,_PAGE_BUSY
731         /* If so, just bail out and refault if needed. Someone else
732          * is changing this PTE anyway and might hash it.
733          */
734         bne-    ht64_bail_ok
735 BEGIN_FTR_SECTION
736         /* Check if PTE has the cache-inhibit bit set */
737         andi.   r0,r31,_PAGE_NO_CACHE
738         /* If so, bail out and refault as a 4k page */
739         bne-    ht64_bail_ok
740 END_MMU_FTR_SECTION_IFCLR(MMU_FTR_CI_LARGE_PAGE)
741         /* Prepare new PTE value (turn access RW into DIRTY, then
742          * add BUSY and ACCESSED)
743          */
744         rlwinm  r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */
745         or      r30,r30,r31
746         ori     r30,r30,_PAGE_BUSY | _PAGE_ACCESSED
747         /* Write the linux PTE atomically (setting busy) */
748         stdcx.  r30,0,r6
749         bne-    1b
750         isync
752         /* Step 2:
753          *
754          * Insert/Update the HPTE in the hash table. At this point,
755          * r4 (access) is re-useable, we use it for the new HPTE flags
756          */
758 BEGIN_FTR_SECTION
759         cmpdi   r9,0                    /* check segment size */
760         bne     3f
761 END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
762         /* Calc vpn and put it in r29 */
763         sldi    r29,r5,SID_SHIFT - VPN_SHIFT
764         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
765         or      r29,r28,r29
767         /* Calculate hash value for primary slot and store it in r28
768          * r3 = va, r5 = vsid
769          * r0 = (va >> 16) & ((1ul << (28 - 16)) -1)
770          */
771         rldicl  r0,r3,64-16,52
772         xor     r28,r5,r0               /* hash */
773         b       4f
775 3:      /* Calc vpn and put it in r29 */
776         sldi    r29,r5,SID_SHIFT_1T - VPN_SHIFT
777         rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
778         or      r29,r28,r29
779         /*
780          * calculate hash value for primary slot and
781          * store it in r28 for 1T segment
782          * r3 = va, r5 = vsid
783          */
784         sldi    r28,r5,25               /* vsid << 25 */
785         /* r0 = (va >> 16) & ((1ul << (40 - 16)) -1) */
786         rldicl  r0,r3,64-16,40
787         xor     r28,r28,r5              /* vsid ^ ( vsid << 25) */
788         xor     r28,r28,r0              /* hash */
790         /* Convert linux PTE bits into HW equivalents */
791 4:      andi.   r3,r30,0x1fe            /* Get basic set of flags */
792         xori    r3,r3,HPTE_R_N          /* _PAGE_EXEC -> NOEXEC */
793         rlwinm  r0,r30,32-9+1,30,30     /* _PAGE_RW -> _PAGE_USER (r0) */
794         rlwinm  r4,r30,32-7+1,30,30     /* _PAGE_DIRTY -> _PAGE_USER (r4) */
795         and     r0,r0,r4                /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
796         andc    r0,r30,r0               /* r0 = pte & ~r0 */
797         rlwimi  r3,r0,32-1,31,31        /* Insert result into PP lsb */
798         ori     r3,r3,HPTE_R_C          /* Always add "C" bit for perf. */
800         /* We eventually do the icache sync here (maybe inline that
801          * code rather than call a C function...)
802          */
803 BEGIN_FTR_SECTION
804         mr      r4,r30
805         mr      r5,r7
806         bl      .hash_page_do_lazy_icache
807 END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
809         /* At this point, r3 contains new PP bits, save them in
810          * place of "access" in the param area (sic)
811          */
812         std     r3,STK_PARAM(R4)(r1)
814         /* Get htab_hash_mask */
815         ld      r4,htab_hash_mask@got(2)
816         ld      r27,0(r4)       /* htab_hash_mask -> r27 */
818         /* Check if we may already be in the hashtable, in this case, we
819          * go to out-of-line code to try to modify the HPTE
820          */
821         rldicl. r0,r31,64-12,48
822         bne     ht64_modify_pte
824 ht64_insert_pte:
825         /* Clear hpte bits in new pte (we also clear BUSY btw) and
826          * add _PAGE_HPTE_SUB0
827          */
828         lis     r0,_PAGE_HPTEFLAGS@h
829         ori     r0,r0,_PAGE_HPTEFLAGS@l
830         andc    r30,r30,r0
831 #ifdef CONFIG_PPC_64K_PAGES
832         oris    r30,r30,_PAGE_HPTE_SUB0@h
833 #else
834         ori     r30,r30,_PAGE_HASHPTE
835 #endif
836         /* Phyical address in r5 */
837         rldicl  r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
838         sldi    r5,r5,PAGE_SHIFT
840         /* Calculate primary group hash */
841         and     r0,r28,r27
842         rldicr  r3,r0,3,63-3    /* r0 = (hash & mask) << 3 */
844         /* Call ppc_md.hpte_insert */
845         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
846         mr      r4,r29                  /* Retrieve vpn */
847         li      r7,0                    /* !bolted, !secondary */
848         li      r8,MMU_PAGE_64K
849         li      r9,MMU_PAGE_64K         /* actual page size */
850         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
851 _GLOBAL(ht64_call_hpte_insert1)
852         bl      .                       /* patched by htab_finish_init() */
853         cmpdi   0,r3,0
854         bge     ht64_pte_insert_ok      /* Insertion successful */
855         cmpdi   0,r3,-2                 /* Critical failure */
856         beq-    ht64_pte_insert_failure
858         /* Now try secondary slot */
860         /* Phyical address in r5 */
861         rldicl  r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
862         sldi    r5,r5,PAGE_SHIFT
864         /* Calculate secondary group hash */
865         andc    r0,r27,r28
866         rldicr  r3,r0,3,63-3    /* r0 = (~hash & mask) << 3 */
868         /* Call ppc_md.hpte_insert */
869         ld      r6,STK_PARAM(R4)(r1)    /* Retrieve new pp bits */
870         mr      r4,r29                  /* Retrieve vpn */
871         li      r7,HPTE_V_SECONDARY     /* !bolted, secondary */
872         li      r8,MMU_PAGE_64K
873         li      r9,MMU_PAGE_64K         /* actual page size */
874         ld      r10,STK_PARAM(R9)(r1)   /* segment size */
875 _GLOBAL(ht64_call_hpte_insert2)
876         bl      .                       /* patched by htab_finish_init() */
877         cmpdi   0,r3,0
878         bge+    ht64_pte_insert_ok      /* Insertion successful */
879         cmpdi   0,r3,-2                 /* Critical failure */
880         beq-    ht64_pte_insert_failure
882         /* Both are full, we need to evict something */
883         mftb    r0
884         /* Pick a random group based on TB */
885         andi.   r0,r0,1
886         mr      r5,r28
887         bne     2f
888         not     r5,r5
889 2:      and     r0,r5,r27
890         rldicr  r3,r0,3,63-3    /* r0 = (hash & mask) << 3 */
891         /* Call ppc_md.hpte_remove */
892 _GLOBAL(ht64_call_hpte_remove)
893         bl      .                       /* patched by htab_finish_init() */
895         /* Try all again */
896         b       ht64_insert_pte
898 ht64_bail_ok:
899         li      r3,0
900         b       ht64_bail
902 ht64_pte_insert_ok:
903         /* Insert slot number & secondary bit in PTE */
904         rldimi  r30,r3,12,63-15
906         /* Write out the PTE with a normal write
907          * (maybe add eieio may be good still ?)
908          */
909 ht64_write_out_pte:
910         ld      r6,STK_PARAM(R6)(r1)
911         std     r30,0(r6)
912         li      r3, 0
913 ht64_bail:
914         ld      r27,STK_REG(R27)(r1)
915         ld      r28,STK_REG(R28)(r1)
916         ld      r29,STK_REG(R29)(r1)
917         ld      r30,STK_REG(R30)(r1)
918         ld      r31,STK_REG(R31)(r1)
919         addi    r1,r1,STACKFRAMESIZE
920         ld      r0,16(r1)
921         mtlr    r0
922         blr
924 ht64_modify_pte:
925         /* Keep PP bits in r4 and slot idx from the PTE around in r3 */
926         mr      r4,r3
927         rlwinm  r3,r31,32-12,29,31
929         /* Secondary group ? if yes, get a inverted hash value */
930         mr      r5,r28
931         andi.   r0,r31,_PAGE_F_SECOND
932         beq     1f
933         not     r5,r5
935         /* Calculate proper slot value for ppc_md.hpte_updatepp */
936         and     r0,r5,r27
937         rldicr  r0,r0,3,63-3    /* r0 = (hash & mask) << 3 */
938         add     r3,r0,r3        /* add slot idx */
940         /* Call ppc_md.hpte_updatepp */
941         mr      r5,r29                  /* vpn */
942         li      r6,MMU_PAGE_64K         /* base page size */
943         li      r7,MMU_PAGE_64K         /* actual page size */
944         ld      r8,STK_PARAM(R9)(r1)    /* segment size */
945         ld      r9,STK_PARAM(R8)(r1)    /* get "local" param */
946 _GLOBAL(ht64_call_hpte_updatepp)
947         bl      .                       /* patched by htab_finish_init() */
949         /* if we failed because typically the HPTE wasn't really here
950          * we try an insertion.
951          */
952         cmpdi   0,r3,-1
953         beq-    ht64_insert_pte
955         /* Clear the BUSY bit and Write out the PTE */
956         li      r0,_PAGE_BUSY
957         andc    r30,r30,r0
958         b       ht64_write_out_pte
960 ht64_wrong_access:
961         /* Bail out clearing reservation */
962         stdcx.  r31,0,r6
963         li      r3,1
964         b       ht64_bail
966 ht64_pte_insert_failure:
967         /* Bail out restoring old PTE */
968         ld      r6,STK_PARAM(R6)(r1)
969         std     r31,0(r6)
970         li      r3,-1
971         b       ht64_bail
974 #endif /* CONFIG_PPC_HAS_HASH_64K */
977 /*****************************************************************************
978  *                                                                           *
979  *           Huge pages implementation is in hugetlbpage.c                   *
980  *                                                                           *
981  *****************************************************************************/