diff options
Diffstat (limited to 'arch/cris/arch-v32/mm/mmu.S')
-rw-r--r-- | arch/cris/arch-v32/mm/mmu.S | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/arch/cris/arch-v32/mm/mmu.S b/arch/cris/arch-v32/mm/mmu.S new file mode 100644 index 000000000000..27b70e5006af --- /dev/null +++ b/arch/cris/arch-v32/mm/mmu.S | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2003 Axis Communications AB | ||
3 | * | ||
4 | * Authors: Mikael Starvik (starvik@axis.com) | ||
5 | * | ||
6 | * Code for the fault low-level handling routines. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <asm/page.h> | ||
11 | #include <asm/pgtable.h> | ||
12 | |||
13 | ; Save all register. Must save in same order as struct pt_regs. | ||
14 | .macro SAVE_ALL | ||
15 | subq 12, $sp | ||
16 | move $erp, [$sp] | ||
17 | subq 4, $sp | ||
18 | move $srp, [$sp] | ||
19 | subq 4, $sp | ||
20 | move $ccs, [$sp] | ||
21 | subq 4, $sp | ||
22 | move $spc, [$sp] | ||
23 | subq 4, $sp | ||
24 | move $mof, [$sp] | ||
25 | subq 4, $sp | ||
26 | move $srs, [$sp] | ||
27 | subq 4, $sp | ||
28 | move.d $acr, [$sp] | ||
29 | subq 14*4, $sp | ||
30 | movem $r13, [$sp] | ||
31 | subq 4, $sp | ||
32 | move.d $r10, [$sp] | ||
33 | .endm | ||
34 | |||
35 | ; Bus fault handler. Extracts relevant information and calls mm subsystem | ||
36 | ; to handle the fault. | ||
37 | .macro MMU_BUS_FAULT_HANDLER handler, mmu, we, ex | ||
38 | .globl \handler | ||
39 | \handler: | ||
40 | SAVE_ALL | ||
41 | move \mmu, $srs ; Select MMU support register bank | ||
42 | move.d $sp, $r11 ; regs | ||
43 | moveq 1, $r12 ; protection fault | ||
44 | moveq \we, $r13 ; write exception? | ||
45 | orq \ex << 1, $r13 ; execute? | ||
46 | move $s3, $r10 ; rw_mm_cause | ||
47 | and.d ~8191, $r10 ; Get faulting page start address | ||
48 | |||
49 | jsr do_page_fault | ||
50 | nop | ||
51 | ba ret_from_intr | ||
52 | nop | ||
53 | .endm | ||
54 | |||
55 | ; Refill handler. Three cases may occur: | ||
56 | ; 1. PMD and PTE exists in mm subsystem but not in TLB | ||
57 | ; 2. PMD exists but not PTE | ||
58 | ; 3. PMD doesn't exist | ||
59 | ; The code below handles case 1 and calls the mm subsystem for case 2 and 3. | ||
60 | ; Do not touch this code without very good reasons and extensive testing. | ||
61 | ; Note that the code is optimized to minimize stalls (makes the code harder | ||
62 | ; to read). | ||
63 | ; | ||
64 | ; Each page is 8 KB. Each PMD holds 8192/4 PTEs (each PTE is 4 bytes) so each | ||
65 | ; PMD holds 16 MB of virtual memory. | ||
66 | ; Bits 0-12 : Offset within a page | ||
67 | ; Bits 13-23 : PTE offset within a PMD | ||
68 | ; Bits 24-31 : PMD offset within the PGD | ||
69 | |||
70 | .macro MMU_REFILL_HANDLER handler, mmu | ||
71 | .globl \handler | ||
72 | \handler: | ||
73 | subq 4, $sp | ||
74 | ; (The pipeline stalls for one cycle; $sp used as address in the next cycle.) | ||
75 | move $srs, [$sp] | ||
76 | subq 4, $sp | ||
77 | move \mmu, $srs ; Select MMU support register bank | ||
78 | move.d $acr, [$sp] | ||
79 | subq 4, $sp | ||
80 | move.d $r0, [$sp] | ||
81 | #ifdef CONFIG_SMP | ||
82 | move $s7, $acr ; PGD | ||
83 | #else | ||
84 | move.d per_cpu__current_pgd, $acr ; PGD | ||
85 | #endif | ||
86 | ; Look up PMD in PGD | ||
87 | move $s3, $r0 ; rw_mm_cause | ||
88 | lsrq 24, $r0 ; Get PMD index into PGD (bit 24-31) | ||
89 | move.d [$acr], $acr ; PGD for the current process | ||
90 | addi $r0.d, $acr, $acr | ||
91 | move $s3, $r0 ; rw_mm_cause | ||
92 | move.d [$acr], $acr ; Get PMD | ||
93 | beq 1f | ||
94 | ; Look up PTE in PMD | ||
95 | lsrq PAGE_SHIFT, $r0 | ||
96 | and.w PAGE_MASK, $acr ; Remove PMD flags | ||
97 | and.d 0x7ff, $r0 ; Get PTE index into PMD (bit 13-23) | ||
98 | addi $r0.d, $acr, $acr | ||
99 | move.d [$acr], $acr ; Get PTE | ||
100 | beq 2f | ||
101 | move.d [$sp+], $r0 ; Pop r0 in delayslot | ||
102 | ; Store in TLB | ||
103 | move $acr, $s5 | ||
104 | ; Return | ||
105 | move.d [$sp+], $acr | ||
106 | move [$sp], $srs | ||
107 | addq 4, $sp | ||
108 | rete | ||
109 | rfe | ||
110 | 1: ; PMD missing, let the mm subsystem fix it up. | ||
111 | move.d [$sp+], $r0 ; Pop r0 | ||
112 | 2: ; PTE missing, let the mm subsystem fix it up. | ||
113 | move.d [$sp+], $acr | ||
114 | move [$sp], $srs | ||
115 | addq 4, $sp | ||
116 | SAVE_ALL | ||
117 | move \mmu, $srs | ||
118 | move.d $sp, $r11 ; regs | ||
119 | clear.d $r12 ; Not a protection fault | ||
120 | move.w PAGE_MASK, $acr | ||
121 | move $s3, $r10 ; rw_mm_cause | ||
122 | btstq 9, $r10 ; Check if write access | ||
123 | smi $r13 | ||
124 | and.w PAGE_MASK, $r10 ; Get VPN (virtual address) | ||
125 | jsr do_page_fault | ||
126 | and.w $acr, $r10 | ||
127 | ; Return | ||
128 | ba ret_from_intr | ||
129 | nop | ||
130 | .endm | ||
131 | |||
132 | ; This is the MMU bus fault handlers. | ||
133 | |||
134 | MMU_REFILL_HANDLER i_mmu_refill, 1 | ||
135 | MMU_BUS_FAULT_HANDLER i_mmu_invalid, 1, 0, 0 | ||
136 | MMU_BUS_FAULT_HANDLER i_mmu_access, 1, 0, 0 | ||
137 | MMU_BUS_FAULT_HANDLER i_mmu_execute, 1, 0, 1 | ||
138 | MMU_REFILL_HANDLER d_mmu_refill, 2 | ||
139 | MMU_BUS_FAULT_HANDLER d_mmu_invalid, 2, 0, 0 | ||
140 | MMU_BUS_FAULT_HANDLER d_mmu_access, 2, 0, 0 | ||
141 | MMU_BUS_FAULT_HANDLER d_mmu_write, 2, 1, 0 | ||