]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
43866e37 | 6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
1c79356b | 7 | * |
43866e37 A |
8 | * This file contains Original Code and/or Modifications of Original Code |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14 | * | |
15 | * The Original Code and all software distributed under the License are | |
16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
1c79356b A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
43866e37 A |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
1c79356b A |
22 | * |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | #include <assym.s> | |
26 | #include <debug.h> | |
27 | #include <cpus.h> | |
28 | #include <db_machine_commands.h> | |
29 | #include <mach_rt.h> | |
30 | ||
31 | #include <mach_debug.h> | |
32 | #include <ppc/asm.h> | |
33 | #include <ppc/proc_reg.h> | |
34 | #include <ppc/exception.h> | |
35 | #include <ppc/Performance.h> | |
36 | #include <ppc/exception.h> | |
de355530 | 37 | #include <ppc/pmap_internals.h> |
1c79356b | 38 | #include <mach/ppc/vm_param.h> |
de355530 | 39 | #define PERFTIMES 0 |
1c79356b A |
40 | |
41 | .text | |
42 | ||
de355530 A |
43 | /* |
44 | * | |
45 | * Random notes and musings... | |
46 | * | |
47 | * Access to mappings via the PTEG hash must be done with the list locked. | |
48 | * Access via the physical entries is controlled by the physent lock. | |
49 | * Access to mappings is controlled by the PTEG lock once they are queued. | |
50 | * If they are not on the list, they don't really exist, so | |
51 | * only one processor at a time can find them, so no access control is needed. | |
52 | * | |
53 | * The second half of the PTE is kept in the physical entry. It is done this | |
54 | * way, because there may be multiple mappings that refer to the same physical | |
55 | * page (i.e., address aliases or synonymns). We must do it this way, because | |
56 | * maintenance of the reference and change bits becomes nightmarish if each mapping | |
57 | * has its own. One side effect of this, and not necessarily a bad one, is that | |
58 | * all mappings for a single page can have a single WIMG, protection state, and RC bits. | |
59 | * The only "bad" thing, is the reference bit. With a single copy, we can not get | |
60 | * a completely accurate working set calculation, i.e., we can't tell which mapping was | |
61 | * used to reference the page, all we can tell is that the physical page was | |
62 | * referenced. | |
63 | * | |
64 | * The master copys of the reference and change bits are kept in the phys_entry. | |
65 | * Other than the reference and change bits, changes to the phys_entry are not | |
66 | * allowed if it has any mappings. The master reference and change bits must be | |
67 | * changed via atomic update. | |
68 | * | |
69 | * Invalidating a PTE merges the RC bits into the phys_entry. | |
70 | * | |
71 | * Before checking the reference and/or bits, ALL mappings to the physical page are | |
72 | * invalidated. | |
73 | * | |
74 | * PTEs are never explicitly validated, they are always faulted in. They are also | |
75 | * not visible outside of the hw_vm modules. Complete seperation of church and state. | |
76 | * | |
77 | * Removal of a mapping is invalidates its PTE. | |
78 | * | |
79 | * So, how do we deal with mappings to I/O space? We don't have a physent for it. | |
80 | * Within the mapping is a copy of the second half of the PTE. This is used | |
81 | * ONLY when there is no physical entry. It is swapped into the PTE whenever | |
82 | * it is built. There is no need to swap it back out, because RC is not | |
83 | * maintained for these mappings. | |
84 | * | |
85 | * So, I'm starting to get concerned about the number of lwarx/stcwx loops in | |
86 | * this. Satisfying a mapped address with no stealing requires one lock. If we | |
87 | * steal an entry, there's two locks and an atomic update. Invalidation of an entry | |
88 | * takes one lock and, if there is a PTE, another lock and an atomic update. Other | |
89 | * operations are multiples (per mapping) of the above. Maybe we should look for | |
90 | * an alternative. So far, I haven't found one, but I haven't looked hard. | |
91 | */ | |
1c79356b A |
92 | |
93 | ||
de355530 | 94 | /* hw_add_map(struct mapping *mp, space_t space, vm_offset_t va) - Adds a mapping |
1c79356b | 95 | * |
de355530 | 96 | * Adds a mapping to the PTEG hash list. |
1c79356b | 97 | * |
de355530 A |
98 | * Interrupts must be disabled before calling. |
99 | * | |
100 | * Using the space and the virtual address, we hash into the hash table | |
101 | * and get a lock on the PTEG hash chain. Then we chain the | |
102 | * mapping to the front of the list. | |
1c79356b A |
103 | * |
104 | */ | |
105 | ||
106 | .align 5 | |
107 | .globl EXT(hw_add_map) | |
108 | ||
109 | LEXT(hw_add_map) | |
1c79356b | 110 | |
de355530 A |
111 | #if PERFTIMES && DEBUG |
112 | mr r7,r3 | |
113 | mflr r11 | |
114 | li r3,20 | |
115 | bl EXT(dbgLog2) ; Start of hw_add_map | |
116 | mr r3,r7 | |
117 | mtlr r11 | |
118 | #endif | |
119 | ||
120 | mfmsr r0 /* Get the MSR */ | |
121 | eqv r6,r6,r6 /* Fill the bottom with foxes */ | |
122 | rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
123 | rlwinm r11,r4,6,6,25 /* Position the space for the VSID */ | |
124 | mfspr r10,sdr1 /* Get hash table base and size */ | |
125 | rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
126 | rlwimi r11,r5,30,2,5 /* Insert the segment no. to make a VSID */ | |
127 | mfsprg r12,2 ; Get feature flags | |
128 | rlwimi r6,r10,16,0,15 /* Make table size -1 out of mask */ | |
129 | rlwinm r7,r5,26,10,25 /* Isolate the page index */ | |
130 | or r8,r10,r6 /* Point to the last byte in table */ | |
131 | rlwinm r9,r5,4,0,3 ; Move nybble 1 up to 0 | |
132 | xor r7,r7,r11 /* Get primary hash */ | |
133 | mtcrf 0x04,r12 ; Set the features | |
134 | andi. r12,r0,0x7FCF /* Disable translation and interruptions */ | |
135 | rlwinm r11,r11,1,1,24 /* Position VSID for pte ID */ | |
136 | addi r8,r8,1 /* Point to the PTEG Control Area */ | |
137 | xor r9,r9,r5 ; Splooch vaddr nybble 0 and 1 together | |
138 | and r7,r7,r6 /* Wrap the hash */ | |
139 | rlwimi r11,r5,10,26,31 /* Move API into pte ID */ | |
140 | rlwinm r9,r9,6,27,29 ; Get splooched bits in place | |
141 | add r8,r8,r7 /* Point to our PCA entry */ | |
142 | rlwinm r10,r4,2,27,29 ; Get low 3 bits of the VSID for look-aside hash | |
143 | ||
144 | bt pfNoMSRirb,hamNoMSR ; No MSR... | |
145 | ||
146 | mtmsr r12 ; Translation and all off | |
147 | isync ; Toss prefetch | |
148 | b hamNoMSRx | |
1c79356b | 149 | |
de355530 A |
150 | hamNoMSR: mr r4,r0 ; Save R0 |
151 | mr r2,r3 ; Save | |
152 | li r0,loadMSR ; Get the MSR setter SC | |
153 | mr r3,r12 ; Get new MSR | |
154 | sc ; Set it | |
155 | mr r0,r4 ; Restore | |
156 | mr r3,r2 ; Restore | |
157 | hamNoMSRx: | |
158 | ||
159 | la r4,PCAhash(r8) /* Point to the mapping hash area */ | |
160 | xor r9,r9,r10 ; Finish splooching nybble 0, 1, and the low bits of the VSID | |
161 | isync /* Get rid of anything prefetched before we ref storage */ | |
162 | /* | |
163 | * We've now got the address of our PCA, the hash chain anchor, our API subhash, | |
164 | * and word 0 of the PTE (the virtual part). | |
165 | * | |
166 | * Now, we just lock the PCA. | |
167 | */ | |
d7e50217 | 168 | |
de355530 A |
169 | li r12,1 /* Get the locked value */ |
170 | dcbt 0,r4 /* We'll need the hash area in a sec, so get it */ | |
171 | add r4,r4,r9 /* Point to the right mapping hash slot */ | |
172 | ||
173 | ptegLckx: lwarx r10,0,r8 /* Get the PTEG lock */ | |
174 | mr. r10,r10 /* Is it locked? */ | |
175 | bne- ptegLckwx /* Yeah... */ | |
176 | stwcx. r12,0,r8 /* Take take it */ | |
177 | bne- ptegLckx /* Someone else was trying, try again... */ | |
178 | b ptegSXgx /* All done... */ | |
179 | ||
180 | .align 4 | |
181 | ||
182 | ptegLckwx: mr. r10,r10 /* Check if it's already held */ | |
183 | beq+ ptegLckx /* It's clear... */ | |
184 | lwz r10,0(r8) /* Get lock word again... */ | |
185 | b ptegLckwx /* Wait... */ | |
186 | ||
187 | .align 4 | |
188 | ||
189 | ptegSXgx: isync /* Make sure we haven't used anything yet */ | |
190 | ||
191 | lwz r7,0(r4) /* Pick up the anchor of hash list */ | |
192 | stw r3,0(r4) /* Save the new head */ | |
193 | stw r7,mmhashnext(r3) /* Chain in the old head */ | |
194 | ||
195 | stw r4,mmPTEhash(r3) /* Point to the head of the hash list */ | |
196 | ||
197 | sync /* Make sure the chain is updated */ | |
198 | stw r10,0(r8) /* Unlock the hash list */ | |
199 | mtmsr r0 /* Restore translation and interruptions */ | |
200 | isync /* Toss anything done with DAT off */ | |
201 | #if PERFTIMES && DEBUG | |
202 | mflr r11 | |
203 | mr r4,r3 | |
204 | li r3,21 | |
205 | bl EXT(dbgLog2) ; end of hw_add_map | |
206 | mr r3,r4 | |
207 | mtlr r11 | |
208 | #endif | |
209 | blr /* Leave... */ | |
210 | ||
211 | ||
212 | /* mp=hw_lock_phys_vir(space, va) - Finds and locks a physical entry by vaddr. | |
213 | * | |
214 | * Returns the mapping with the associated physent locked if found, or a | |
215 | * zero and no lock if not. It we timed out trying to get a the lock on | |
216 | * the physical entry, we retun a 1. A physical entry can never be on an | |
217 | * odd boundary, so we can distinguish between a mapping and a timeout code. | |
218 | * | |
219 | * Interrupts must be disabled before calling. | |
220 | * | |
221 | * Using the space and the virtual address, we hash into the hash table | |
222 | * and get a lock on the PTEG hash chain. Then we search the chain for the | |
223 | * mapping for our virtual address. From there, we extract the pointer to | |
224 | * the physical entry. | |
225 | * | |
226 | * Next comes a bit of monkey business. we need to get a lock on the physical | |
227 | * entry. But, according to our rules, we can't get it after we've gotten the | |
228 | * PTEG hash lock, we could deadlock if we do. So, we need to release the | |
229 | * hash lock. The problem is, though, that as soon as we release it, some | |
230 | * other yahoo may remove our mapping between the time that we release the | |
231 | * hash lock and obtain the phys entry lock. So, we can't count on the | |
232 | * mapping once we release the lock. Instead, after we lock the phys entry, | |
233 | * we search the mapping list (phys_link) for our translation. If we don't find it, | |
234 | * we unlock the phys entry, bail out, and return a 0 for the mapping address. If we | |
235 | * did find it, we keep the lock and return the address of the mapping block. | |
236 | * | |
237 | * What happens when a mapping is found, but there is no physical entry? | |
238 | * This is what happens when there is I/O area mapped. It one of these mappings | |
239 | * is found, the mapping is returned, as is usual for this call, but we don't | |
240 | * try to lock anything. There could possibly be some problems here if another | |
241 | * processor releases the mapping while we still alre using it. Hope this | |
242 | * ain't gonna happen. | |
243 | * | |
244 | * Taaa-dahhh! Easy as pie, huh? | |
245 | * | |
246 | * So, we have a few hacks hacks for running translate off in here. | |
247 | * First, when we call the lock routine, we have carnel knowlege of the registers is uses. | |
248 | * That way, we don't need a stack frame, which we can't have 'cause the stack is in | |
249 | * virtual storage. But wait, as if that's not enough... We need one more register. So, | |
250 | * we cram the LR into the CTR and return from there. | |
251 | * | |
252 | */ | |
253 | .align 5 | |
254 | .globl EXT(hw_lock_phys_vir) | |
255 | ||
256 | LEXT(hw_lock_phys_vir) | |
257 | ||
258 | #if PERFTIMES && DEBUG | |
259 | mflr r11 | |
260 | mr r5,r3 | |
261 | li r3,22 | |
262 | bl EXT(dbgLog2) ; Start of hw_add_map | |
263 | mr r3,r5 | |
264 | mtlr r11 | |
265 | #endif | |
266 | mfmsr r12 /* Get the MSR */ | |
267 | eqv r6,r6,r6 /* Fill the bottom with foxes */ | |
268 | mfsprg r9,2 ; Get feature flags | |
269 | rlwinm r11,r3,6,6,25 /* Position the space for the VSID */ | |
270 | rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
271 | mfspr r5,sdr1 /* Get hash table base and size */ | |
272 | rlwimi r11,r4,30,2,5 /* Insert the segment no. to make a VSID */ | |
273 | mtcrf 0x04,r9 ; Set the features | |
274 | rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
275 | rlwimi r6,r5,16,0,15 /* Make table size -1 out of mask */ | |
276 | andi. r0,r12,0x7FCF /* Disable translation and interruptions */ | |
277 | rlwinm r9,r4,4,0,3 ; Move nybble 1 up to 0 | |
278 | rlwinm r7,r4,26,10,25 /* Isolate the page index */ | |
279 | or r8,r5,r6 /* Point to the last byte in table */ | |
280 | xor r7,r7,r11 /* Get primary hash */ | |
281 | rlwinm r11,r11,1,1,24 /* Position VSID for pte ID */ | |
282 | addi r8,r8,1 /* Point to the PTEG Control Area */ | |
283 | xor r9,r9,r4 ; Splooch vaddr nybble 0 and 1 together | |
284 | and r7,r7,r6 /* Wrap the hash */ | |
285 | rlwimi r11,r4,10,26,31 /* Move API into pte ID */ | |
286 | rlwinm r9,r9,6,27,29 ; Get splooched bits in place | |
287 | add r8,r8,r7 /* Point to our PCA entry */ | |
288 | rlwinm r10,r3,2,27,29 ; Get low 3 bits of the VSID for look-aside hash | |
289 | ||
290 | bt pfNoMSRirb,hlpNoMSR ; No MSR... | |
291 | ||
292 | mtmsr r0 ; Translation and all off | |
293 | isync ; Toss prefetch | |
294 | b hlpNoMSRx | |
1c79356b | 295 | |
de355530 A |
296 | hlpNoMSR: mr r3,r0 ; Get the new MSR |
297 | li r0,loadMSR ; Get the MSR setter SC | |
298 | sc ; Set it | |
299 | hlpNoMSRx: | |
300 | ||
301 | la r3,PCAhash(r8) /* Point to the mapping hash area */ | |
302 | xor r9,r9,r10 ; Finish splooching nybble 0, 1, and the low bits of the VSID | |
303 | isync /* Make sure translation is off before we ref storage */ | |
304 | ||
305 | /* | |
306 | * We've now got the address of our PCA, the hash chain anchor, our API subhash, | |
307 | * and word 0 of the PTE (the virtual part). | |
308 | * | |
309 | * Now, we just lock the PCA and find our mapping, if it exists. | |
310 | */ | |
d7e50217 | 311 | |
de355530 A |
312 | dcbt 0,r3 /* We'll need the hash area in a sec, so get it */ |
313 | add r3,r3,r9 /* Point to the right mapping hash slot */ | |
1c79356b | 314 | |
de355530 A |
315 | ptegLcka: lwarx r10,0,r8 /* Get the PTEG lock */ |
316 | li r5,1 /* Get the locked value */ | |
317 | mr. r10,r10 /* Is it locked? */ | |
318 | bne- ptegLckwa /* Yeah... */ | |
319 | stwcx. r5,0,r8 /* Take take it */ | |
320 | bne- ptegLcka /* Someone else was trying, try again... */ | |
321 | b ptegSXga /* All done... */ | |
1c79356b | 322 | |
de355530 | 323 | .align 4 |
1c79356b | 324 | |
de355530 A |
325 | ptegLckwa: mr. r10,r10 /* Check if it's already held */ |
326 | beq+ ptegLcka /* It's clear... */ | |
327 | lwz r10,0(r8) /* Get lock word again... */ | |
328 | b ptegLckwa /* Wait... */ | |
1c79356b | 329 | |
de355530 | 330 | .align 4 |
1c79356b | 331 | |
de355530 | 332 | ptegSXga: isync /* Make sure we haven't used anything yet */ |
1c79356b | 333 | |
de355530 A |
334 | mflr r0 /* Get the LR */ |
335 | lwz r9,0(r3) /* Pick up the first mapping block */ | |
336 | mtctr r0 /* Stuff it into the CTR */ | |
1c79356b | 337 | |
de355530 | 338 | findmapa: |
1c79356b | 339 | |
de355530 A |
340 | mr. r3,r9 /* Did we hit the end? */ |
341 | bne+ chkmapa /* Nope... */ | |
342 | ||
343 | stw r3,0(r8) /* Unlock the PTEG lock | |
344 | Note: we never saved anything while we | |
345 | had the lock, so we don't need a sync | |
346 | before we unlock it */ | |
1c79356b | 347 | |
de355530 A |
348 | vbail: mtmsr r12 /* Restore translation and interruptions */ |
349 | isync /* Make sure translation is cool */ | |
350 | #if PERFTIMES && DEBUG | |
351 | mflr r11 | |
352 | mr r4,r3 | |
353 | li r3,23 | |
354 | bl EXT(dbgLog2) ; Start of hw_add_map | |
355 | mr r3,r4 | |
356 | mtlr r11 | |
357 | #endif | |
358 | bctr /* Return in abject failure... */ | |
359 | ||
360 | .align 4 | |
361 | ||
362 | chkmapa: lwz r10,mmPTEv(r3) /* Pick up our virtual ID */ | |
363 | lwz r9,mmhashnext(r3) /* Pick up next mapping block */ | |
364 | cmplw r10,r11 /* Have we found ourself? */ | |
365 | bne- findmapa /* Nope, still wandering... */ | |
366 | ||
367 | lwz r9,mmphysent(r3) /* Get our physical entry pointer */ | |
368 | li r5,0 /* Clear this out */ | |
369 | mr. r9,r9 /* Is there, like, a physical entry? */ | |
370 | stw r5,0(r8) /* Unlock the PTEG lock | |
371 | Note: we never saved anything while we | |
372 | had the lock, so we don't need a sync | |
373 | before we unlock it */ | |
374 | ||
375 | beq- vbail /* If there is no physical entry, it's time | |
376 | to leave... */ | |
377 | ||
378 | /* Here we want to call hw_lock_bit. We don't want to use the stack, 'cause it's | |
379 | * in virtual storage, and we're in real. So, we've carefully looked at the code | |
380 | * in hw_lock_bit (and unlock) and cleverly don't use any of the registers that it uses. | |
381 | * Be very, very aware of how you change this code. By the way, it uses: | |
382 | * R0, R6, R7, R8, and R9. R3, R4, and R5 contain parameters | |
383 | * Unfortunatly, we need to stash R9 still. So... Since we know we will not be interrupted | |
384 | * ('cause we turned off interruptions and translation is off) we will use SPRG3... | |
385 | */ | |
386 | ||
387 | lwz r10,mmPTEhash(r3) /* Save the head of the hash-alike chain. We need it to find ourselves later */ | |
388 | lis r5,HIGH_ADDR(EXT(LockTimeOut)) /* Get address of timeout value */ | |
389 | la r3,pephyslink(r9) /* Point to the lock word */ | |
390 | ori r5,r5,LOW_ADDR(EXT(LockTimeOut)) /* Get second half of address */ | |
391 | li r4,PHYS_LOCK /* Get the lock bit value */ | |
392 | lwz r5,0(r5) /* Pick up the timeout value */ | |
393 | mtsprg 3,r9 /* Save R9 in SPRG3 */ | |
1c79356b | 394 | |
de355530 | 395 | bl EXT(hw_lock_bit) /* Go do the lock */ |
1c79356b | 396 | |
de355530 A |
397 | mfsprg r9,3 /* Restore pointer to the phys_entry */ |
398 | mr. r3,r3 /* Did we timeout? */ | |
399 | lwz r4,pephyslink(r9) /* Pick up first mapping block */ | |
400 | beq- penterr /* Bad deal, we timed out... */ | |
1c79356b | 401 | |
de355530 | 402 | rlwinm r4,r4,0,0,26 ; Clear out the flags from first link |
1c79356b | 403 | |
de355530 A |
404 | findmapb: mr. r3,r4 /* Did we hit the end? */ |
405 | bne+ chkmapb /* Nope... */ | |
d7e50217 | 406 | |
de355530 A |
407 | la r3,pephyslink(r9) /* Point to where the lock is */ |
408 | li r4,PHYS_LOCK /* Get the lock bit value */ | |
409 | bl EXT(hw_unlock_bit) /* Go unlock the physentry */ | |
d7e50217 | 410 | |
de355530 A |
411 | li r3,0 /* Say we failed */ |
412 | b vbail /* Return in abject failure... */ | |
413 | ||
414 | penterr: li r3,1 /* Set timeout */ | |
415 | b vbail /* Return in abject failure... */ | |
416 | ||
417 | .align 5 | |
d7e50217 | 418 | |
de355530 A |
419 | chkmapb: lwz r6,mmPTEv(r3) /* Pick up our virtual ID */ |
420 | lwz r4,mmnext(r3) /* Pick up next mapping block */ | |
421 | cmplw r6,r11 /* Have we found ourself? */ | |
422 | lwz r5,mmPTEhash(r3) /* Get the start of our hash chain */ | |
423 | bne- findmapb /* Nope, still wandering... */ | |
424 | cmplw r5,r10 /* On the same hash chain? */ | |
425 | bne- findmapb /* Nope, keep looking... */ | |
1c79356b | 426 | |
de355530 | 427 | b vbail /* Return in glorious triumph... */ |
1c79356b A |
428 | |
429 | ||
430 | /* | |
de355530 | 431 | * hw_rem_map(mapping) - remove a mapping from the system. |
1c79356b | 432 | * |
de355530 A |
433 | * Upon entry, R3 contains a pointer to a mapping block and the associated |
434 | * physical entry is locked if there is one. | |
435 | * | |
436 | * If the mapping entry indicates that there is a PTE entry, we invalidate | |
437 | * if and merge the reference and change information into the phys_entry. | |
1c79356b | 438 | * |
de355530 | 439 | * Next, we remove the mapping from the phys_ent and the PTEG hash list. |
1c79356b | 440 | * |
de355530 | 441 | * Unlock any locks that are left, and exit. |
1c79356b A |
442 | * |
443 | * Note that this must be done with both interruptions off and VM off | |
444 | * | |
de355530 A |
445 | * Note that this code depends upon the VSID being of the format 00SXXXXX |
446 | * where S is the segment number. | |
447 | * | |
448 | * | |
1c79356b A |
449 | */ |
450 | ||
451 | .align 5 | |
452 | .globl EXT(hw_rem_map) | |
453 | ||
454 | LEXT(hw_rem_map) | |
de355530 A |
455 | #if PERFTIMES && DEBUG |
456 | mflr r11 | |
457 | mr r4,r3 | |
458 | li r3,24 | |
459 | bl EXT(dbgLog2) ; Start of hw_add_map | |
460 | mr r3,r4 | |
461 | mtlr r11 | |
462 | #endif | |
463 | mfsprg r9,2 ; Get feature flags | |
464 | mfmsr r0 /* Save the MSR */ | |
465 | rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
466 | rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
467 | rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ | |
468 | mtcrf 0x04,r9 ; Set the features | |
469 | rlwinm r12,r12,0,28,25 /* Clear IR and DR */ | |
1c79356b | 470 | |
de355530 A |
471 | bt pfNoMSRirb,lmvNoMSR ; No MSR... |
472 | ||
473 | mtmsr r12 ; Translation and all off | |
474 | isync ; Toss prefetch | |
475 | b lmvNoMSRx | |
476 | ||
477 | lmvNoMSR: | |
478 | mr r6,r0 | |
479 | mr r4,r3 | |
480 | li r0,loadMSR ; Get the MSR setter SC | |
481 | mr r3,r12 ; Get new MSR | |
482 | sc ; Set it | |
483 | mr r3,r4 | |
484 | mr r0,r6 | |
1c79356b | 485 | |
de355530 | 486 | lmvNoMSRx: |
1c79356b | 487 | |
de355530 A |
488 | |
489 | lwz r6,mmPTEhash(r3) /* Get pointer to hash list anchor */ | |
490 | lwz r5,mmPTEv(r3) /* Get the VSID */ | |
491 | dcbt 0,r6 /* We'll need that chain in a bit */ | |
1c79356b | 492 | |
de355530 A |
493 | rlwinm r7,r6,0,0,25 /* Round hash list down to PCA boundary */ |
494 | li r12,1 /* Get the locked value */ | |
495 | subi r6,r6,mmhashnext /* Make the anchor look like an entry */ | |
1c79356b | 496 | |
de355530 A |
497 | ptegLck1: lwarx r10,0,r7 /* Get the PTEG lock */ |
498 | mr. r10,r10 /* Is it locked? */ | |
499 | bne- ptegLckw1 /* Yeah... */ | |
500 | stwcx. r12,0,r7 /* Try to take it */ | |
501 | bne- ptegLck1 /* Someone else was trying, try again... */ | |
502 | b ptegSXg1 /* All done... */ | |
1c79356b | 503 | |
de355530 | 504 | .align 4 |
1c79356b | 505 | |
de355530 A |
506 | ptegLckw1: mr. r10,r10 /* Check if it's already held */ |
507 | beq+ ptegLck1 /* It's clear... */ | |
508 | lwz r10,0(r7) /* Get lock word again... */ | |
509 | b ptegLckw1 /* Wait... */ | |
1c79356b | 510 | |
de355530 | 511 | .align 4 |
d7e50217 | 512 | |
de355530 A |
513 | ptegSXg1: isync /* Make sure we haven't used anything yet */ |
514 | ||
515 | lwz r12,mmhashnext(r3) /* Prime with our forward pointer */ | |
516 | lwz r4,mmPTEent(r3) /* Get the pointer to the PTE now that the lock's set */ | |
d7e50217 | 517 | |
de355530 A |
518 | srchmaps: mr. r10,r6 /* Save the previous entry */ |
519 | bne+ mapok /* No error... */ | |
1c79356b | 520 | |
de355530 A |
521 | lis r0,HIGH_ADDR(Choke) /* We have a kernel choke!!! */ |
522 | ori r0,r0,LOW_ADDR(Choke) | |
523 | sc /* Firmware Heimlich manuever */ | |
1c79356b | 524 | |
de355530 | 525 | .align 4 |
1c79356b | 526 | |
de355530 A |
527 | mapok: lwz r6,mmhashnext(r6) /* Look at the next one */ |
528 | cmplwi cr5,r4,0 /* Is there a PTE? */ | |
529 | cmplw r6,r3 /* Have we found ourselves? */ | |
530 | bne+ srchmaps /* Nope, get your head together... */ | |
1c79356b | 531 | |
de355530 A |
532 | stw r12,mmhashnext(r10) /* Remove us from the queue */ |
533 | rlwinm r9,r5,1,0,3 /* Move in the segment */ | |
534 | rlwinm r8,r4,6,4,19 /* Line PTEG disp up to a page */ | |
535 | rlwinm r11,r5,5,4,19 /* Line up the VSID */ | |
536 | lwz r10,mmphysent(r3) /* Point to the physical entry */ | |
537 | ||
538 | beq+ cr5,nopte /* There's no PTE to invalidate... */ | |
1c79356b | 539 | |
de355530 A |
540 | xor r8,r8,r11 /* Back hash to virt index */ |
541 | lis r12,HIGH_ADDR(EXT(tlb_system_lock)) /* Get the TLBIE lock */ | |
542 | rlwimi r9,r5,22,4,9 /* Move in the API */ | |
543 | ori r12,r12,LOW_ADDR(EXT(tlb_system_lock)) /* Grab up the bottom part */ | |
544 | mfspr r11,pvr /* Find out what kind of machine we are */ | |
545 | rlwimi r9,r8,0,10,19 /* Create the virtual address */ | |
546 | rlwinm r11,r11,16,16,31 /* Isolate CPU type */ | |
1c79356b | 547 | |
de355530 | 548 | stw r5,0(r4) /* Make the PTE invalid */ |
1c79356b | 549 | |
de355530 A |
550 | cmplwi cr1,r11,3 /* Is this a 603? */ |
551 | sync /* Make sure the invalid is stored */ | |
552 | ||
553 | tlbhang1: lwarx r5,0,r12 /* Get the TLBIE lock */ | |
554 | rlwinm r11,r4,29,29,31 /* Get the bit position of entry */ | |
555 | mr. r5,r5 /* Is it locked? */ | |
556 | lis r6,0x8000 /* Start up a bit mask */ | |
557 | li r5,1 /* Get our lock word */ | |
558 | bne- tlbhang1 /* It's locked, go wait... */ | |
559 | stwcx. r5,0,r12 /* Try to get it */ | |
560 | bne- tlbhang1 /* We was beat... */ | |
1c79356b | 561 | |
de355530 A |
562 | srw r6,r6,r11 /* Make a "free slot" mask */ |
563 | lwz r5,PCAallo(r7) /* Get the allocation control bits */ | |
564 | rlwinm r11,r6,24,8,15 /* Make the autogen bit to turn off */ | |
565 | or r5,r5,r6 /* turn on the free bit */ | |
566 | rlwimi r11,r11,24,16,23 /* Get lock bit mask to turn it off */ | |
1c79356b | 567 | |
de355530 A |
568 | andc r5,r5,r11 /* Turn off the lock and autogen bits in allocation flags */ |
569 | li r11,0 /* Lock clear value */ | |
1c79356b | 570 | |
de355530 | 571 | tlbie r9 /* Invalidate it everywhere */ |
1c79356b | 572 | |
1c79356b | 573 | |
de355530 A |
574 | beq- cr1,its603a /* It's a 603, skip the tlbsync... */ |
575 | ||
576 | eieio /* Make sure that the tlbie happens first */ | |
577 | tlbsync /* wait for everyone to catch up */ | |
578 | isync | |
579 | ||
580 | its603a: sync /* Make sure of it all */ | |
581 | stw r11,0(r12) /* Clear the tlbie lock */ | |
582 | eieio /* Make sure those RC bit are loaded */ | |
583 | stw r5,PCAallo(r7) /* Show that the slot is free */ | |
584 | stw r11,mmPTEent(r3) /* Clear the pointer to the PTE */ | |
9bccf70c | 585 | |
de355530 A |
586 | nopte: mr. r10,r10 /* See if there is a physical entry */ |
587 | la r9,pephyslink(r10) /* Point to the physical mapping chain */ | |
588 | beq- nophys /* No physical entry, we're done... */ | |
589 | beq- cr5,nadamrg /* No PTE to merge... */ | |
d7e50217 | 590 | |
de355530 A |
591 | lwz r6,4(r4) /* Get the latest reference and change bits */ |
592 | la r12,pepte1(r10) /* Point right at the master copy */ | |
593 | rlwinm r6,r6,0,23,24 /* Extract just the RC bits */ | |
d7e50217 | 594 | |
de355530 A |
595 | mrgrc: lwarx r8,0,r12 /* Get the master copy */ |
596 | or r8,r8,r6 /* Merge in latest RC */ | |
597 | stwcx. r8,0,r12 /* Save it back */ | |
598 | bne- mrgrc /* If it changed, try again... */ | |
d7e50217 | 599 | |
de355530 A |
600 | nadamrg: li r11,0 /* Clear this out */ |
601 | lwz r12,mmnext(r3) /* Prime with our next */ | |
1c79356b | 602 | |
de355530 A |
603 | sync ; Make sure all is saved |
604 | ||
605 | stw r11,0(r7) /* Unlock the hash chain now so we don't | |
606 | lock out another processor during | |
607 | our next little search */ | |
d7e50217 | 608 | |
de355530 A |
609 | srchpmap: mr. r10,r9 /* Save the previous entry */ |
610 | bne+ mapok1 /* No error... */ | |
d7e50217 | 611 | |
de355530 A |
612 | lis r0,HIGH_ADDR(Choke) /* We have a kernel choke!!! */ |
613 | ori r0,r0,LOW_ADDR(Choke) | |
614 | sc /* Firmware Heimlich maneuver */ | |
d7e50217 | 615 | |
de355530 | 616 | .align 4 |
d7e50217 | 617 | |
de355530 A |
618 | mapok1: lwz r9,mmnext(r9) /* Look at the next one */ |
619 | rlwinm r8,r9,0,27,31 ; Save the flags (including the lock) | |
620 | rlwinm r9,r9,0,0,26 ; Clear out the flags from first link | |
621 | cmplw r9,r3 /* Have we found ourselves? */ | |
622 | bne+ srchpmap /* Nope, get your head together... */ | |
d7e50217 | 623 | |
de355530 A |
624 | rlwimi r12,r8,0,27,31 ; Insert the lock and flags */ |
625 | stw r12,mmnext(r10) /* Remove us from the queue */ | |
626 | ||
627 | mtmsr r0 /* Interrupts and translation back on */ | |
628 | isync | |
629 | #if PERFTIMES && DEBUG | |
630 | mflr r11 | |
631 | li r3,25 | |
632 | bl EXT(dbgLog2) ; Start of hw_add_map | |
633 | mtlr r11 | |
634 | #endif | |
635 | blr /* Return... */ | |
1c79356b | 636 | |
de355530 | 637 | .align 4 |
1c79356b | 638 | |
de355530 A |
639 | nophys: li r4,0 /* Make sure this is 0 */ |
640 | sync /* Make sure that chain is updated */ | |
641 | stw r4,0(r7) /* Unlock the hash chain */ | |
642 | mtmsr r0 /* Interrupts and translation back on */ | |
1c79356b | 643 | isync |
de355530 A |
644 | #if PERFTIMES && DEBUG |
645 | mflr r11 | |
646 | li r3,25 | |
647 | bl EXT(dbgLog2) ; Start of hw_add_map | |
648 | mtlr r11 | |
649 | #endif | |
650 | blr /* Return... */ | |
1c79356b | 651 | |
de355530 A |
652 | |
653 | /* | |
654 | * hw_prot(physent, prot) - Change the protection of a physical page | |
655 | * | |
656 | * Upon entry, R3 contains a pointer to a physical entry which is locked. | |
657 | * R4 contains the PPC protection bits. | |
658 | * | |
659 | * The first thing we do is to slam the new protection into the phys entry. | |
660 | * Then we scan the mappings and process each one. | |
661 | * | |
662 | * Acquire the lock on the PTEG hash list for the mapping being processed. | |
663 | * | |
664 | * If the current mapping has a PTE entry, we invalidate | |
665 | * it and merge the reference and change information into the phys_entry. | |
666 | * | |
667 | * Next, slam the protection bits into the entry and unlock the hash list. | |
668 | * | |
669 | * Note that this must be done with both interruptions off and VM off | |
670 | * | |
671 | * | |
672 | */ | |
1c79356b A |
673 | |
674 | .align 5 | |
de355530 | 675 | .globl EXT(hw_prot) |
1c79356b | 676 | |
de355530 A |
677 | LEXT(hw_prot) |
678 | #if PERFTIMES && DEBUG | |
679 | mflr r11 | |
680 | mr r7,r3 | |
681 | // lwz r5,4(r3) | |
682 | li r5,0x1111 | |
683 | li r3,26 | |
684 | bl EXT(dbgLog2) ; Start of hw_add_map | |
685 | mr r3,r7 | |
686 | mtlr r11 | |
687 | #endif | |
688 | mfsprg r9,2 ; Get feature flags | |
689 | mfmsr r0 /* Save the MSR */ | |
690 | li r5,pepte1 /* Get displacement to the second word of master pte */ | |
691 | rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
692 | rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
693 | rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ | |
694 | mtcrf 0x04,r9 ; Set the features | |
695 | rlwinm r12,r12,0,28,25 /* Clear IR and DR */ | |
696 | ||
697 | bt pfNoMSRirb,hpNoMSR ; No MSR... | |
698 | ||
699 | mtmsr r12 ; Translation and all off | |
700 | isync ; Toss prefetch | |
701 | b hpNoMSRx | |
d7e50217 | 702 | |
de355530 A |
703 | hpNoMSR: |
704 | mr r10,r0 | |
705 | mr r7,r3 | |
706 | li r0,loadMSR ; Get the MSR setter SC | |
707 | mr r3,r12 ; Get new MSR | |
708 | sc ; Set it | |
709 | mr r0,r10 | |
710 | mr r3,r7 | |
711 | hpNoMSRx: | |
1c79356b A |
712 | |
713 | ||
714 | ||
de355530 A |
715 | lwz r10,pephyslink(r3) /* Get the first mapping block */ |
716 | rlwinm r10,r10,0,0,26 ; Clear out the flags from first link | |
1c79356b | 717 | |
de355530 A |
718 | /* |
719 | * Note that we need to to do the interlocked update here because another processor | |
720 | * can be updating the reference and change bits even though the physical entry | |
721 | * is locked. All modifications to the PTE portion of the physical entry must be | |
722 | * done via interlocked update. | |
723 | */ | |
d7e50217 | 724 | |
de355530 A |
725 | protcng: lwarx r8,r5,r3 /* Get the master copy */ |
726 | rlwimi r8,r4,0,30,31 /* Move in the protection bits */ | |
727 | stwcx. r8,r5,r3 /* Save it back */ | |
728 | bne- protcng /* If it changed, try again... */ | |
1c79356b A |
729 | |
730 | ||
731 | ||
de355530 A |
732 | protnext: mr. r10,r10 /* Are there any more mappings? */ |
733 | beq- protdone /* Naw... */ | |
1c79356b | 734 | |
de355530 A |
735 | lwz r7,mmPTEhash(r10) /* Get pointer to hash list anchor */ |
736 | lwz r5,mmPTEv(r10) /* Get the virtual address */ | |
737 | rlwinm r7,r7,0,0,25 /* Round hash list down to PCA boundary */ | |
1c79356b | 738 | |
de355530 | 739 | li r12,1 /* Get the locked value */ |
1c79356b | 740 | |
de355530 A |
741 | protLck1: lwarx r11,0,r7 /* Get the PTEG lock */ |
742 | mr. r11,r11 /* Is it locked? */ | |
743 | bne- protLckw1 /* Yeah... */ | |
744 | stwcx. r12,0,r7 /* Try to take it */ | |
745 | bne- protLck1 /* Someone else was trying, try again... */ | |
746 | b protSXg1 /* All done... */ | |
747 | ||
748 | .align 4 | |
1c79356b | 749 | |
de355530 A |
750 | protLckw1: mr. r11,r11 /* Check if it's already held */ |
751 | beq+ protLck1 /* It's clear... */ | |
752 | lwz r11,0(r7) /* Get lock word again... */ | |
753 | b protLckw1 /* Wait... */ | |
754 | ||
755 | .align 4 | |
1c79356b | 756 | |
de355530 | 757 | protSXg1: isync /* Make sure we haven't used anything yet */ |
1c79356b | 758 | |
de355530 | 759 | lwz r6,mmPTEent(r10) /* Get the pointer to the PTE now that the lock's set */ |
1c79356b | 760 | |
de355530 A |
761 | rlwinm r9,r5,1,0,3 /* Move in the segment */ |
762 | lwz r2,mmPTEr(r10) ; Get the mapping copy of the PTE | |
763 | mr. r6,r6 /* See if there is a PTE here */ | |
764 | rlwinm r8,r5,31,2,25 /* Line it up */ | |
765 | rlwimi r2,r4,0,30,31 ; Move protection bits into the mapping copy | |
766 | ||
767 | beq+ protul /* There's no PTE to invalidate... */ | |
768 | ||
769 | xor r8,r8,r6 /* Back hash to virt index */ | |
770 | rlwimi r9,r5,22,4,9 /* Move in the API */ | |
771 | lis r12,HIGH_ADDR(EXT(tlb_system_lock)) /* Get the TLBIE lock */ | |
772 | rlwinm r5,r5,0,1,31 /* Clear the valid bit */ | |
773 | ori r12,r12,LOW_ADDR(EXT(tlb_system_lock)) /* Grab up the bottom part */ | |
774 | mfspr r11,pvr /* Find out what kind of machine we are */ | |
775 | rlwimi r9,r8,6,10,19 /* Create the virtual address */ | |
776 | rlwinm r11,r11,16,16,31 /* Isolate CPU type */ | |
777 | ||
778 | stw r5,0(r6) /* Make the PTE invalid */ | |
779 | cmplwi cr1,r11,3 /* Is this a 603? */ | |
780 | sync /* Make sure the invalid is stored */ | |
781 | ||
782 | tlbhangp: lwarx r11,0,r12 /* Get the TLBIE lock */ | |
783 | rlwinm r8,r6,29,29,31 /* Get the bit position of entry */ | |
784 | mr. r11,r11 /* Is it locked? */ | |
785 | lis r5,0x8000 /* Start up a bit mask */ | |
786 | li r11,1 /* Get our lock word */ | |
787 | bne- tlbhangp /* It's locked, go wait... */ | |
788 | stwcx. r11,0,r12 /* Try to get it */ | |
789 | bne- tlbhangp /* We was beat... */ | |
790 | ||
791 | li r11,0 /* Lock clear value */ | |
1c79356b | 792 | |
de355530 | 793 | tlbie r9 /* Invalidate it everywhere */ |
1c79356b | 794 | |
de355530 A |
795 | beq- cr1,its603p /* It's a 603, skip the tlbsync... */ |
796 | ||
797 | eieio /* Make sure that the tlbie happens first */ | |
798 | tlbsync /* wait for everyone to catch up */ | |
799 | isync | |
800 | ||
801 | its603p: stw r11,0(r12) /* Clear the lock */ | |
802 | srw r5,r5,r8 /* Make a "free slot" mask */ | |
803 | sync /* Make sure of it all */ | |
1c79356b | 804 | |
de355530 A |
805 | lwz r6,4(r6) /* Get the latest reference and change bits */ |
806 | stw r11,mmPTEent(r10) /* Clear the pointer to the PTE */ | |
807 | rlwinm r6,r6,0,23,24 /* Extract the RC bits */ | |
808 | lwz r9,PCAallo(r7) /* Get the allocation control bits */ | |
809 | rlwinm r8,r5,24,8,15 /* Make the autogen bit to turn off */ | |
810 | rlwimi r2,r6,0,23,24 ; Put the latest RC bit in mapping copy | |
811 | or r9,r9,r5 /* Set the slot free */ | |
812 | rlwimi r8,r8,24,16,23 /* Get lock bit mask to turn it off */ | |
813 | andc r9,r9,r8 /* Clear the auto and lock bits */ | |
814 | li r5,pepte1 /* Get displacement to the second word of master pte */ | |
815 | stw r9,PCAallo(r7) /* Store the allocation controls */ | |
816 | ||
817 | protmod: lwarx r11,r5,r3 /* Get the master copy */ | |
818 | or r11,r11,r6 /* Merge in latest RC */ | |
819 | stwcx. r11,r5,r3 /* Save it back */ | |
820 | bne- protmod /* If it changed, try again... */ | |
821 | ||
822 | protul: li r4,0 /* Get a 0 */ | |
823 | stw r2,mmPTEr(r10) ; Save the updated mapping PTE | |
824 | lwz r10,mmnext(r10) /* Get the next */ | |
9bccf70c | 825 | |
de355530 | 826 | sync ; Make sure stores are complete |
9bccf70c | 827 | |
de355530 A |
828 | stw r4,0(r7) /* Unlock the hash chain */ |
829 | b protnext /* Go get the next one */ | |
1c79356b | 830 | |
de355530 | 831 | .align 4 |
1c79356b | 832 | |
de355530 A |
833 | protdone: mtmsr r0 /* Interrupts and translation back on */ |
834 | isync | |
835 | #if PERFTIMES && DEBUG | |
836 | mflr r11 | |
837 | li r3,27 | |
838 | bl EXT(dbgLog2) ; Start of hw_add_map | |
839 | mtlr r11 | |
840 | #endif | |
841 | blr /* Return... */ | |
1c79356b A |
842 | |
843 | ||
de355530 A |
844 | /* |
845 | * hw_prot_virt(mapping, prot) - Change the protection of single page | |
846 | * | |
847 | * Upon entry, R3 contains a pointer (real) to a mapping. | |
848 | * R4 contains the PPC protection bits. | |
849 | * | |
850 | * Acquire the lock on the PTEG hash list for the mapping being processed. | |
851 | * | |
852 | * If the current mapping has a PTE entry, we invalidate | |
853 | * it and merge the reference and change information into the phys_entry. | |
854 | * | |
855 | * Next, slam the protection bits into the entry, merge the RC bits, | |
856 | * and unlock the hash list. | |
857 | * | |
858 | * Note that this must be done with both interruptions off and VM off | |
859 | * | |
860 | * | |
861 | */ | |
1c79356b A |
862 | |
863 | .align 5 | |
de355530 | 864 | .globl EXT(hw_prot_virt) |
1c79356b | 865 | |
de355530 A |
866 | LEXT(hw_prot_virt) |
867 | #if PERFTIMES && DEBUG | |
868 | mflr r11 | |
869 | mr r7,r3 | |
870 | // lwz r5,4(r3) | |
871 | li r5,0x1111 | |
872 | li r3,40 | |
873 | bl EXT(dbgLog2) ; Start of hw_add_map | |
874 | mr r3,r7 | |
875 | mtlr r11 | |
876 | #endif | |
877 | mfsprg r9,2 ; Get feature flags | |
878 | mfmsr r0 /* Save the MSR */ | |
879 | rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
880 | rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
881 | rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ | |
882 | mtcrf 0x04,r9 ; Set the features | |
883 | rlwinm r12,r12,0,28,25 /* Clear IR and DR */ | |
1c79356b | 884 | |
de355530 | 885 | bt pfNoMSRirb,hpvNoMSR ; No MSR... |
d7e50217 | 886 | |
de355530 A |
887 | mtmsr r12 ; Translation and all off |
888 | isync ; Toss prefetch | |
889 | b hpvNoMSRx | |
890 | ||
891 | hpvNoMSR: | |
892 | mr r5,r0 | |
893 | mr r7,r3 | |
894 | li r0,loadMSR ; Get the MSR setter SC | |
895 | mr r3,r12 ; Get new MSR | |
896 | sc ; Set it | |
897 | mr r3,r7 | |
898 | mr r0,r5 | |
899 | hpvNoMSRx: | |
1c79356b A |
900 | |
901 | ||
1c79356b | 902 | |
de355530 A |
903 | /* |
904 | * Note that we need to to do the interlocked update here because another processor | |
905 | * can be updating the reference and change bits even though the physical entry | |
906 | * is locked. All modifications to the PTE portion of the physical entry must be | |
907 | * done via interlocked update. | |
908 | */ | |
d7e50217 | 909 | |
de355530 A |
910 | lwz r7,mmPTEhash(r3) /* Get pointer to hash list anchor */ |
911 | lwz r5,mmPTEv(r3) /* Get the virtual address */ | |
912 | rlwinm r7,r7,0,0,25 /* Round hash list down to PCA boundary */ | |
913 | ||
914 | li r12,1 /* Get the locked value */ | |
1c79356b | 915 | |
de355530 A |
916 | protvLck1: lwarx r11,0,r7 /* Get the PTEG lock */ |
917 | mr. r11,r11 /* Is it locked? */ | |
918 | bne- protvLckw1 /* Yeah... */ | |
919 | stwcx. r12,0,r7 /* Try to take it */ | |
920 | bne- protvLck1 /* Someone else was trying, try again... */ | |
921 | b protvSXg1 /* All done... */ | |
d7e50217 | 922 | |
de355530 A |
923 | .align 4 |
924 | ||
925 | protvLckw1: mr. r11,r11 /* Check if it's already held */ | |
926 | beq+ protvLck1 /* It's clear... */ | |
927 | lwz r11,0(r7) /* Get lock word again... */ | |
928 | b protvLckw1 /* Wait... */ | |
1c79356b | 929 | |
de355530 A |
930 | .align 4 |
931 | ||
932 | protvSXg1: isync /* Make sure we haven't used anything yet */ | |
933 | ||
934 | lwz r6,mmPTEent(r3) /* Get the pointer to the PTE now that the lock's set */ | |
935 | lwz r2,mmPTEr(r3) ; Get the mapping copy if the real part | |
936 | ||
937 | rlwinm r9,r5,1,0,3 /* Move in the segment */ | |
938 | cmplwi cr7,r6,0 ; Any PTE to invalidate? | |
939 | rlwimi r2,r4,0,30,31 ; Move in the new protection bits | |
940 | rlwinm r8,r5,31,2,25 /* Line it up */ | |
d7e50217 | 941 | |
de355530 A |
942 | beq+ cr7,pvnophys /* There's no PTE to invalidate... */ |
943 | ||
944 | xor r8,r8,r6 /* Back hash to virt index */ | |
945 | rlwimi r9,r5,22,4,9 /* Move in the API */ | |
946 | lis r12,HIGH_ADDR(EXT(tlb_system_lock)) /* Get the TLBIE lock */ | |
947 | rlwinm r5,r5,0,1,31 /* Clear the valid bit */ | |
948 | ori r12,r12,LOW_ADDR(EXT(tlb_system_lock)) /* Grab up the bottom part */ | |
949 | mfspr r11,pvr /* Find out what kind of machine we are */ | |
950 | rlwimi r9,r8,6,10,19 /* Create the virtual address */ | |
951 | rlwinm r11,r11,16,16,31 /* Isolate CPU type */ | |
952 | ||
953 | stw r5,0(r6) /* Make the PTE invalid */ | |
954 | cmplwi cr1,r11,3 /* Is this a 603? */ | |
955 | sync /* Make sure the invalid is stored */ | |
956 | ||
957 | tlbhangpv: lwarx r11,0,r12 /* Get the TLBIE lock */ | |
958 | rlwinm r8,r6,29,29,31 /* Get the bit position of entry */ | |
959 | mr. r11,r11 /* Is it locked? */ | |
960 | lis r5,0x8000 /* Start up a bit mask */ | |
961 | li r11,1 /* Get our lock word */ | |
962 | bne- tlbhangpv /* It's locked, go wait... */ | |
963 | stwcx. r11,0,r12 /* Try to get it */ | |
964 | bne- tlbhangpv /* We was beat... */ | |
d7e50217 | 965 | |
de355530 | 966 | li r11,0 /* Lock clear value */ |
1c79356b | 967 | |
de355530 | 968 | tlbie r9 /* Invalidate it everywhere */ |
1c79356b | 969 | |
de355530 | 970 | beq- cr1,its603pv /* It's a 603, skip the tlbsync... */ |
1c79356b | 971 | |
de355530 A |
972 | eieio /* Make sure that the tlbie happens first */ |
973 | tlbsync /* wait for everyone to catch up */ | |
974 | isync | |
d7e50217 | 975 | |
de355530 A |
976 | its603pv: stw r11,0(r12) /* Clear the lock */ |
977 | srw r5,r5,r8 /* Make a "free slot" mask */ | |
978 | sync /* Make sure of it all */ | |
979 | ||
980 | lwz r6,4(r6) /* Get the latest reference and change bits */ | |
981 | stw r11,mmPTEent(r3) /* Clear the pointer to the PTE */ | |
982 | rlwinm r6,r6,0,23,24 /* Extract the RC bits */ | |
983 | lwz r9,PCAallo(r7) /* Get the allocation control bits */ | |
984 | rlwinm r8,r5,24,8,15 /* Make the autogen bit to turn off */ | |
985 | lwz r10,mmphysent(r3) ; Get any physical entry | |
986 | or r9,r9,r5 /* Set the slot free */ | |
987 | rlwimi r8,r8,24,16,23 /* Get lock bit mask to turn it off */ | |
988 | andc r9,r9,r8 /* Clear the auto and lock bits */ | |
989 | mr. r10,r10 ; Is there a physical entry? | |
990 | li r5,pepte1 /* Get displacement to the second word of master pte */ | |
991 | stw r9,PCAallo(r7) /* Store the allocation controls */ | |
992 | rlwimi r2,r6,0,23,24 ; Stick in RC bits | |
993 | beq- pvnophys ; No physical entry... | |
994 | ||
995 | protvmod: lwarx r11,r5,r10 /* Get the master copy */ | |
996 | or r11,r11,r6 /* Merge in latest RC */ | |
997 | stwcx. r11,r5,r10 /* Save it back */ | |
998 | bne- protvmod /* If it changed, try again... */ | |
999 | ||
1000 | pvnophys: li r4,0 /* Get a 0 */ | |
1001 | stw r2,mmPTEr(r3) ; Set the real part of the PTE | |
1002 | ||
1003 | sync ; Make sure everything is stored | |
1004 | ||
1005 | stw r4,0(r7) /* Unlock the hash chain */ | |
1006 | mtmsr r0 ; Restore interrupts and translation | |
1007 | isync | |
1c79356b | 1008 | |
de355530 A |
1009 | #if PERFTIMES && DEBUG |
1010 | mflr r11 | |
1011 | li r3,41 | |
1012 | bl EXT(dbgLog2) | |
1013 | mtlr r11 | |
1014 | #endif | |
1015 | blr /* Return... */ | |
1c79356b | 1016 | |
1c79356b | 1017 | |
de355530 A |
1018 | /* |
1019 | * hw_attr_virt(mapping, attr) - Change the attributes of single page | |
1020 | * | |
1021 | * Upon entry, R3 contains a pointer (real) to a mapping. | |
1022 | * R4 contains the WIMG bits. | |
1023 | * | |
1024 | * Acquire the lock on the PTEG hash list for the mapping being processed. | |
1025 | * | |
1026 | * If the current mapping has a PTE entry, we invalidate | |
1027 | * it and merge the reference and change information into the phys_entry. | |
1028 | * | |
1029 | * Next, slam the WIMG bits into the entry, merge the RC bits, | |
1030 | * and unlock the hash list. | |
1031 | * | |
1032 | * Note that this must be done with both interruptions off and VM off | |
1033 | * | |
1034 | * | |
1035 | */ | |
1c79356b | 1036 | |
de355530 A |
1037 | .align 5 |
1038 | .globl EXT(hw_attr_virt) | |
1c79356b | 1039 | |
de355530 A |
1040 | LEXT(hw_attr_virt) |
1041 | #if PERFTIMES && DEBUG | |
1042 | mflr r11 | |
1043 | mr r7,r3 | |
1044 | // lwz r5,4(r3) | |
1045 | li r5,0x1111 | |
1046 | li r3,40 | |
1047 | bl EXT(dbgLog2) ; Start of hw_add_map | |
1048 | mr r3,r7 | |
1049 | mtlr r11 | |
1050 | #endif | |
1051 | mfsprg r9,2 ; Get feature flags | |
1052 | mfmsr r0 /* Save the MSR */ | |
1053 | rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
1054 | rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
1055 | mtcrf 0x04,r9 ; Set the features | |
1056 | rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ | |
1057 | rlwinm r12,r12,0,28,25 /* Clear IR and DR */ | |
1c79356b | 1058 | |
de355530 | 1059 | bt pfNoMSRirb,havNoMSR ; No MSR... |
1c79356b | 1060 | |
de355530 A |
1061 | mtmsr r12 ; Translation and all off |
1062 | isync ; Toss prefetch | |
1063 | b havNoMSRx | |
1064 | ||
1065 | havNoMSR: | |
1066 | mr r5,r0 | |
1067 | mr r7,r3 | |
1068 | li r0,loadMSR ; Get the MSR setter SC | |
1069 | mr r3,r12 ; Get new MSR | |
1070 | sc ; Set it | |
1071 | mr r3,r7 | |
1072 | mr r0,r5 | |
1073 | havNoMSRx: | |
1c79356b | 1074 | |
de355530 A |
1075 | /* |
1076 | * Note that we need to to do the interlocked update here because another processor | |
1077 | * can be updating the reference and change bits even though the physical entry | |
1078 | * is locked. All modifications to the PTE portion of the physical entry must be | |
1079 | * done via interlocked update. | |
1080 | */ | |
1081 | ||
1082 | lwz r7,mmPTEhash(r3) /* Get pointer to hash list anchor */ | |
1083 | lwz r5,mmPTEv(r3) /* Get the virtual address */ | |
1084 | rlwinm r7,r7,0,0,25 /* Round hash list down to PCA boundary */ | |
d7e50217 | 1085 | |
de355530 | 1086 | li r12,1 /* Get the locked value */ |
d7e50217 | 1087 | |
de355530 A |
1088 | attrvLck1: lwarx r11,0,r7 /* Get the PTEG lock */ |
1089 | mr. r11,r11 /* Is it locked? */ | |
1090 | bne- attrvLckw1 /* Yeah... */ | |
1091 | stwcx. r12,0,r7 /* Try to take it */ | |
1092 | bne- attrvLck1 /* Someone else was trying, try again... */ | |
1093 | b attrvSXg1 /* All done... */ | |
1094 | ||
1095 | .align 4 | |
d7e50217 | 1096 | |
de355530 A |
1097 | attrvLckw1: mr. r11,r11 /* Check if it's already held */ |
1098 | beq+ attrvLck1 /* It's clear... */ | |
1099 | lwz r11,0(r7) /* Get lock word again... */ | |
1100 | b attrvLckw1 /* Wait... */ | |
1101 | ||
1102 | .align 4 | |
d7e50217 | 1103 | |
de355530 | 1104 | attrvSXg1: isync /* Make sure we haven't used anything yet */ |
d7e50217 | 1105 | |
de355530 A |
1106 | lwz r6,mmPTEent(r3) /* Get the pointer to the PTE now that the lock's set */ |
1107 | lwz r2,mmPTEr(r3) ; Get the mapping copy if the real part | |
d7e50217 | 1108 | |
de355530 A |
1109 | rlwinm r9,r5,1,0,3 /* Move in the segment */ |
1110 | mr. r6,r6 /* See if there is a PTE here */ | |
1111 | rlwimi r2,r4,0,25,28 ; Move in the new attribute bits | |
1112 | rlwinm r8,r5,31,2,25 /* Line it up and check if empty */ | |
1113 | ||
1114 | beq+ avnophys /* There's no PTE to invalidate... */ | |
1115 | ||
1116 | xor r8,r8,r6 /* Back hash to virt index */ | |
1117 | rlwimi r9,r5,22,4,9 /* Move in the API */ | |
1118 | lis r12,HIGH_ADDR(EXT(tlb_system_lock)) /* Get the TLBIE lock */ | |
1119 | rlwinm r5,r5,0,1,31 /* Clear the valid bit */ | |
1120 | ori r12,r12,LOW_ADDR(EXT(tlb_system_lock)) /* Grab up the bottom part */ | |
1121 | mfspr r11,pvr /* Find out what kind of machine we are */ | |
1122 | rlwimi r9,r8,6,10,19 /* Create the virtual address */ | |
1123 | rlwinm r11,r11,16,16,31 /* Isolate CPU type */ | |
1124 | stw r5,0(r6) /* Make the PTE invalid */ | |
1125 | cmplwi cr1,r11,3 /* Is this a 603? */ | |
1126 | sync /* Make sure the invalid is stored */ | |
1127 | ||
1128 | tlbhangav: lwarx r11,0,r12 /* Get the TLBIE lock */ | |
1129 | rlwinm r8,r6,29,29,31 /* Get the bit position of entry */ | |
1130 | mr. r11,r11 /* Is it locked? */ | |
1131 | lis r5,0x8000 /* Start up a bit mask */ | |
1132 | li r11,1 /* Get our lock word */ | |
1133 | bne- tlbhangav /* It's locked, go wait... */ | |
1134 | stwcx. r11,0,r12 /* Try to get it */ | |
1135 | bne- tlbhangav /* We was beat... */ | |
1c79356b | 1136 | |
de355530 | 1137 | li r11,0 /* Lock clear value */ |
1c79356b | 1138 | |
de355530 | 1139 | tlbie r9 /* Invalidate it everywhere */ |
1c79356b | 1140 | |
de355530 | 1141 | beq- cr1,its603av /* It's a 603, skip the tlbsync... */ |
1c79356b | 1142 | |
de355530 A |
1143 | eieio /* Make sure that the tlbie happens first */ |
1144 | tlbsync /* wait for everyone to catch up */ | |
150bd074 | 1145 | isync |
de355530 A |
1146 | |
1147 | its603av: stw r11,0(r12) /* Clear the lock */ | |
1148 | srw r5,r5,r8 /* Make a "free slot" mask */ | |
1149 | sync /* Make sure of it all */ | |
1150 | ||
1151 | lwz r6,4(r6) /* Get the latest reference and change bits */ | |
1152 | stw r11,mmPTEent(r3) /* Clear the pointer to the PTE */ | |
1153 | rlwinm r6,r6,0,23,24 /* Extract the RC bits */ | |
1154 | lwz r9,PCAallo(r7) /* Get the allocation control bits */ | |
1155 | rlwinm r8,r5,24,8,15 /* Make the autogen bit to turn off */ | |
1156 | lwz r10,mmphysent(r3) ; Get any physical entry | |
1157 | or r9,r9,r5 /* Set the slot free */ | |
1158 | rlwimi r8,r8,24,16,23 /* Get lock bit mask to turn it off */ | |
1159 | andc r9,r9,r8 /* Clear the auto and lock bits */ | |
1160 | mr. r10,r10 ; Is there a physical entry? | |
1161 | li r5,pepte1 /* Get displacement to the second word of master pte */ | |
1162 | stw r9,PCAallo(r7) /* Store the allocation controls */ | |
1163 | rlwimi r2,r6,0,23,24 ; Stick in RC bits | |
1164 | beq- avnophys ; No physical entry... | |
1165 | ||
1166 | attrvmod: lwarx r11,r5,r10 /* Get the master copy */ | |
1167 | or r11,r11,r6 /* Merge in latest RC */ | |
1168 | stwcx. r11,r5,r10 /* Save it back */ | |
1169 | bne- attrvmod /* If it changed, try again... */ | |
1170 | ||
1171 | avnophys: li r4,0 /* Get a 0 */ | |
1172 | stw r2,mmPTEr(r3) ; Set the real part of the PTE | |
1173 | ||
1174 | sync ; Make sure that everything is updated | |
1175 | ||
1176 | stw r4,0(r7) /* Unlock the hash chain */ | |
1177 | ||
1178 | rlwinm r2,r2,0,0,19 ; Clear back to page boundary | |
1179 | ||
1180 | attrflsh: cmplwi r4,(4096-32) ; Are we about to do the last line on page? | |
1181 | dcbst r2,r4 ; Flush cache because we changed attributes | |
1182 | addi r4,r4,32 ; Bump up cache | |
1183 | blt+ attrflsh ; Do the whole page... | |
1184 | sync | |
1c79356b | 1185 | |
de355530 A |
1186 | li r4,0 |
1187 | attrimvl: cmplwi r4,(4096-32) ; Are we about to do the last line on page? | |
1188 | dcbi r2,r4 ; Invalidate dcache because we changed attributes | |
1189 | icbi r2,r4 ; Invalidate icache because we changed attributes | |
1190 | addi r4,r4,32 ; Bump up cache | |
1191 | blt+ attrimvl ; Do the whole page... | |
1192 | sync | |
d7e50217 | 1193 | |
de355530 A |
1194 | mtmsr r0 ; Restore interrupts and translation |
1195 | isync | |
1c79356b | 1196 | |
de355530 A |
1197 | #if PERFTIMES && DEBUG |
1198 | mflr r11 | |
1199 | li r3,41 | |
1200 | bl EXT(dbgLog2) | |
1201 | mtlr r11 | |
1202 | #endif | |
1203 | blr /* Return... */ | |
1c79356b A |
1204 | |
1205 | ||
1206 | /* | |
de355530 | 1207 | * hw_pte_comm(physent) - Do something to the PTE pointing to a physical page |
1c79356b | 1208 | * |
de355530 A |
1209 | * Upon entry, R3 contains a pointer to a physical entry which is locked. |
1210 | * Note that this must be done with both interruptions off and VM off | |
1c79356b | 1211 | * |
de355530 | 1212 | * First, we set up CRs 5 and 7 to indicate which of the 7 calls this is. |
1c79356b | 1213 | * |
de355530 | 1214 | * Now we scan the mappings to invalidate any with an active PTE. |
1c79356b | 1215 | * |
de355530 A |
1216 | * Acquire the lock on the PTEG hash list for the mapping being processed. |
1217 | * | |
1218 | * If the current mapping has a PTE entry, we invalidate | |
1219 | * it and merge the reference and change information into the phys_entry. | |
1220 | * | |
1221 | * Next, unlock the hash list and go on to the next mapping. | |
1c79356b A |
1222 | * |
1223 | * | |
de355530 | 1224 | * |
1c79356b A |
1225 | */ |
1226 | ||
1227 | .align 5 | |
de355530 | 1228 | .globl EXT(hw_inv_all) |
1c79356b | 1229 | |
de355530 A |
1230 | LEXT(hw_inv_all) |
1231 | ||
1232 | li r9,0x800 /* Indicate invalidate all */ | |
1233 | li r2,0 ; No inadvertant modifications please | |
1234 | b hw_pte_comm /* Join in the fun... */ | |
d7e50217 | 1235 | |
d7e50217 | 1236 | |
de355530 A |
1237 | .align 5 |
1238 | .globl EXT(hw_tst_mod) | |
1c79356b | 1239 | |
de355530 | 1240 | LEXT(hw_tst_mod) |
1c79356b | 1241 | |
de355530 A |
1242 | lwz r8,pepte1(r3) ; Get the saved PTE image |
1243 | li r9,0x400 /* Indicate test modify */ | |
1244 | li r2,0 ; No inadvertant modifications please | |
1245 | rlwinm. r8,r8,25,31,31 ; Make change bit into return code | |
1246 | beq+ hw_pte_comm ; Assume we do not know if it is set... | |
1247 | mr r3,r8 ; Set the return code | |
1248 | blr ; Return quickly... | |
1c79356b | 1249 | |
de355530 A |
1250 | .align 5 |
1251 | .globl EXT(hw_tst_ref) | |
1c79356b | 1252 | |
de355530 A |
1253 | LEXT(hw_tst_ref) |
1254 | lwz r8,pepte1(r3) ; Get the saved PTE image | |
1255 | li r9,0x200 /* Indicate test reference bit */ | |
1256 | li r2,0 ; No inadvertant modifications please | |
1257 | rlwinm. r8,r8,24,31,31 ; Make reference bit into return code | |
1258 | beq+ hw_pte_comm ; Assume we do not know if it is set... | |
1259 | mr r3,r8 ; Set the return code | |
1260 | blr ; Return quickly... | |
1c79356b A |
1261 | |
1262 | /* | |
de355530 | 1263 | * Note that the following are all in one CR for ease of use later |
1c79356b | 1264 | */ |
de355530 A |
1265 | .align 4 |
1266 | .globl EXT(hw_set_mod) | |
1c79356b | 1267 | |
de355530 A |
1268 | LEXT(hw_set_mod) |
1269 | ||
1270 | li r9,0x008 /* Indicate set modify bit */ | |
1271 | li r2,0x4 ; Set set C, clear none | |
1272 | b hw_pte_comm /* Join in the fun... */ | |
1c79356b A |
1273 | |
1274 | ||
de355530 A |
1275 | .align 4 |
1276 | .globl EXT(hw_clr_mod) | |
1c79356b | 1277 | |
de355530 | 1278 | LEXT(hw_clr_mod) |
1c79356b | 1279 | |
de355530 A |
1280 | li r9,0x004 /* Indicate clear modify bit */ |
1281 | li r2,0x1 ; Set set none, clear C | |
1282 | b hw_pte_comm /* Join in the fun... */ | |
1c79356b | 1283 | |
1c79356b | 1284 | |
de355530 A |
1285 | .align 4 |
1286 | .globl EXT(hw_set_ref) | |
1c79356b | 1287 | |
de355530 A |
1288 | LEXT(hw_set_ref) |
1289 | ||
1290 | li r9,0x002 /* Indicate set reference */ | |
1291 | li r2,0x8 ; Set set R, clear none | |
1292 | b hw_pte_comm /* Join in the fun... */ | |
1c79356b | 1293 | |
de355530 A |
1294 | .align 5 |
1295 | .globl EXT(hw_clr_ref) | |
d7e50217 | 1296 | |
de355530 A |
1297 | LEXT(hw_clr_ref) |
1298 | ||
1299 | li r9,0x001 /* Indicate clear reference bit */ | |
1300 | li r2,0x2 ; Set set none, clear R | |
1301 | b hw_pte_comm /* Join in the fun... */ | |
1c79356b A |
1302 | |
1303 | ||
1304 | /* | |
de355530 | 1305 | * This is the common stuff. |
1c79356b A |
1306 | */ |
1307 | ||
1308 | .align 5 | |
1309 | ||
de355530 | 1310 | hw_pte_comm: /* Common routine for pte tests and manips */ |
1c79356b | 1311 | |
de355530 A |
1312 | #if PERFTIMES && DEBUG |
1313 | mflr r11 | |
1314 | mr r7,r3 | |
1315 | lwz r4,4(r3) | |
1316 | mr r5,r9 | |
1317 | li r3,28 | |
1318 | bl EXT(dbgLog2) ; Start of hw_add_map | |
1319 | mr r3,r7 | |
1320 | mtlr r11 | |
1321 | #endif | |
1322 | mfsprg r8,2 ; Get feature flags | |
1323 | lwz r10,pephyslink(r3) /* Get the first mapping block */ | |
1324 | mfmsr r0 /* Save the MSR */ | |
1325 | rlwinm. r10,r10,0,0,26 ; Clear out the flags from first link and see if we are mapped | |
1326 | rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
1327 | rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
1328 | rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ | |
1329 | mtcrf 0x04,r8 ; Set the features | |
1330 | rlwinm r12,r12,0,28,25 /* Clear IR and DR */ | |
1331 | beq- comnmap ; No mapping | |
1332 | dcbt br0,r10 ; Touch the first mapping in before the isync | |
1333 | ||
1334 | comnmap: | |
1335 | ||
1336 | bt pfNoMSRirb,hpcNoMSR ; No MSR... | |
1337 | ||
1338 | mtmsr r12 ; Translation and all off | |
1339 | isync ; Toss prefetch | |
1340 | b hpcNoMSRx | |
d7e50217 | 1341 | |
de355530 A |
1342 | hpcNoMSR: |
1343 | mr r5,r0 | |
1344 | mr r7,r3 | |
1345 | li r0,loadMSR ; Get the MSR setter SC | |
1346 | mr r3,r12 ; Get new MSR | |
1347 | sc ; Set it | |
1348 | mr r3,r7 | |
1349 | mr r0,r5 | |
1350 | hpcNoMSRx: | |
1c79356b | 1351 | |
de355530 | 1352 | mtcrf 0x05,r9 /* Set the call type flags into cr5 and 7 */ |
1c79356b | 1353 | |
de355530 A |
1354 | beq- commdone ; Nothing us mapped to this page... |
1355 | b commnext ; Jump to first pass (jump here so we can align loop) | |
1c79356b | 1356 | |
de355530 | 1357 | .align 5 |
1c79356b | 1358 | |
de355530 A |
1359 | commnext: lwz r11,mmnext(r10) ; Get the pointer to the next mapping (if any) |
1360 | lwz r7,mmPTEhash(r10) /* Get pointer to hash list anchor */ | |
1361 | lwz r5,mmPTEv(r10) /* Get the virtual address */ | |
1362 | mr. r11,r11 ; More mappings to go? | |
1363 | rlwinm r7,r7,0,0,25 /* Round hash list down to PCA boundary */ | |
1364 | beq- commnxtch ; No more mappings... | |
1365 | dcbt br0,r11 ; Touch the next mapping | |
1c79356b | 1366 | |
de355530 | 1367 | commnxtch: li r12,1 /* Get the locked value */ |
1c79356b | 1368 | |
de355530 A |
1369 | commLck1: lwarx r11,0,r7 /* Get the PTEG lock */ |
1370 | mr. r11,r11 /* Is it locked? */ | |
1371 | bne- commLckw1 /* Yeah... */ | |
1372 | stwcx. r12,0,r7 /* Try to take it */ | |
1373 | bne- commLck1 /* Someone else was trying, try again... */ | |
1374 | b commSXg1 /* All done... */ | |
1375 | ||
1376 | .align 4 | |
1c79356b | 1377 | |
de355530 A |
1378 | commLckw1: mr. r11,r11 /* Check if it's already held */ |
1379 | beq+ commLck1 /* It's clear... */ | |
1380 | lwz r11,0(r7) /* Get lock word again... */ | |
1381 | b commLckw1 /* Wait... */ | |
1382 | ||
1383 | .align 4 | |
1c79356b | 1384 | |
de355530 | 1385 | commSXg1: isync /* Make sure we haven't used anything yet */ |
1c79356b | 1386 | |
de355530 | 1387 | lwz r6,mmPTEent(r10) /* Get the pointer to the PTE now that the lock's set */ |
1c79356b | 1388 | |
de355530 A |
1389 | rlwinm r9,r5,1,0,3 /* Move in the segment */ |
1390 | mr. r6,r6 /* See if there is a PTE entry here */ | |
1391 | rlwinm r8,r5,31,2,25 /* Line it up and check if empty */ | |
1392 | ||
1393 | beq+ commul /* There's no PTE to invalidate... */ | |
1394 | ||
1395 | xor r8,r8,r6 /* Back hash to virt index */ | |
1396 | rlwimi r9,r5,22,4,9 /* Move in the API */ | |
1397 | lis r12,HIGH_ADDR(EXT(tlb_system_lock)) /* Get the TLBIE lock */ | |
1398 | rlwinm r5,r5,0,1,31 /* Clear the valid bit */ | |
1399 | ori r12,r12,LOW_ADDR(EXT(tlb_system_lock)) /* Grab up the bottom part */ | |
1400 | rlwimi r9,r8,6,10,19 /* Create the virtual address */ | |
1401 | ||
1402 | stw r5,0(r6) /* Make the PTE invalid */ | |
1403 | mfspr r4,pvr /* Find out what kind of machine we are */ | |
1404 | sync /* Make sure the invalid is stored */ | |
1405 | ||
1406 | tlbhangco: lwarx r11,0,r12 /* Get the TLBIE lock */ | |
1407 | rlwinm r8,r6,29,29,31 /* Get the bit position of entry */ | |
1408 | mr. r11,r11 /* Is it locked? */ | |
1409 | lis r5,0x8000 /* Start up a bit mask */ | |
1410 | li r11,1 /* Get our lock word */ | |
1411 | bne- tlbhangco /* It's locked, go wait... */ | |
1412 | stwcx. r11,0,r12 /* Try to get it */ | |
1413 | bne- tlbhangco /* We was beat... */ | |
1414 | ||
1415 | rlwinm r4,r4,16,16,31 /* Isolate CPU type */ | |
1416 | li r11,0 /* Lock clear value */ | |
1417 | cmplwi r4,3 /* Is this a 603? */ | |
1c79356b | 1418 | |
de355530 | 1419 | tlbie r9 /* Invalidate it everywhere */ |
1c79356b | 1420 | |
de355530 A |
1421 | beq- its603co /* It's a 603, skip the tlbsync... */ |
1422 | ||
1423 | eieio /* Make sure that the tlbie happens first */ | |
1424 | tlbsync /* wait for everyone to catch up */ | |
1425 | isync | |
1426 | ||
1427 | its603co: stw r11,0(r12) /* Clear the lock */ | |
1428 | srw r5,r5,r8 /* Make a "free slot" mask */ | |
1429 | sync /* Make sure of it all */ | |
1c79356b | 1430 | |
de355530 A |
1431 | lwz r6,4(r6) /* Get the latest reference and change bits */ |
1432 | lwz r9,PCAallo(r7) /* Get the allocation control bits */ | |
1433 | stw r11,mmPTEent(r10) /* Clear the pointer to the PTE */ | |
1434 | rlwinm r8,r5,24,8,15 /* Make the autogen bit to turn off */ | |
1435 | or r9,r9,r5 /* Set the slot free */ | |
1436 | rlwimi r8,r8,24,16,23 /* Get lock bit mask to turn it off */ | |
1437 | rlwinm r4,r6,0,23,24 /* Extract the RC bits */ | |
1438 | andc r9,r9,r8 /* Clear the auto and lock bits */ | |
1439 | li r5,pepte1 /* Get displacement to the second word of master pte */ | |
1440 | stw r9,PCAallo(r7) /* Store the allocation controls */ | |
d7e50217 | 1441 | |
de355530 A |
1442 | commmod: lwarx r11,r5,r3 /* Get the master copy */ |
1443 | or r11,r11,r4 /* Merge in latest RC */ | |
1444 | stwcx. r11,r5,r3 /* Save it back */ | |
1445 | bne- commmod /* If it changed, try again... */ | |
1446 | b commulnl ; Skip loading the old real part... | |
9bccf70c | 1447 | |
de355530 | 1448 | commul: lwz r6,mmPTEr(r10) ; Get the real part |
9bccf70c | 1449 | |
de355530 A |
1450 | commulnl: rlwinm r12,r2,5,23,24 ; Get the "set" bits |
1451 | rlwinm r11,r2,7,23,24 ; Get the "clear" bits | |
1c79356b | 1452 | |
de355530 A |
1453 | or r6,r6,r12 ; Set the bits to come on |
1454 | andc r6,r6,r11 ; Clear those to come off | |
1c79356b | 1455 | |
de355530 | 1456 | stw r6,mmPTEr(r10) ; Set the new RC |
1c79356b | 1457 | |
de355530 A |
1458 | lwz r10,mmnext(r10) /* Get the next */ |
1459 | li r4,0 /* Make sure this is 0 */ | |
1460 | mr. r10,r10 ; Is there another mapping? | |
1c79356b | 1461 | |
de355530 | 1462 | sync ; Make sure that all is saved |
1c79356b | 1463 | |
de355530 A |
1464 | stw r4,0(r7) /* Unlock the hash chain */ |
1465 | bne+ commnext ; Go get the next if there is one... | |
1466 | ||
1467 | /* | |
1468 | * Now that all PTEs have been invalidated and the master RC bits are updated, | |
1469 | * we go ahead and figure out what the original call was and do that. Note that | |
1470 | * another processor could be messing around and may have entered one of the | |
1471 | * PTEs we just removed into the hash table. Too bad... You takes yer chances. | |
1472 | * If there's a problem with that, it's because some higher level was trying to | |
1473 | * do something with a mapping that it shouldn't. So, the problem's really | |
1474 | * there, nyaaa, nyaaa, nyaaa... nyaaa, nyaaa... nyaaa! So there! | |
1475 | */ | |
1c79356b | 1476 | |
de355530 A |
1477 | commdone: li r5,pepte1 /* Get displacement to the second word of master pte */ |
1478 | blt cr5,commfini /* We're finished, it was invalidate all... */ | |
1479 | bgt cr5,commtst /* It was a test modified... */ | |
1480 | beq cr5,commtst /* It was a test reference... */ | |
1c79356b | 1481 | |
de355530 A |
1482 | /* |
1483 | * Note that we need to to do the interlocked update here because another processor | |
1484 | * can be updating the reference and change bits even though the physical entry | |
1485 | * is locked. All modifications to the PTE portion of the physical entry must be | |
1486 | * done via interlocked update. | |
1487 | */ | |
1c79356b | 1488 | |
de355530 A |
1489 | rlwinm r12,r2,5,23,24 ; Get the "set" bits |
1490 | rlwinm r11,r2,7,23,24 ; Get the "clear" bits | |
d7e50217 | 1491 | |
de355530 A |
1492 | commcng: lwarx r8,r5,r3 /* Get the master copy */ |
1493 | or r8,r8,r12 ; Set the bits to come on | |
1494 | andc r8,r8,r11 ; Clear those to come off | |
1495 | stwcx. r8,r5,r3 /* Save it back */ | |
1496 | bne- commcng /* If it changed, try again... */ | |
d7e50217 | 1497 | |
de355530 | 1498 | mtmsr r0 /* Interrupts and translation back on */ |
d7e50217 | 1499 | isync |
de355530 A |
1500 | #if PERFTIMES && DEBUG |
1501 | mflr r11 | |
1502 | mr r4,r3 | |
1503 | li r3,29 | |
1504 | bl EXT(dbgLog2) ; Start of hw_add_map | |
1505 | mr r3,r4 | |
1506 | mtlr r11 | |
1507 | #endif | |
1508 | blr /* Return... */ | |
1509 | ||
1510 | .align 4 | |
1511 | ||
1512 | commtst: lwz r8,pepte1(r3) /* Get the PTE */ | |
1513 | bne- cr5,commtcb ; This is for the change bit... | |
1514 | mtmsr r0 ; Interrupts and translation back on | |
1515 | rlwinm r3,r8,24,31,31 ; Copy reference bit to bit 31 | |
1516 | isync ; Toss prefetching | |
1517 | #if PERFTIMES && DEBUG | |
1518 | mflr r11 | |
1519 | mr r4,r3 | |
1520 | li r3,29 | |
1521 | bl EXT(dbgLog2) ; Start of hw_add_map | |
1522 | mr r3,r4 | |
1523 | mtlr r11 | |
1524 | #endif | |
1525 | blr ; Return... | |
d7e50217 | 1526 | |
de355530 A |
1527 | .align 4 |
1528 | ||
1529 | commtcb: rlwinm r3,r8,25,31,31 ; Copy change bit to bit 31 | |
1530 | ||
1531 | commfini: mtmsr r0 ; Interrupts and translation back on | |
1532 | isync ; Toss prefetching | |
1c79356b | 1533 | |
de355530 A |
1534 | #if PERFTIMES && DEBUG |
1535 | mflr r11 | |
1536 | mr r4,r3 | |
1537 | li r3,29 | |
1538 | bl EXT(dbgLog2) ; Start of hw_add_map | |
1539 | mr r3,r4 | |
1540 | mtlr r11 | |
1541 | #endif | |
1542 | blr ; Return... | |
1c79356b A |
1543 | |
1544 | /* | |
de355530 | 1545 | * unsigned int hw_test_rc(mapping *mp, boolean_t reset); |
1c79356b | 1546 | * |
de355530 A |
1547 | * Test the RC bits for a specific mapping. If reset is non-zero, clear them. |
1548 | * We return the RC value in the mapping if there is no PTE or if C is set. | |
1549 | * (Note: R is always set with C.) Otherwise we invalidate the PTE and | |
1550 | * collect the RC bits from there, also merging them into the global copy. | |
1551 | * | |
1552 | * For now, we release the PTE slot and leave it invalid. In the future, we | |
1553 | * may consider re-validating and not releasing the slot. It would be faster, | |
1554 | * but our current implementation says that we will have not PTEs valid | |
1555 | * without the reference bit set. | |
1c79356b | 1556 | * |
de355530 | 1557 | * We will special case C==1 && not reset to just return the RC. |
d7e50217 | 1558 | * |
de355530 | 1559 | * Probable state is worst performance state: C bit is off and there is a PTE. |
1c79356b A |
1560 | */ |
1561 | ||
de355530 A |
1562 | #define htrReset 31 |
1563 | ||
1c79356b | 1564 | .align 5 |
de355530 | 1565 | .globl EXT(hw_test_rc) |
1c79356b | 1566 | |
de355530 | 1567 | LEXT(hw_test_rc) |
1c79356b | 1568 | |
de355530 A |
1569 | mfsprg r9,2 ; Get feature flags |
1570 | mfmsr r0 ; Save the MSR | |
1571 | rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
1572 | mr. r4,r4 ; See if we have a reset to do later | |
1573 | rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
1574 | rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruption mask | |
1575 | crnot htrReset,cr0_eq ; Remember reset | |
1576 | mtcrf 0x04,r9 ; Set the features | |
1577 | rlwinm r12,r12,0,28,25 ; Clear IR and DR | |
1c79356b | 1578 | |
de355530 | 1579 | bt pfNoMSRirb,htrNoMSR ; No MSR... |
d7e50217 | 1580 | |
de355530 A |
1581 | mtmsr r12 ; Translation and all off |
1582 | isync ; Toss prefetch | |
1583 | b htrNoMSRx | |
1c79356b | 1584 | |
de355530 A |
1585 | htrNoMSR: |
1586 | mr r2,r0 | |
1587 | mr r7,r3 | |
1588 | li r0,loadMSR ; Get the MSR setter SC | |
1589 | mr r3,r12 ; Get new MSR | |
1590 | sc ; Set it | |
1591 | mr r3,r7 | |
1592 | mr r0,r2 | |
1593 | htrNoMSRx: | |
d7e50217 | 1594 | |
de355530 A |
1595 | lwz r2,mmPTEr(r3) ; Get the real part |
1596 | lwz r7,mmPTEhash(r3) ; Get pointer to hash list anchor | |
1597 | rlwinm. r12,r2,0,24,24 ; Is the change bit on? | |
1598 | lwz r5,mmPTEv(r3) ; Get the virtual address | |
1599 | crnor cr0_eq,cr0_eq,htrReset ; Set if C=1 && not reset | |
1600 | rlwinm r7,r7,0,0,25 ; Round hash list down to PCA boundary | |
1601 | bt cr0_eq,htrcset ; Special case changed but no reset case... | |
1c79356b | 1602 | |
de355530 | 1603 | li r12,1 ; Get the locked value |
1c79356b | 1604 | |
de355530 A |
1605 | htrLck1: lwarx r11,0,r7 ; Get the PTEG lock |
1606 | mr. r11,r11 ; Is it locked? | |
1607 | bne- htrLckw1 ; Yeah... | |
1608 | stwcx. r12,0,r7 ; Try to take it | |
1609 | bne- htrLck1 ; Someone else was trying, try again... | |
1610 | b htrSXg1 ; All done... | |
1c79356b | 1611 | |
de355530 | 1612 | .align 4 |
1c79356b | 1613 | |
de355530 A |
1614 | htrLckw1: mr. r11,r11 ; Check if it is already held |
1615 | beq+ htrLck1 ; It is clear... | |
1616 | lwz r11,0(r7) ; Get lock word again... | |
1617 | b htrLckw1 ; Wait... | |
1c79356b | 1618 | |
de355530 | 1619 | .align 4 |
1c79356b | 1620 | |
de355530 | 1621 | htrSXg1: isync ; Make sure we have not used anything yet |
1c79356b | 1622 | |
de355530 A |
1623 | lwz r6,mmPTEent(r3) ; Get the pointer to the PTE now that the lock is set |
1624 | lwz r2,mmPTEr(r3) ; Get the mapping copy of the real part | |
1c79356b | 1625 | |
de355530 A |
1626 | rlwinm r9,r5,1,0,3 ; Move in the segment |
1627 | mr. r6,r6 ; Any PTE to invalidate? | |
1628 | rlwinm r8,r5,31,2,25 ; Line it up | |
1c79356b | 1629 | |
de355530 A |
1630 | beq+ htrnopte ; There is no PTE to invalidate... |
1631 | ||
1632 | xor r8,r8,r6 ; Back hash to virt index | |
1633 | rlwimi r9,r5,22,4,9 ; Move in the API | |
1634 | lis r12,HIGH_ADDR(EXT(tlb_system_lock)) ; Get the TLBIE lock | |
1635 | rlwinm r5,r5,0,1,31 ; Clear the valid bit | |
1636 | ori r12,r12,LOW_ADDR(EXT(tlb_system_lock)) ; Grab up the bottom part | |
1637 | mfspr r11,pvr ; Find out what kind of machine we are | |
1638 | rlwimi r9,r8,6,10,19 ; Create the virtual address | |
1639 | rlwinm r11,r11,16,16,31 ; Isolate CPU type | |
1640 | ||
1641 | stw r5,0(r6) ; Make the PTE invalid | |
1642 | cmplwi cr1,r11,3 ; Is this a 603? | |
1643 | sync ; Make sure the invalid is stored | |
1644 | ||
1645 | htrtlbhang: lwarx r11,0,r12 ; Get the TLBIE lock | |
1646 | rlwinm r8,r6,29,29,31 ; Get the bit position of entry | |
1647 | mr. r11,r11 ; Is it locked? | |
1648 | lis r5,0x8000 ; Start up a bit mask | |
1649 | li r11,1 ; Get our lock word | |
1650 | bne- htrtlbhang ; It is locked, go wait... | |
1651 | stwcx. r11,0,r12 ; Try to get it | |
1652 | bne- htrtlbhang ; We was beat... | |
d7e50217 | 1653 | |
de355530 | 1654 | li r11,0 ; Lock clear value |
1c79356b | 1655 | |
de355530 | 1656 | tlbie r9 ;Invalidate it everywhere |
1c79356b | 1657 | |
de355530 | 1658 | beq- cr1,htr603 ; It is a 603, skip the tlbsync... |
1c79356b | 1659 | |
de355530 A |
1660 | eieio ; Make sure that the tlbie happens first |
1661 | tlbsync ; wait for everyone to catch up | |
1662 | isync | |
d7e50217 | 1663 | |
de355530 A |
1664 | htr603: stw r11,0(r12) ; Clear the lock |
1665 | srw r5,r5,r8 ; Make a "free slot" mask | |
1666 | sync ; Make sure of it all | |
1667 | ||
1668 | lwz r6,4(r6) ; Get the latest reference and change bits | |
1669 | stw r11,mmPTEent(r3) ; Clear the pointer to the PTE | |
1670 | rlwinm r6,r6,0,23,24 ; Extract the RC bits | |
1671 | lwz r9,PCAallo(r7) ; Get the allocation control bits | |
1672 | rlwinm r8,r5,24,8,15 ; Make the autogen bit to turn off | |
1673 | lwz r10,mmphysent(r3) ; Get any physical entry | |
1674 | or r9,r9,r5 ; Set the slot free | |
1675 | rlwimi r8,r8,24,16,23 ; Get lock bit mask to turn it off | |
1676 | andc r9,r9,r8 ; Clear the auto and lock bits | |
1677 | mr. r10,r10 ; Is there a physical entry? | |
1678 | li r5,pepte1 ; Get displacement to the second word of master pte | |
1679 | stw r9,PCAallo(r7) ; Store the allocation controls | |
1680 | rlwimi r2,r6,0,23,24 ; Stick in RC bits | |
1681 | beq- htrnopte ; No physical entry... | |
1682 | ||
1683 | htrmrc: lwarx r11,r5,r10 ; Get the master copy | |
1684 | or r11,r11,r6 ; Merge in latest RC | |
1685 | stwcx. r11,r5,r10 ; Save it back | |
1686 | bne- htrmrc ; If it changed, try again... | |
1687 | ||
1688 | htrnopte: rlwinm r5,r2,25,30,31 ; Position RC and mask off | |
1689 | bf htrReset,htrnorst ; No reset to do... | |
1690 | rlwinm r2,r2,0,25,22 ; Clear the RC if requested | |
1691 | ||
1692 | htrnorst: li r4,0 ; Get a 0 | |
1693 | stw r2,mmPTEr(r3) ; Set the real part of the PTE | |
1694 | ||
1695 | sync ; Make sure that stuff is all stored | |
1696 | ||
1697 | stw r4,0(r7) ; Unlock the hash chain | |
1c79356b | 1698 | |
de355530 A |
1699 | mr r3,r5 ; Get the old RC to pass back |
1700 | mtmsr r0 ; Restore interrupts and translation | |
1c79356b | 1701 | isync |
de355530 | 1702 | blr ; Return... |
1c79356b | 1703 | |
de355530 | 1704 | .align 4 |
d7e50217 | 1705 | |
de355530 A |
1706 | htrcset: rlwinm r3,r2,25,30,31 ; Position RC and mask off |
1707 | mtmsr r0 ; Restore interrupts and translation | |
1708 | isync | |
1709 | blr ; Return... | |
d7e50217 | 1710 | |
d7e50217 | 1711 | |
de355530 A |
1712 | /* |
1713 | * hw_phys_attr(struct phys_entry *pp, vm_prot_t prot, unsigned int wimg) - Sets the default physical page attributes | |
1714 | * | |
1715 | * Note that this must be done with both interruptions off and VM off | |
1716 | * Move the passed in attributes into the pte image in the phys entry | |
1717 | * | |
1718 | * | |
1719 | */ | |
1c79356b A |
1720 | |
1721 | .align 5 | |
de355530 | 1722 | .globl EXT(hw_phys_attr) |
1c79356b | 1723 | |
de355530 | 1724 | LEXT(hw_phys_attr) |
1c79356b | 1725 | |
de355530 A |
1726 | #if PERFTIMES && DEBUG |
1727 | mflr r11 | |
1728 | mr r8,r3 | |
1729 | mr r7,r5 | |
1730 | mr r5,r4 | |
1731 | // lwz r4,4(r3) | |
1732 | li r4,0x1111 | |
1733 | li r3,30 | |
1734 | bl EXT(dbgLog2) ; Start of hw_add_map | |
1735 | mr r3,r8 | |
1736 | mr r4,r5 | |
1737 | mr r5,r7 | |
1738 | mtlr r11 | |
1739 | #endif | |
1740 | mfsprg r9,2 ; Get feature flags | |
1741 | mfmsr r0 /* Save the MSR */ | |
1742 | rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
1743 | rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
1744 | andi. r5,r5,0x0078 /* Clean up the WIMG */ | |
1745 | rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ | |
1746 | mtcrf 0x04,r9 ; Set the features | |
1747 | rlwimi r5,r4,0,30,31 /* Move the protection into the wimg register */ | |
1748 | la r6,pepte1(r3) /* Point to the default pte */ | |
1749 | rlwinm r12,r12,0,28,25 /* Clear IR and DR */ | |
1750 | ||
1751 | bt pfNoMSRirb,hpaNoMSR ; No MSR... | |
1752 | ||
1753 | mtmsr r12 ; Translation and all off | |
1754 | isync ; Toss prefetch | |
1755 | b hpaNoMSRx | |
d7e50217 | 1756 | |
de355530 A |
1757 | hpaNoMSR: |
1758 | mr r10,r0 | |
1759 | mr r4,r3 | |
1760 | li r0,loadMSR ; Get the MSR setter SC | |
1761 | mr r3,r12 ; Get new MSR | |
1762 | sc ; Set it | |
1763 | mr r3,r4 | |
1764 | mr r0,r10 | |
1765 | hpaNoMSRx: | |
1766 | ||
1767 | atmattr: lwarx r10,0,r6 /* Get the pte */ | |
1768 | rlwimi r10,r5,0,25,31 /* Move in the new attributes */ | |
1769 | stwcx. r10,0,r6 /* Try it on for size */ | |
1770 | bne- atmattr /* Someone else was trying, try again... */ | |
1771 | ||
1772 | mtmsr r0 /* Interrupts and translation back on */ | |
1773 | isync | |
1774 | #if PERFTIMES && DEBUG | |
1775 | mflr r11 | |
1776 | mr r4,r10 | |
1777 | li r3,31 | |
1778 | bl EXT(dbgLog2) ; Start of hw_add_map | |
1779 | mtlr r11 | |
1780 | #endif | |
1781 | blr /* All done... */ | |
1c79356b A |
1782 | |
1783 | ||
1c79356b | 1784 | |
de355530 A |
1785 | /* |
1786 | * handlePF - handle a page fault interruption | |
1787 | * | |
1788 | * If the fault can be handled, this routine will RFI directly, | |
1789 | * otherwise it will return with all registers as in entry. | |
1790 | * | |
1791 | * Upon entry, state and all registers have been saved in savearea. | |
1792 | * This is pointed to by R13. | |
1793 | * IR and DR are off, interrupts are masked, | |
1794 | * Floating point be disabled. | |
1795 | * R3 is the interrupt code. | |
1796 | * | |
1797 | * If we bail, we must restore cr5, and all registers except 6 and | |
1798 | * 3. | |
1799 | * | |
1800 | */ | |
1801 | ||
1802 | .align 5 | |
1803 | .globl EXT(handlePF) | |
1c79356b | 1804 | |
de355530 | 1805 | LEXT(handlePF) |
1c79356b | 1806 | |
de355530 A |
1807 | /* |
1808 | * This first part does a quick check to see if we can handle the fault. | |
1809 | * We can't handle any kind of protection exceptions here, so we pass | |
1810 | * them up to the next level. | |
1811 | * | |
1812 | * The mapping lists are kept in MRS (most recently stolen) | |
1813 | * order on queues anchored within from the | |
1814 | * PTEG to which the virtual address hashes. This is further segregated by | |
1815 | * the low-order 3 bits of the VSID XORed with the segment number and XORed | |
1816 | * with bits 4-7 of the vaddr in an attempt to keep the searches | |
1817 | * short. | |
1818 | * | |
1819 | * MRS is handled by moving the entry to the head of its list when stolen in the | |
1820 | * assumption that it will be revalidated soon. Entries are created on the head | |
1821 | * of the list because they will be used again almost immediately. | |
1822 | * | |
1823 | * We need R13 set to the savearea, R3 set to the interrupt code, and R2 | |
1824 | * set to the per_proc. | |
1825 | * | |
1826 | * NOTE: In order for a page-fault redrive to work, the translation miss | |
1827 | * bit must be set in the DSISR (or SRR1 for IFETCH). That must occur | |
1828 | * before we come here. | |
1829 | */ | |
d7e50217 | 1830 | |
de355530 A |
1831 | cmplwi r3,T_INSTRUCTION_ACCESS /* See if this is for the instruction */ |
1832 | lwz r8,savesrr1(r13) ; Get the MSR to determine mode | |
1833 | beq- gotIfetch ; We have an IFETCH here... | |
1c79356b | 1834 | |
de355530 A |
1835 | lwz r7,savedsisr(r13) /* Get the DSISR */ |
1836 | lwz r6,savedar(r13) /* Get the fault address */ | |
1837 | b ckIfProt ; Go check if this is a protection fault... | |
1c79356b | 1838 | |
de355530 A |
1839 | gotIfetch: mr r7,r8 ; IFETCH info is in SRR1 |
1840 | lwz r6,savesrr0(r13) /* Get the instruction address */ | |
1c79356b | 1841 | |
de355530 A |
1842 | ckIfProt: rlwinm. r7,r7,0,1,1 ; Is this a protection exception? |
1843 | beqlr- ; Yes... (probably not though) | |
1c79356b | 1844 | |
de355530 A |
1845 | /* |
1846 | * We will need to restore registers if we bail after this point. | |
1847 | * Note that at this point several SRs have been changed to the kernel versions. | |
1848 | * Therefore, for these we must build these values. | |
1849 | */ | |
1c79356b | 1850 | |
de355530 A |
1851 | #if PERFTIMES && DEBUG |
1852 | mflr r11 | |
1853 | mr r5,r6 | |
1854 | mr r4,r3 | |
1855 | li r3,32 | |
1856 | bl EXT(dbgLog2) ; Start of hw_add_map | |
1857 | mr r3,r4 | |
1858 | mtlr r11 | |
1859 | mfsprg r2,0 | |
1860 | #endif | |
1861 | lwz r3,PP_USERPMAP(r2) ; Get the user pmap (not needed if kernel access, but optimize for user??) | |
1862 | rlwinm. r8,r8,0,MSR_PR_BIT,MSR_PR_BIT ; Supervisor state access? | |
1863 | rlwinm r5,r6,6,26,29 ; Get index to the segment slot | |
1864 | eqv r1,r1,r1 ; Fill the bottom with foxes | |
1865 | bne+ notsuper ; Go do the user mode interrupt stuff... | |
1866 | ||
1867 | cmplwi cr1,r5,SR_COPYIN_NUM*4 ; See if this is the copyin/copyout segment | |
1868 | rlwinm r3,r6,24,8,11 ; Make the kernel VSID | |
1869 | bne+ cr1,havevsid ; We are done if we do not want the copyin/out guy... | |
1870 | ||
1871 | mfsr r3,SR_COPYIN ; Get the copy vsid | |
1872 | b havevsid ; Join up... | |
1873 | ||
1874 | .align 5 | |
1875 | ||
1876 | notsuper: addi r5,r5,PMAP_SEGS ; Get offset to table | |
1877 | lwzx r3,r3,r5 ; Get the VSID | |
1878 | ||
1879 | havevsid: mfspr r5,sdr1 /* Get hash table base and size */ | |
1880 | cror cr1_eq,cr0_eq,cr0_eq ; Remember if kernel fault for later | |
1881 | rlwinm r9,r6,2,2,5 ; Move nybble 1 up to 0 (keep aligned with VSID) | |
1882 | rlwimi r1,r5,16,0,15 /* Make table size -1 out of mask */ | |
1883 | rlwinm r3,r3,6,2,25 /* Position the space for the VSID */ | |
1884 | rlwinm r7,r6,26,10,25 /* Isolate the page index */ | |
1885 | xor r9,r9,r3 ; Splooch vaddr nybble 0 (from VSID) and 1 together | |
1886 | or r8,r5,r1 /* Point to the last byte in table */ | |
1887 | xor r7,r7,r3 /* Get primary hash */ | |
1888 | rlwinm r3,r3,1,1,24 /* Position VSID for pte ID */ | |
1889 | addi r8,r8,1 /* Point to the PTEG Control Area */ | |
1890 | rlwinm r9,r9,8,27,29 ; Get splooched bits in place | |
1891 | and r7,r7,r1 /* Wrap the hash */ | |
1892 | rlwimi r3,r6,10,26,31 /* Move API into pte ID */ | |
1893 | add r8,r8,r7 /* Point to our PCA entry */ | |
1894 | rlwinm r12,r3,27,27,29 ; Get low 3 bits of the VSID for look-aside hash | |
1895 | la r11,PCAhash(r8) /* Point to the mapping hash area */ | |
1896 | xor r9,r9,r12 ; Finish splooching nybble 0, 1, and the low bits of the VSID | |
1c79356b A |
1897 | |
1898 | ||
de355530 A |
1899 | /* |
1900 | * We have about as much as we need to start searching the autogen (aka block maps) | |
1901 | * and mappings. From here on, any kind of failure will bail, and | |
1902 | * contention will either bail or restart from here. | |
1903 | * | |
1904 | * | |
1905 | */ | |
1c79356b | 1906 | |
de355530 A |
1907 | li r12,1 /* Get the locked value */ |
1908 | dcbt 0,r11 /* We'll need the hash area in a sec, so get it */ | |
1909 | add r11,r11,r9 /* Point to the right mapping hash slot */ | |
1c79356b | 1910 | |
de355530 A |
1911 | ptegLck: lwarx r10,0,r8 /* Get the PTEG lock */ |
1912 | mr. r10,r10 /* Is it locked? */ | |
1913 | bne- ptegLckw /* Yeah... */ | |
1914 | stwcx. r12,0,r8 /* Take take it */ | |
1915 | bne- ptegLck /* Someone else was trying, try again... */ | |
1916 | b ptegSXg /* All done... */ | |
1917 | ||
1918 | .align 4 | |
d7e50217 | 1919 | |
de355530 A |
1920 | ptegLckw: mr. r10,r10 /* Check if it's already held */ |
1921 | beq+ ptegLck /* It's clear... */ | |
1922 | lwz r10,0(r8) /* Get lock word again... */ | |
1923 | b ptegLckw /* Wait... */ | |
1c79356b | 1924 | |
de355530 A |
1925 | .align 5 |
1926 | ||
1927 | nop ; Force ISYNC to last instruction in IFETCH | |
1928 | nop | |
1929 | nop | |
1c79356b | 1930 | |
de355530 | 1931 | ptegSXg: isync /* Make sure we haven't used anything yet */ |
1c79356b | 1932 | |
de355530 A |
1933 | lwz r9,0(r11) /* Pick up first mapping block */ |
1934 | mr r5,r11 /* Get the address of the anchor */ | |
1935 | mr r7,r9 /* Save the first in line */ | |
1936 | b findmap ; Take space and force loop to cache line | |
1937 | ||
1938 | findmap: mr. r12,r9 /* Are there more? */ | |
1939 | beq- tryAuto /* Nope, nothing in mapping list for us... */ | |
1940 | ||
1941 | lwz r10,mmPTEv(r12) /* Get unique PTE identification */ | |
1942 | lwz r9,mmhashnext(r12) /* Get the chain, just in case */ | |
1943 | cmplw r10,r3 /* Did we hit our PTE? */ | |
1944 | lwz r0,mmPTEent(r12) /* Get the pointer to the hash table entry */ | |
1945 | mr r5,r12 /* Save the current as previous */ | |
1946 | bne- findmap ; Nothing here, try the next... | |
1947 | ||
1948 | ; Cache line boundary here | |
1949 | ||
1950 | cmplwi cr1,r0,0 /* Is there actually a PTE entry in the hash? */ | |
1951 | lwz r2,mmphysent(r12) /* Get the physical entry */ | |
1952 | bne- cr1,MustBeOK /* There's an entry in the hash table, so, this must | |
1953 | have been taken care of already... */ | |
1954 | lis r4,0x8000 ; Tell PTE inserter that this was not an auto | |
1955 | cmplwi cr2,r2,0 /* Is there a physical entry? */ | |
1956 | li r0,0x0100 /* Force on the reference bit whenever we make a PTE valid */ | |
1957 | bne+ cr2,gotphys /* Skip down if we have a physical entry */ | |
1958 | li r0,0x0180 /* When there is no physical entry, force on | |
1959 | both R and C bits to keep hardware from | |
1960 | updating the PTE to set them. We don't | |
1961 | keep track of RC for I/O areas, so this is ok */ | |
1962 | ||
1963 | gotphys: lwz r2,mmPTEr(r12) ; Get the second part of the PTE | |
1964 | b insert /* Go insert into the PTEG... */ | |
1965 | ||
1966 | MustBeOK: li r10,0 /* Get lock clear value */ | |
1967 | li r3,T_IN_VAIN /* Say that we handled it */ | |
1968 | stw r10,PCAlock(r8) /* Clear the PTEG lock */ | |
1969 | ||
1970 | #if PERFTIMES && DEBUG | |
1971 | mflr r11 | |
1972 | mr r4,r3 | |
1973 | li r3,33 | |
1974 | bl EXT(dbgLog2) ; Start of hw_add_map | |
1975 | mr r3,r4 | |
1976 | mtlr r11 | |
1977 | #endif | |
1978 | blr /* Blow back and handle exception */ | |
1c79356b A |
1979 | |
1980 | ||
1981 | ||
de355530 A |
1982 | /* |
1983 | * We couldn't find it in the mapping list. As a last try, we will | |
1984 | * see if we can autogen it from the block mapped list. | |
1985 | * | |
1986 | * A block mapped area is defined as a contiguous virtual area that is mapped to | |
1987 | * a contiguous physical area. The olde-tyme IBM VM/XA Interpretive Execution | |
1988 | * architecture referred to this as a V=F, or Virtual = Fixed area. | |
1989 | * | |
1990 | * We consider a V=F area to be a single entity, adjacent areas can not be merged | |
1991 | * or overlapped. The protection and memory attributes are the same and reference | |
1992 | * and change indications are not kept. The areas are not considered part of the | |
1993 | * physical RAM of the machine and do not have any associated physical table | |
1994 | * entries. Their primary use is intended for mapped I/O areas (e.g., framebuffers) | |
1995 | * although certain areas of RAM, such as the kernel V=R memory, can be mapped. | |
1996 | * | |
1997 | * We also have a problem in the case of copyin/out: that access is done | |
1998 | * within the kernel for a user address. Unfortunately, the user isn't | |
1999 | * necessarily the current guy. That means that we don't have access to the | |
2000 | * right autogen list. We can't support this kind of access. So, we need to do | |
2001 | * a quick check here and cause a fault if an attempt to copyin or out to | |
2002 | * any autogenned area. | |
2003 | * | |
2004 | * The lists must be kept short. | |
2005 | * | |
2006 | * NOTE: kernel_pmap_store must be in V=R storage!!!!!!!!!!!!!! | |
2007 | */ | |
2008 | ||
2009 | .align 5 | |
1c79356b | 2010 | |
de355530 A |
2011 | tryAuto: rlwinm. r11,r3,0,5,24 ; Check if this is a kernel VSID |
2012 | lis r10,HIGH_ADDR(EXT(kernel_pmap_store)+PMAP_BMAPS) ; Get the top part of kernel block map anchor | |
2013 | crandc cr0_eq,cr1_eq,cr0_eq ; Set if kernel access and non-zero VSID (copyin or copyout) | |
2014 | mfsprg r11,0 ; Get the per_proc area | |
2015 | beq- cr0,realFault ; Can not autogen for copyin/copyout... | |
2016 | ori r10,r10,LOW_ADDR(EXT(kernel_pmap_store)+PMAP_BMAPS) ; Get the bottom part | |
2017 | beq- cr1,bmInKernel ; We are in kernel... (cr1 set way back at entry) | |
2018 | ||
2019 | lwz r10,PP_USERPMAP(r11) ; Get the user pmap | |
2020 | la r10,PMAP_BMAPS(r10) ; Point to the chain anchor | |
2021 | b bmInKernel ; Jump over alignment gap... | |
2022 | nop | |
2023 | nop | |
2024 | nop | |
2025 | nop | |
2026 | nop | |
2027 | nop | |
2028 | bmInKernel: | |
2029 | #ifndef CHIP_ERRATA_MAX_V1 | |
2030 | lwarx r9,0,r10 | |
2031 | #endif /* CHIP_ERRATA_MAX_V1 */ | |
2032 | ||
2033 | bmapLck: lwarx r9,0,r10 ; Get the block map anchor and lock | |
2034 | rlwinm. r5,r9,0,31,31 ; Is it locked? | |
2035 | ori r5,r5,1 ; Set the lock | |
2036 | bne- bmapLckw ; Yeah... | |
2037 | stwcx. r5,0,r10 ; Lock the bmap list | |
2038 | bne- bmapLck ; Someone else was trying, try again... | |
2039 | b bmapSXg ; All done... | |
2040 | ||
2041 | .align 4 | |
2042 | ||
2043 | bmapLckw: rlwinm. r5,r9,0,31,31 ; Check if it is still held | |
2044 | beq+ bmapLck ; Not no more... | |
2045 | lwz r9,0(r10) ; Get lock word again... | |
2046 | b bmapLckw ; Check it out... | |
2047 | ||
2048 | .align 5 | |
2049 | ||
2050 | nop ; Force ISYNC to last instruction in IFETCH | |
2051 | nop | |
2052 | nop | |
2053 | ||
2054 | bmapSXg: rlwinm. r4,r9,0,0,26 ; Clear out flags and lock | |
2055 | isync ; Make sure we have not used anything yet | |
2056 | bne+ findAuto ; We have something, let us go... | |
2057 | ||
2058 | bmapNone: stw r9,0(r10) ; Unlock it, we have nothing here | |
2059 | ; No sync here because we have not changed anything | |
1c79356b | 2060 | |
de355530 A |
2061 | /* |
2062 | * When we come here, we know that we can't handle this. Restore whatever | |
2063 | * state that we trashed and go back to continue handling the interrupt. | |
2064 | */ | |
1c79356b | 2065 | |
de355530 A |
2066 | realFault: li r10,0 /* Get lock clear value */ |
2067 | lwz r3,saveexception(r13) /* Figure out the exception code again */ | |
2068 | stw r10,PCAlock(r8) /* Clear the PTEG lock */ | |
2069 | #if PERFTIMES && DEBUG | |
2070 | mflr r11 | |
2071 | mr r4,r3 | |
2072 | li r3,33 | |
2073 | bl EXT(dbgLog2) ; Start of hw_add_map | |
2074 | mr r3,r4 | |
2075 | mtlr r11 | |
2076 | #endif | |
2077 | blr /* Blow back and handle exception */ | |
1c79356b | 2078 | |
de355530 | 2079 | .align 5 |
1c79356b | 2080 | |
de355530 A |
2081 | findAuto: mr. r4,r4 ; Is there more? |
2082 | beq- bmapNone ; No more... | |
2083 | lwz r5,bmstart(r4) ; Get the bottom of range | |
2084 | lwz r11,bmend(r4) ; Get the top of range | |
2085 | cmplw cr0,r6,r5 ; Are we before the entry? | |
2086 | cmplw cr1,r6,r11 ; Are we after the entry? | |
2087 | cror cr1_eq,cr0_lt,cr1_gt ; Set cr1_eq if new not in range | |
2088 | bne+ cr1,faGot ; Found it... | |
1c79356b | 2089 | |
de355530 A |
2090 | lwz r4,bmnext(r4) ; Get the next one |
2091 | b findAuto ; Check it out... | |
1c79356b | 2092 | |
de355530 A |
2093 | faGot: |
2094 | lwz r7,blkFlags(r4) ; Get the flags | |
2095 | rlwinm. r7,r7,0,blkRembit,blkRembit ; is this mapping partially removed | |
2096 | bne bmapNone ; Pending remove, bail out | |
2097 | rlwinm r6,r6,0,0,19 ; Round to page | |
2098 | lwz r2,bmPTEr(r4) ; Get the real part of the PTE | |
2099 | sub r5,r6,r5 ; Get offset into area | |
2100 | stw r9,0(r10) ; Unlock it, we are done with it (no sync needed) | |
2101 | add r2,r2,r5 ; Adjust the real address | |
d7e50217 | 2102 | |
de355530 A |
2103 | lis r4,0x8080 /* Indicate that this was autogened */ |
2104 | li r0,0x0180 /* Autogenned areas always set RC bits. | |
2105 | This keeps the hardware from having | |
2106 | to do two storage writes */ | |
1c79356b | 2107 | |
de355530 A |
2108 | /* |
2109 | * Here where we insert the PTE into the hash. The PTE image is in R3, R2. | |
2110 | * The PTEG allocation controls are a bit map of the state of the PTEG. The | |
2111 | * PCAlock bits are a temporary lock for the specified PTE. PCAfree indicates that | |
2112 | * the PTE slot is empty. PCAauto means that it comes from an autogen area. These | |
2113 | * guys do not keep track of reference and change and are actually "wired". | |
2114 | * They're easy to maintain. PCAsteal | |
2115 | * is a sliding position mask used to "randomize" PTE slot stealing. All 4 of these | |
2116 | * fields fit in a single word and are loaded and stored under control of the | |
2117 | * PTEG control area lock (PCAlock). | |
2118 | * | |
2119 | * Note that PCAauto does not contribute to the steal calculations at all. Originally | |
2120 | * it did, autogens were second in priority. This can result in a pathalogical | |
2121 | * case where an instruction can not make forward progress, or one PTE slot | |
2122 | * thrashes. | |
2123 | * | |
2124 | * Physically, the fields are arranged: | |
2125 | * 0: PCAfree | |
2126 | * 1: PCAauto | |
2127 | * 2: PCAlock | |
2128 | * 3: PCAsteal | |
2129 | */ | |
2130 | ||
2131 | insert: lwz r10,PCAallo(r8) /* Get the PTEG controls */ | |
2132 | eqv r6,r6,r6 /* Get all ones */ | |
2133 | mr r11,r10 /* Make a copy */ | |
2134 | rlwimi r6,r10,8,16,23 /* Insert sliding steal position */ | |
2135 | rlwimi r11,r11,24,24,31 /* Duplicate the locked field */ | |
2136 | addi r6,r6,-256 /* Form mask */ | |
2137 | rlwimi r11,r11,16,0,15 /* This gives us a quadrupled lock mask */ | |
2138 | rlwinm r5,r10,31,24,0 /* Slide over the mask for next time */ | |
2139 | mr r9,r10 /* Make a copy to test */ | |
2140 | not r11,r11 /* Invert the quadrupled lock */ | |
2141 | or r2,r2,r0 /* Force on R, and maybe C bit */ | |
2142 | and r9,r9,r11 /* Remove the locked guys */ | |
2143 | rlwimi r5,r5,8,24,24 /* Wrap bottom bit to top in mask */ | |
2144 | rlwimi r9,r11,0,16,31 /* Put two copies of the unlocked entries at the end */ | |
2145 | rlwinm r6,r6,0,16,7 ; Remove the autogens from the priority calculations | |
2146 | rlwimi r10,r5,0,24,31 /* Move steal map back in */ | |
2147 | and r9,r9,r6 /* Set the starting point for stealing */ | |
2148 | ||
2149 | /* So, now we have in R9: | |
2150 | byte 0 = ~locked & free | |
2151 | byte 1 = 0 | |
2152 | byte 2 = ~locked & (PCAsteal - 1) | |
2153 | byte 3 = ~locked | |
2154 | ||
2155 | Each bit position represents (modulo 8) a PTE. If it is 1, it is available for | |
2156 | allocation at its priority level, left to right. | |
2157 | ||
2158 | Additionally, the PCA steal field in R10 has been rotated right one bit. | |
2159 | */ | |
2160 | ||
2161 | ||
2162 | rlwinm r21,r10,8,0,7 ; Isolate just the old autogen bits | |
2163 | cntlzw r6,r9 /* Allocate a slot */ | |
2164 | mr r14,r12 /* Save our mapping for later */ | |
2165 | cmplwi r6,32 ; Was there anything available? | |
2166 | rlwinm r7,r6,29,30,31 /* Get the priority slot we got this from */ | |
2167 | rlwinm r6,r6,0,29,31 ; Isolate bit position | |
2168 | srw r11,r4,r6 /* Position the PTEG control bits */ | |
2169 | slw r21,r21,r6 ; Move corresponding old autogen flag to bit 0 | |
2170 | mr r22,r11 ; Get another copy of the selected slot | |
2171 | ||
2172 | beq- realFault /* Arghh, no slots! Take the long way 'round... */ | |
2173 | ||
2174 | /* Remember, we've already set up the mask pattern | |
2175 | depending upon how we got here: | |
2176 | if got here from simple mapping, R4=0x80000000, | |
2177 | if we got here from autogen it is 0x80800000. */ | |
2178 | ||
2179 | rlwinm r6,r6,3,26,28 /* Start calculating actual PTE address */ | |
2180 | rlwimi r22,r22,24,8,15 ; Duplicate selected slot in second byte | |
2181 | rlwinm. r11,r11,0,8,15 /* Isolate just the auto bit (remember about it too) */ | |
2182 | andc r10,r10,r22 /* Turn off the free and auto bits */ | |
2183 | add r6,r8,r6 /* Get position into PTEG control area */ | |
2184 | cmplwi cr1,r7,1 /* Set the condition based upon the old PTE type */ | |
2185 | sub r6,r6,r1 /* Switch it to the hash table */ | |
2186 | or r10,r10,r11 /* Turn auto on if it is (PTEG control all set up now) */ | |
2187 | subi r6,r6,1 /* Point right */ | |
2188 | stw r10,PCAallo(r8) /* Allocate our slot */ | |
2189 | dcbt br0,r6 ; Touch in the PTE | |
2190 | bne wasauto /* This was autogenned... */ | |
2191 | ||
2192 | stw r6,mmPTEent(r14) /* Link the mapping to the PTE slot */ | |
2193 | ||
2194 | /* | |
2195 | * So, now we're here and what exactly do we have? We've got: | |
2196 | * 1) a full PTE entry, both top and bottom words in R3 and R2 | |
2197 | * 2) an allocated slot in the PTEG. | |
2198 | * 3) R8 still points to the PTEG Control Area (PCA) | |
2199 | * 4) R6 points to the PTE entry. | |
2200 | * 5) R1 contains length of the hash table-1. We use this to back-translate | |
2201 | * a PTE to a virtual address so we can invalidate TLBs. | |
2202 | * 6) R11 has a copy of the PCA controls we set. | |
2203 | * 7a) R7 indicates what the PTE slot was before we got to it. 0 shows | |
2204 | * that it was empty and 2 or 3, that it was | |
2205 | * a we've stolen a live one. CR1 is set to LT for empty and GT | |
2206 | * otherwise. | |
2207 | * 7b) Bit 0 of R21 is 1 if the stolen PTE was autogenned | |
2208 | * 8) So far as our selected PTE, it should be valid if it was stolen | |
2209 | * and invalid if not. We could put some kind of assert here to | |
2210 | * check, but I think that I'd rather leave it in as a mysterious, | |
2211 | * non-reproducable bug. | |
2212 | * 9) The new PTE's mapping has been moved to the front of its PTEG hash list | |
2213 | * so that it's kept in some semblance of a MRU list. | |
2214 | * 10) R14 points to the mapping we're adding. | |
2215 | * | |
2216 | * So, what do we have to do yet? | |
2217 | * 1) If we stole a slot, we need to invalidate the PTE completely. | |
2218 | * 2) If we stole one AND it was not an autogen, | |
2219 | * copy the entire old PTE (including R and C bits) to its mapping. | |
2220 | * 3) Set the new PTE in the PTEG and make sure it is valid. | |
2221 | * 4) Unlock the PTEG control area. | |
2222 | * 5) Go back to the interrupt handler, changing the interrupt | |
2223 | * code to "in vain" which will restore the registers and bail out. | |
2224 | * | |
2225 | */ | |
2226 | wasauto: oris r3,r3,0x8000 /* Turn on the valid bit */ | |
2227 | blt+ cr1,slamit /* It was empty, go slam it on in... */ | |
2228 | ||
2229 | lwz r10,0(r6) /* Grab the top part of the PTE */ | |
2230 | rlwinm r12,r6,6,4,19 /* Match up the hash to a page boundary */ | |
2231 | rlwinm r5,r10,5,4,19 /* Extract the VSID to a page boundary */ | |
2232 | rlwinm r10,r10,0,1,31 /* Make it invalid */ | |
2233 | xor r12,r5,r12 /* Calculate vaddr */ | |
2234 | stw r10,0(r6) /* Invalidate the PTE */ | |
2235 | rlwinm r5,r10,7,27,29 ; Move nybble 0 up to subhash position | |
2236 | rlwimi r12,r10,1,0,3 /* Move in the segment portion */ | |
2237 | lis r9,HIGH_ADDR(EXT(tlb_system_lock)) /* Get the TLBIE lock */ | |
2238 | xor r5,r5,r10 ; Splooch nybble 0 and 1 | |
2239 | rlwimi r12,r10,22,4,9 /* Move in the API */ | |
2240 | ori r9,r9,LOW_ADDR(EXT(tlb_system_lock)) /* Grab up the bottom part */ | |
2241 | rlwinm r4,r10,27,27,29 ; Get low 3 bits of the VSID for look-aside hash | |
2242 | ||
2243 | sync /* Make sure the invalid is stored */ | |
2244 | ||
2245 | xor r4,r4,r5 ; Finish splooching nybble 0, 1, and the low bits of the VSID | |
2246 | ||
2247 | tlbhang: lwarx r5,0,r9 /* Get the TLBIE lock */ | |
2248 | ||
2249 | rlwinm r4,r4,0,27,29 ; Clean up splooched hash value | |
1c79356b | 2250 | |
de355530 A |
2251 | mr. r5,r5 /* Is it locked? */ |
2252 | add r4,r4,r8 /* Point to the offset into the PCA area */ | |
2253 | li r5,1 /* Get our lock word */ | |
2254 | bne- tlbhang /* It's locked, go wait... */ | |
2255 | ||
2256 | la r4,PCAhash(r4) /* Point to the start of the hash chain for the PTE we're replacing */ | |
d7e50217 | 2257 | |
de355530 A |
2258 | stwcx. r5,0,r9 /* Try to get it */ |
2259 | bne- tlbhang /* We was beat... */ | |
2260 | ||
2261 | mfspr r7,pvr /* Find out what kind of machine we are */ | |
2262 | li r5,0 /* Lock clear value */ | |
2263 | rlwinm r7,r7,16,16,31 /* Isolate CPU type */ | |
1c79356b | 2264 | |
de355530 | 2265 | tlbie r12 /* Invalidate it everywhere */ |
1c79356b | 2266 | |
de355530 A |
2267 | cmplwi r7,3 /* Is this a 603? */ |
2268 | stw r5,0(r9) /* Clear the lock */ | |
2269 | ||
2270 | beq- its603 /* It's a 603, skip the tlbsync... */ | |
2271 | ||
2272 | eieio /* Make sure that the tlbie happens first */ | |
2273 | tlbsync /* wait for everyone to catch up */ | |
2274 | isync | |
2275 | ||
2276 | its603: rlwinm. r21,r21,0,0,0 ; See if we just stole an autogenned entry | |
2277 | sync /* Make sure of it all */ | |
1c79356b | 2278 | |
de355530 A |
2279 | bne slamit ; The old was an autogen, time to slam the new in... |
2280 | ||
2281 | lwz r9,4(r6) /* Get the real portion of old PTE */ | |
2282 | lwz r7,0(r4) /* Get the first element. We can't get to here | |
2283 | if we aren't working with a mapping... */ | |
2284 | mr r0,r7 ; Save pointer to first element | |
2285 | ||
2286 | findold: mr r1,r11 ; Save the previous guy | |
2287 | mr. r11,r7 /* Copy and test the chain */ | |
2288 | beq- bebad /* Assume it's not zero... */ | |
1c79356b | 2289 | |
de355530 A |
2290 | lwz r5,mmPTEv(r11) /* See if this is the old active one */ |
2291 | cmplw cr2,r11,r14 /* Check if this is actually the new one */ | |
2292 | cmplw r5,r10 /* Is this us? (Note: valid bit kept off in mappings) */ | |
2293 | lwz r7,mmhashnext(r11) /* Get the next one in line */ | |
2294 | beq- cr2,findold /* Don't count the new one... */ | |
2295 | cmplw cr2,r11,r0 ; Check if we are first on the list | |
2296 | bne+ findold /* Not it (and assume the worst)... */ | |
2297 | ||
2298 | lwz r12,mmphysent(r11) /* Get the pointer to the physical entry */ | |
2299 | beq- cr2,nomove ; We are first, no need to requeue... | |
1c79356b | 2300 | |
de355530 A |
2301 | stw r11,0(r4) ; Chain us to the head |
2302 | stw r0,mmhashnext(r11) ; Chain the old head to us | |
2303 | stw r7,mmhashnext(r1) ; Unlink us | |
d7e50217 | 2304 | |
de355530 A |
2305 | nomove: li r5,0 /* Clear this on out */ |
2306 | ||
2307 | mr. r12,r12 /* Is there a physical entry? */ | |
2308 | stw r5,mmPTEent(r11) ; Clear the PTE entry pointer | |
2309 | li r5,pepte1 /* Point to the PTE last half */ | |
2310 | stw r9,mmPTEr(r11) ; Squirrel away the whole thing (RC bits are in here) | |
1c79356b | 2311 | |
de355530 A |
2312 | beq- mrgmrcx ; No physical entry for this one... |
2313 | ||
2314 | rlwinm r11,r9,0,23,24 /* Keep only the RC bits */ | |
d7e50217 | 2315 | |
de355530 A |
2316 | mrgmrcx: lwarx r9,r5,r12 /* Get the master copy */ |
2317 | or r9,r9,r11 /* Merge in latest RC */ | |
2318 | stwcx. r9,r5,r12 /* Save it back */ | |
2319 | bne- mrgmrcx /* If it changed, try again... */ | |
d7e50217 | 2320 | |
de355530 A |
2321 | /* |
2322 | * Here's where we finish up. We save the real part of the PTE, eieio it, to make sure it's | |
2323 | * out there before the top half (with the valid bit set). | |
2324 | */ | |
d7e50217 | 2325 | |
de355530 A |
2326 | slamit: stw r2,4(r6) /* Stash the real part */ |
2327 | li r4,0 /* Get a lock clear value */ | |
2328 | eieio /* Erect a barricade */ | |
2329 | stw r3,0(r6) /* Stash the virtual part and set valid on */ | |
2330 | ||
2331 | stw r4,PCAlock(r8) /* Clear the PCA lock */ | |
2332 | ||
2333 | li r3,T_IN_VAIN /* Say that we handled it */ | |
2334 | sync /* Go no further until the stores complete */ | |
2335 | #if PERFTIMES && DEBUG | |
2336 | mflr r11 | |
2337 | mr r4,r3 | |
2338 | li r3,33 | |
2339 | bl EXT(dbgLog2) ; Start of hw_add_map | |
2340 | mr r3,r4 | |
2341 | mtlr r11 | |
2342 | #endif | |
2343 | blr /* Back to the fold... */ | |
2344 | ||
2345 | bebad: lis r0,HIGH_ADDR(Choke) /* We have a kernel choke!!! */ | |
2346 | ori r0,r0,LOW_ADDR(Choke) | |
2347 | sc /* Firmware Heimlich maneuver */ | |
1c79356b | 2348 | |
de355530 A |
2349 | /* |
2350 | * This walks the hash table or DBATs to locate the physical address of a virtual one. | |
2351 | * The space is provided. If it is the kernel space, the DBATs are searched first. Failing | |
2352 | * that, the hash table is accessed. Zero is returned for failure, so it must be special cased. | |
2353 | * This is usually used for debugging, so we try not to rely | |
2354 | * on anything that we don't have to. | |
2355 | */ | |
d7e50217 | 2356 | |
de355530 | 2357 | ENTRY(LRA, TAG_NO_FRAME_USED) |
1c79356b | 2358 | |
de355530 A |
2359 | mfsprg r8,2 ; Get feature flags |
2360 | mfmsr r10 /* Save the current MSR */ | |
2361 | rlwinm r10,r10,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
2362 | rlwinm r10,r10,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
2363 | mtcrf 0x04,r8 ; Set the features | |
2364 | xoris r5,r3,HIGH_ADDR(PPC_SID_KERNEL) /* Clear the top half if equal */ | |
2365 | andi. r9,r10,0x7FCF /* Turn off interrupts and translation */ | |
2366 | eqv r12,r12,r12 /* Fill the bottom with foxes */ | |
1c79356b | 2367 | |
de355530 | 2368 | bt pfNoMSRirb,lraNoMSR ; No MSR... |
1c79356b | 2369 | |
de355530 A |
2370 | mtmsr r9 ; Translation and all off |
2371 | isync ; Toss prefetch | |
2372 | b lraNoMSRx | |
2373 | ||
2374 | lraNoMSR: | |
2375 | mr r7,r3 | |
2376 | li r0,loadMSR ; Get the MSR setter SC | |
2377 | mr r3,r9 ; Get new MSR | |
2378 | sc ; Set it | |
2379 | mr r3,r7 | |
2380 | lraNoMSRx: | |
2381 | ||
2382 | cmplwi r5,LOW_ADDR(PPC_SID_KERNEL) /* See if this is kernel space */ | |
2383 | rlwinm r11,r3,6,6,25 /* Position the space for the VSID */ | |
2384 | isync /* Purge pipe */ | |
2385 | bne- notkernsp /* This is not for the kernel... */ | |
2386 | ||
2387 | mfspr r5,dbat0u /* Get the virtual address and length */ | |
2388 | eqv r8,r8,r8 /* Get all foxes */ | |
2389 | rlwinm. r0,r5,0,30,30 /* Check if valid for supervisor state */ | |
2390 | rlwinm r7,r5,0,0,14 /* Clean up the base virtual address */ | |
2391 | beq- ckbat1 /* not valid, skip this one... */ | |
2392 | sub r7,r4,r7 /* Subtract out the base */ | |
2393 | rlwimi r8,r5,15,0,14 /* Get area length - 1 */ | |
2394 | mfspr r6,dbat0l /* Get the real part */ | |
2395 | cmplw r7,r8 /* Check if it is in the range */ | |
2396 | bng+ fndbat /* Yup, she's a good un... */ | |
2397 | ||
2398 | ckbat1: mfspr r5,dbat1u /* Get the virtual address and length */ | |
2399 | eqv r8,r8,r8 /* Get all foxes */ | |
2400 | rlwinm. r0,r5,0,30,30 /* Check if valid for supervisor state */ | |
2401 | rlwinm r7,r5,0,0,14 /* Clean up the base virtual address */ | |
2402 | beq- ckbat2 /* not valid, skip this one... */ | |
2403 | sub r7,r4,r7 /* Subtract out the base */ | |
2404 | rlwimi r8,r5,15,0,14 /* Get area length - 1 */ | |
2405 | mfspr r6,dbat1l /* Get the real part */ | |
2406 | cmplw r7,r8 /* Check if it is in the range */ | |
2407 | bng+ fndbat /* Yup, she's a good un... */ | |
2408 | ||
2409 | ckbat2: mfspr r5,dbat2u /* Get the virtual address and length */ | |
2410 | eqv r8,r8,r8 /* Get all foxes */ | |
2411 | rlwinm. r0,r5,0,30,30 /* Check if valid for supervisor state */ | |
2412 | rlwinm r7,r5,0,0,14 /* Clean up the base virtual address */ | |
2413 | beq- ckbat3 /* not valid, skip this one... */ | |
2414 | sub r7,r4,r7 /* Subtract out the base */ | |
2415 | rlwimi r8,r5,15,0,14 /* Get area length - 1 */ | |
2416 | mfspr r6,dbat2l /* Get the real part */ | |
2417 | cmplw r7,r8 /* Check if it is in the range */ | |
2418 | bng- fndbat /* Yup, she's a good un... */ | |
2419 | ||
2420 | ckbat3: mfspr r5,dbat3u /* Get the virtual address and length */ | |
2421 | eqv r8,r8,r8 /* Get all foxes */ | |
2422 | rlwinm. r0,r5,0,30,30 /* Check if valid for supervisor state */ | |
2423 | rlwinm r7,r5,0,0,14 /* Clean up the base virtual address */ | |
2424 | beq- notkernsp /* not valid, skip this one... */ | |
2425 | sub r7,r4,r7 /* Subtract out the base */ | |
2426 | rlwimi r8,r5,15,0,14 /* Get area length - 1 */ | |
2427 | mfspr r6,dbat3l /* Get the real part */ | |
2428 | cmplw r7,r8 /* Check if it is in the range */ | |
2429 | bgt+ notkernsp /* No good... */ | |
2430 | ||
2431 | fndbat: rlwinm r6,r6,0,0,14 /* Clean up the real address */ | |
2432 | mtmsr r10 /* Restore state */ | |
2433 | add r3,r7,r6 /* Relocate the offset to real */ | |
2434 | isync /* Purge pipe */ | |
2435 | blr /* Bye, bye... */ | |
2436 | ||
2437 | notkernsp: mfspr r5,sdr1 /* Get hash table base and size */ | |
2438 | rlwimi r11,r4,30,2,5 /* Insert the segment no. to make a VSID */ | |
2439 | rlwimi r12,r5,16,0,15 /* Make table size -1 out of mask */ | |
2440 | rlwinm r7,r4,26,10,25 /* Isolate the page index */ | |
2441 | andc r5,r5,r12 /* Clean up the hash table */ | |
2442 | xor r7,r7,r11 /* Get primary hash */ | |
2443 | rlwinm r11,r11,1,1,24 /* Position VSID for pte ID */ | |
2444 | and r7,r7,r12 /* Wrap the hash */ | |
2445 | rlwimi r11,r4,10,26,31 /* Move API into pte ID */ | |
2446 | add r5,r7,r5 /* Point to the PTEG */ | |
2447 | oris r11,r11,0x8000 /* Slam on valid bit so's we don't match an invalid one */ | |
2448 | ||
2449 | li r9,8 /* Get the number of PTEs to check */ | |
2450 | lwz r6,0(r5) /* Preload the virtual half */ | |
2451 | ||
2452 | fndpte: subi r9,r9,1 /* Count the pte */ | |
2453 | lwz r3,4(r5) /* Get the real half */ | |
2454 | cmplw cr1,r6,r11 /* Is this what we want? */ | |
2455 | lwz r6,8(r5) /* Start to get the next virtual half */ | |
2456 | mr. r9,r9 /* Any more to try? */ | |
2457 | addi r5,r5,8 /* Bump to next slot */ | |
2458 | beq cr1,gotxlate /* We found what we were looking for... */ | |
2459 | bne+ fndpte /* Go try the next PTE... */ | |
2460 | ||
2461 | mtmsr r10 /* Restore state */ | |
2462 | li r3,0 /* Show failure */ | |
2463 | isync /* Purge pipe */ | |
2464 | blr /* Leave... */ | |
2465 | ||
2466 | gotxlate: mtmsr r10 /* Restore state */ | |
2467 | rlwimi r3,r4,0,20,31 /* Cram in the page displacement */ | |
2468 | isync /* Purge pipe */ | |
2469 | blr /* Return... */ | |
1c79356b | 2470 | |
1c79356b A |
2471 | |
2472 | ||
de355530 A |
2473 | /* |
2474 | * struct blokmap *hw_add_blk(pmap_t pmap, struct blokmap *bmr) | |
2475 | * | |
2476 | * This is used to add a block mapping entry to the MRU list whose top | |
2477 | * node is anchored at bmaps. This is a real address and is also used as | |
2478 | * the lock. | |
2479 | * | |
2480 | * Overlapping areas are not allowed. If we find one, we return it's address and | |
2481 | * expect the upper layers to panic. We only check this for a debug build... | |
2482 | * | |
2483 | */ | |
1c79356b | 2484 | |
de355530 A |
2485 | .align 5 |
2486 | .globl EXT(hw_add_blk) | |
1c79356b | 2487 | |
de355530 | 2488 | LEXT(hw_add_blk) |
1c79356b | 2489 | |
de355530 A |
2490 | mfsprg r9,2 ; Get feature flags |
2491 | lwz r6,PMAP_PMAPVR(r3) ; Get the v to r translation | |
2492 | mfmsr r0 /* Save the MSR */ | |
2493 | rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
2494 | rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
2495 | rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ | |
2496 | mtcrf 0x04,r9 ; Set the features | |
2497 | xor r3,r3,r6 ; Get real address of bmap anchor | |
2498 | rlwinm r12,r12,0,28,25 /* Clear IR and DR */ | |
2499 | la r3,PMAP_BMAPS(r3) ; Point to bmap header | |
d7e50217 | 2500 | |
de355530 | 2501 | bt pfNoMSRirb,habNoMSR ; No MSR... |
1c79356b | 2502 | |
de355530 A |
2503 | mtmsr r12 ; Translation and all off |
2504 | isync ; Toss prefetch | |
2505 | b habNoMSRx | |
1c79356b | 2506 | |
de355530 A |
2507 | habNoMSR: |
2508 | mr r9,r0 | |
2509 | mr r8,r3 | |
2510 | li r0,loadMSR ; Get the MSR setter SC | |
2511 | mr r3,r12 ; Get new MSR | |
2512 | sc ; Set it | |
2513 | mr r3,r8 | |
2514 | mr r0,r9 | |
2515 | habNoMSRx: | |
2516 | ||
2517 | abLck: lwarx r9,0,r3 ; Get the block map anchor and lock | |
2518 | rlwinm. r8,r9,0,31,31 ; Is it locked? | |
2519 | ori r8,r9,1 ; Set the lock | |
2520 | bne- abLckw ; Yeah... | |
2521 | stwcx. r8,0,r3 ; Lock the bmap list | |
2522 | bne- abLck ; Someone else was trying, try again... | |
2523 | b abSXg ; All done... | |
1c79356b | 2524 | |
de355530 | 2525 | .align 4 |
1c79356b | 2526 | |
de355530 A |
2527 | abLckw: rlwinm. r5,r9,0,31,31 ; Check if it is still held |
2528 | beq+ abLck ; Not no more... | |
2529 | lwz r9,0(r3) ; Get lock word again... | |
2530 | b abLckw ; Check it out... | |
1c79356b | 2531 | |
de355530 | 2532 | .align 5 |
d7e50217 | 2533 | |
de355530 A |
2534 | nop ; Force ISYNC to last instruction in IFETCH |
2535 | nop | |
d7e50217 | 2536 | |
de355530 A |
2537 | abSXg: rlwinm r11,r9,0,0,26 ; Clear out flags and lock |
2538 | isync ; Make sure we have not used anything yet | |
d7e50217 | 2539 | |
de355530 A |
2540 | ; |
2541 | ; | |
2542 | ; | |
d7e50217 | 2543 | |
de355530 A |
2544 | lwz r7,bmstart(r4) ; Get start |
2545 | lwz r8,bmend(r4) ; Get end | |
2546 | mr r2,r11 ; Get chain | |
2547 | ||
2548 | abChk: mr. r10,r2 ; End of chain? | |
2549 | beq abChkD ; Yes, chain is ok... | |
2550 | lwz r5,bmstart(r10) ; Get start of current area | |
2551 | lwz r6,bmend(r10) ; Get end of current area | |
2552 | ||
2553 | cmplw cr0,r8,r5 ; Is the end of the new before the old? | |
2554 | cmplw cr1,r8,r6 ; Is the end of the new after the old? | |
2555 | cmplw cr6,r6,r7 ; Is the end of the old before the new? | |
2556 | cror cr1_eq,cr0_lt,cr1_gt ; Set cr1_eq if new not in old | |
2557 | cmplw cr7,r6,r8 ; Is the end of the old after the new? | |
2558 | lwz r2,bmnext(r10) ; Get pointer to the next | |
2559 | cror cr6_eq,cr6_lt,cr7_gt ; Set cr2_eq if old not in new | |
2560 | crand cr1_eq,cr1_eq,cr6_eq ; Set cr1_eq if no overlap | |
2561 | beq+ cr1,abChk ; Ok check the next... | |
2562 | ||
2563 | lwz r8,blkFlags(r10) ; Get the flags | |
2564 | rlwinm. r8,r8,0,blkRembit,blkRembit ; Check the blkRem bit | |
2565 | beq abRet ; Is the mapping partially removed | |
2566 | ori r10,r10,2 ; Indicate that this block is partially removed | |
2567 | abRet: | |
2568 | stw r9,0(r3) ; Unlock | |
2569 | mtmsr r0 ; Restore xlation and rupts | |
2570 | mr r3,r10 ; Pass back the overlap | |
2571 | isync ; | |
2572 | blr ; Return... | |
1c79356b | 2573 | |
de355530 A |
2574 | abChkD: stw r11,bmnext(r4) ; Chain this on in |
2575 | rlwimi r4,r9,0,27,31 ; Copy in locks and flags | |
2576 | sync ; Make sure that is done | |
1c79356b | 2577 | |
de355530 A |
2578 | stw r4,0(r3) ; Unlock and chain the new first one |
2579 | mtmsr r0 ; Restore xlation and rupts | |
2580 | li r3,0 ; Pass back a no failure return code | |
2581 | isync | |
2582 | blr ; Return... | |
d7e50217 | 2583 | |
d7e50217 | 2584 | |
de355530 A |
2585 | /* |
2586 | * struct blokmap *hw_rem_blk(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) | |
2587 | * | |
2588 | * This is used to remove a block mapping entry from the list that | |
2589 | * is anchored at bmaps. bmaps is a virtual address and is also used as | |
2590 | * the lock. | |
2591 | * | |
2592 | * Note that this function clears a single block that contains | |
2593 | * any address within the range sva to eva (inclusive). To entirely | |
2594 | * clear any range, hw_rem_blk must be called repeatedly until it | |
2595 | * returns a 0. | |
2596 | * | |
2597 | * The block is removed from the list and all hash table entries | |
2598 | * corresponding to the mapped block are invalidated and the TLB | |
2599 | * entries are purged. If the block is large, this could take | |
2600 | * quite a while. We need to hash every possible address in the | |
2601 | * range and lock down the PCA. | |
2602 | * | |
2603 | * If we attempt to remove a permanent entry, we will not do it. | |
2604 | * The block address will be ored with 1 and returned. | |
2605 | * | |
2606 | * | |
2607 | */ | |
9bccf70c | 2608 | |
de355530 A |
2609 | .align 5 |
2610 | .globl EXT(hw_rem_blk) | |
9bccf70c | 2611 | |
de355530 | 2612 | LEXT(hw_rem_blk) |
9bccf70c | 2613 | |
de355530 A |
2614 | mfsprg r9,2 ; Get feature flags |
2615 | lwz r6,PMAP_PMAPVR(r3) ; Get the v to r translation | |
2616 | mfmsr r0 /* Save the MSR */ | |
2617 | rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
2618 | rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
2619 | rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ | |
2620 | mtcrf 0x04,r9 ; Set the features | |
2621 | xor r3,r3,r6 ; Get real address of bmap anchor | |
2622 | rlwinm r12,r12,0,28,25 /* Clear IR and DR */ | |
2623 | la r3,PMAP_BMAPS(r3) ; Point to the bmap chain head | |
9bccf70c | 2624 | |
de355530 | 2625 | bt pfNoMSRirb,hrbNoMSR ; No MSR... |
d7e50217 | 2626 | |
de355530 A |
2627 | mtmsr r12 ; Translation and all off |
2628 | isync ; Toss prefetch | |
2629 | b hrbNoMSRx | |
2630 | ||
2631 | hrbNoMSR: | |
2632 | mr r9,r0 | |
2633 | mr r8,r3 | |
2634 | li r0,loadMSR ; Get the MSR setter SC | |
2635 | mr r3,r12 ; Get new MSR | |
2636 | sc ; Set it | |
2637 | mr r3,r8 | |
2638 | mr r0,r9 | |
2639 | hrbNoMSRx: | |
2640 | li r7,0 | |
2641 | cmp cr5,r0,r7 ; Request to invalidate the ptes | |
2642 | b rbLck | |
d7e50217 | 2643 | |
de355530 A |
2644 | rbunlink: |
2645 | lwz r4,bmstart(r10) ; Get start of current mapping | |
2646 | lwz r5,bmend(r10) ; Get end of current mapping | |
2647 | cmp cr5,r3,r3 ; Request to unlink the mapping | |
2648 | ||
2649 | rbLck: lwarx r9,0,r3 ; Get the block map anchor and lock | |
2650 | rlwinm. r8,r9,0,31,31 ; Is it locked? | |
2651 | ori r8,r9,1 ; Set the lock | |
2652 | bne- rbLckw ; Yeah... | |
2653 | stwcx. r8,0,r3 ; Lock the bmap list | |
2654 | bne- rbLck ; Someone else was trying, try again... | |
2655 | b rbSXg ; All done... | |
d7e50217 | 2656 | |
de355530 A |
2657 | .align 4 |
2658 | ||
2659 | rbLckw: rlwinm. r11,r9,0,31,31 ; Check if it is still held | |
2660 | beq+ rbLck ; Not no more... | |
2661 | lwz r9,0(r3) ; Get lock word again... | |
2662 | b rbLckw ; Check it out... | |
d7e50217 A |
2663 | |
2664 | .align 5 | |
1c79356b | 2665 | |
de355530 A |
2666 | nop ; Force ISYNC to last instruction in IFETCH |
2667 | nop | |
2668 | ||
2669 | rbSXg: rlwinm. r2,r9,0,0,26 ; Clear out flags and lock | |
2670 | mr r10,r3 ; Keep anchor as previous pointer | |
2671 | isync ; Make sure we have not used anything yet | |
1c79356b | 2672 | |
de355530 | 2673 | beq- rbMT ; There is nothing in the list |
d7e50217 | 2674 | |
de355530 A |
2675 | rbChk: mr r12,r10 ; Save the previous |
2676 | mr. r10,r2 ; End of chain? | |
2677 | beq rbMT ; Yes, nothing to do... | |
2678 | lwz r11,bmstart(r10) ; Get start of current area | |
2679 | lwz r6,bmend(r10) ; Get end of current area | |
d7e50217 | 2680 | |
de355530 A |
2681 | cmplw cr0,r5,r11 ; Is the end of range before the start of the area? |
2682 | cmplw cr1,r4,r6 ; Is the start of range after the end of the area? | |
2683 | cror cr1_eq,cr0_lt,cr1_gt ; Set cr1_eq if new not in range | |
2684 | lwz r2,bmnext(r10) ; Get the next one | |
2685 | beq+ cr1,rbChk ; Not this one, check the next... | |
2686 | ||
2687 | cmplw cr1,r12,r3 ; Is the current mapping the first one? | |
2688 | ||
2689 | bne cr5,rbblkRem ; Do we have to unchain the mapping | |
2690 | ||
2691 | bne cr1,rbnFirst ; Yes, is this the first mapping? | |
2692 | rlwimi r9,r2,0,0,26 ; Yes, Change the lock value | |
2693 | ori r2,r9,1 ; Turn on the lock bit | |
2694 | rbnFirst: | |
2695 | stw r2,bmnext(r12) ; Unchain us | |
2696 | sync | |
2697 | b rbDone | |
2698 | ||
2699 | rbblkRem: | |
2700 | ||
2701 | lwz r8,blkFlags(r10) ; Get the flags | |
d7e50217 | 2702 | |
de355530 | 2703 | rlwinm. r7,r8,0,blkPermbit,blkPermbit ; is this a permanent block? |
d7e50217 | 2704 | |
de355530 | 2705 | bne- rbPerm ; This is permanent, do not remove... |
9bccf70c | 2706 | |
de355530 | 2707 | rlwinm. r7,r8,0,blkRembit,blkRembit ; is this mapping partially removed |
9bccf70c | 2708 | |
de355530 A |
2709 | beq rbblkRemcont ; If not, check the max size |
2710 | lwz r11,bmcurrent(r10) ; If yes, resume for the current page | |
9bccf70c | 2711 | |
de355530 A |
2712 | cmp cr5,r11,r6 ; No partial remove left |
2713 | beq cr5, rbpendret ; But there is a pending remove | |
9bccf70c | 2714 | |
de355530 A |
2715 | rbblkRemcont: |
2716 | bne rbblkRemcont1 ; Is it the first remove | |
0b4e3aa0 | 2717 | |
de355530 A |
2718 | oris r8,r8,hi16(blkRem) ; Yes |
2719 | stw r8,blkFlags(r10) ; set the blkRem bit in blkFlags | |
9bccf70c | 2720 | |
de355530 A |
2721 | rbblkRemcont1: |
2722 | lis r5,hi16(BLKREMMAX*4096) ; Load maximun size tear down | |
2723 | ori r5,r5,lo16(BLKREMMAX*4096) ; Load maximun size tear down | |
2724 | sub r7,r6,r11 ; Get the remaining size to tear down | |
2725 | cmp cr5,r7,r5 ; Compare against the maximun size | |
2726 | ble cr5,rbfullblk ; If less or equal, go remove the mapping | |
9bccf70c | 2727 | |
de355530 A |
2728 | add r7,r11,r5 ; Add the max size tear down to the current page |
2729 | stw r7,bmcurrent(r10) ; Update the current page | |
2730 | subi r6,r7,1 ; Set the current end of the partial tear down | |
2731 | b rbcont | |
9bccf70c | 2732 | |
de355530 A |
2733 | rbfullblk: |
2734 | stw r6,bmcurrent(r10) ; Update the current page | |
9bccf70c | 2735 | |
de355530 A |
2736 | rbcont: |
2737 | lwz r8,bmspace(r10) ; Get the VSID | |
2738 | sync | |
2739 | stw r9,0(r3) ; Unlock and chain the new first one | |
2740 | ||
2741 | eqv r4,r4,r4 ; Fill the bottom with foxes | |
2742 | mfspr r12,sdr1 ; Get hash table base and size | |
2743 | rlwinm r8,r8,6,0,25 ; Align VSID to PTEG | |
2744 | rlwimi r4,r12,16,0,15 ; Make table size - 1 out of mask | |
2745 | andc r12,r12,r4 ; Clean up address of hash table | |
2746 | rlwinm r5,r11,26,6,25 ; Rotate virtual start address into PTEG units | |
2747 | add r12,r12,r4 ; Point to PCA - 1 | |
2748 | rlwinm r6,r6,26,6,25 ; Rotate virtual end address into PTEG units | |
2749 | addi r12,r12,1 ; Point to PCA base | |
2750 | sub r6,r6,r5 ; Get the total number of PTEGs to clear | |
2751 | cmplw r6,r4 ; See if this wraps all the way around | |
2752 | blt rbHash ; Nope, length is right | |
2753 | subi r6,r4,32+31 ; Back down to correct length | |
2754 | ||
2755 | rbHash: rlwinm r5,r5,0,10,25 ; Keep only the page index | |
2756 | xor r2,r8,r5 ; Hash into table | |
2757 | and r2,r2,r4 ; Wrap into the table | |
2758 | add r2,r2,r12 ; Point right at the PCA | |
2759 | ||
2760 | rbLcka: lwarx r7,0,r2 ; Get the PTEG lock | |
2761 | mr. r7,r7 ; Is it locked? | |
2762 | bne- rbLckwa ; Yeah... | |
2763 | li r7,1 ; Get the locked value | |
2764 | stwcx. r7,0,r2 ; Take it | |
2765 | bne- rbLcka ; Someone else was trying, try again... | |
2766 | b rbSXga ; All done... | |
2767 | ||
2768 | rbLckwa: mr. r7,r7 ; Check if it is already held | |
2769 | beq+ rbLcka ; It is clear... | |
2770 | lwz r7,0(r2) ; Get lock word again... | |
2771 | b rbLckwa ; Wait... | |
2772 | ||
2773 | rbSXga: isync ; Make sure nothing used yet | |
2774 | lwz r7,PCAallo(r2) ; Get the allocation word | |
2775 | rlwinm. r11,r7,8,0,7 ; Isolate the autogenerated PTEs | |
2776 | or r7,r7,r11 ; Release the autogen slots | |
2777 | beq+ rbAintNone ; There are not any here | |
2778 | mtcrf 0xC0,r11 ; Set the branch masks for autogens | |
2779 | sub r11,r2,r4 ; Move back to the hash table + 1 | |
2780 | rlwinm r7,r7,0,16,7 ; Clear the autogen field | |
2781 | subi r11,r11,1 ; Point to the PTEG | |
2782 | stw r7,PCAallo(r2) ; Update the flags | |
2783 | li r7,0 ; Get an invalid PTE value | |
2784 | ||
2785 | bf 0,rbSlot1 ; No autogen here | |
2786 | stw r7,0x00(r11) ; Invalidate PTE | |
2787 | rbSlot1: bf 1,rbSlot2 ; No autogen here | |
2788 | stw r7,0x08(r11) ; Invalidate PTE | |
2789 | rbSlot2: bf 2,rbSlot3 ; No autogen here | |
2790 | stw r7,0x10(r11) ; Invalidate PTE | |
2791 | rbSlot3: bf 3,rbSlot4 ; No autogen here | |
2792 | stw r7,0x18(r11) ; Invalidate PTE | |
2793 | rbSlot4: bf 4,rbSlot5 ; No autogen here | |
2794 | stw r7,0x20(r11) ; Invalidate PTE | |
2795 | rbSlot5: bf 5,rbSlot6 ; No autogen here | |
2796 | stw r7,0x28(r11) ; Invalidate PTE | |
2797 | rbSlot6: bf 6,rbSlot7 ; No autogen here | |
2798 | stw r7,0x30(r11) ; Invalidate PTE | |
2799 | rbSlot7: bf 7,rbSlotx ; No autogen here | |
2800 | stw r7,0x38(r11) ; Invalidate PTE | |
2801 | rbSlotx: | |
2802 | ||
2803 | rbAintNone: li r7,0 ; Clear this out | |
2804 | sync ; To make SMP happy | |
2805 | addic. r6,r6,-64 ; Decrement the count | |
2806 | stw r7,PCAlock(r2) ; Release the PTEG lock | |
2807 | addi r5,r5,64 ; Move up by adjusted page number | |
2808 | bge+ rbHash ; Not done... | |
2809 | ||
2810 | sync ; Make sure the memory is quiet | |
1c79356b | 2811 | |
de355530 A |
2812 | ; |
2813 | ; Here we take the easy way out and just purge the entire TLB. This is | |
2814 | ; certainly faster and definitly easier than blasting just the correct ones | |
2815 | ; in the range, we only need one lock and one TLBSYNC. We would hope | |
2816 | ; that most blocks are more than 64 pages (256K) and on every machine | |
2817 | ; up to Book E, 64 TLBIEs will invalidate the entire table. | |
2818 | ; | |
1c79356b | 2819 | |
de355530 A |
2820 | li r5,64 ; Get number of TLB entries to purge |
2821 | lis r12,HIGH_ADDR(EXT(tlb_system_lock)) ; Get the TLBIE lock | |
2822 | li r6,0 ; Start at 0 | |
2823 | ori r12,r12,LOW_ADDR(EXT(tlb_system_lock)) ; Grab up the bottom part | |
1c79356b | 2824 | |
de355530 A |
2825 | rbTlbL: lwarx r2,0,r12 ; Get the TLBIE lock |
2826 | mr. r2,r2 ; Is it locked? | |
2827 | li r2,1 ; Get our lock value | |
2828 | bne- rbTlbL ; It is locked, go wait... | |
2829 | stwcx. r2,0,r12 ; Try to get it | |
2830 | bne- rbTlbL ; We was beat... | |
2831 | ||
2832 | rbTlbN: addic. r5,r5,-1 ; See if we did them all | |
2833 | tlbie r6 ; Invalidate it everywhere | |
2834 | addi r6,r6,0x1000 ; Up to the next page | |
2835 | bgt+ rbTlbN ; Make sure we have done it all... | |
1c79356b | 2836 | |
de355530 A |
2837 | mfspr r5,pvr ; Find out what kind of machine we are |
2838 | li r2,0 ; Lock clear value | |
1c79356b | 2839 | |
de355530 A |
2840 | rlwinm r5,r5,16,16,31 ; Isolate CPU type |
2841 | cmplwi r5,3 ; Is this a 603? | |
2842 | sync ; Make sure all is quiet | |
2843 | beq- rbits603a ; It is a 603, skip the tlbsync... | |
d7e50217 | 2844 | |
de355530 A |
2845 | eieio ; Make sure that the tlbie happens first |
2846 | tlbsync ; wait for everyone to catch up | |
2847 | isync | |
9bccf70c | 2848 | |
de355530 A |
2849 | rbits603a: sync ; Wait for quiet again |
2850 | stw r2,0(r12) ; Unlock invalidates | |
d7e50217 | 2851 | |
de355530 | 2852 | sync ; Make sure that is done |
1c79356b | 2853 | |
de355530 A |
2854 | ble cr5,rbunlink ; If all ptes are flush, go unlink the mapping |
2855 | mtmsr r0 ; Restore xlation and rupts | |
2856 | mr r3,r10 ; Pass back the removed block in progress | |
2857 | ori r3,r3,2 ; Indicate that the block remove isn't completed yet | |
2858 | isync | |
2859 | blr ; Return... | |
1c79356b | 2860 | |
de355530 A |
2861 | rbpendret: |
2862 | stw r9,0(r3) ; Unlock | |
2863 | mtmsr r0 ; Restore xlation and rupts | |
2864 | mr r3,r10 ; Pass back the removed block in progress | |
2865 | ori r3,r3,2 ; Indicate that the block remove isn't completed yet | |
2866 | isync | |
2867 | blr ; Return... | |
9bccf70c | 2868 | |
9bccf70c | 2869 | |
de355530 A |
2870 | rbMT: stw r9,0(r3) ; Unlock |
2871 | mtmsr r0 ; Restore xlation and rupts | |
2872 | li r3,0 ; Say we did not find one | |
2873 | isync | |
2874 | blr ; Return... | |
d7e50217 | 2875 | |
de355530 A |
2876 | rbPerm: stw r9,0(r3) ; Unlock |
2877 | mtmsr r0 ; Restore xlation and rupts | |
2878 | ori r3,r10,1 ; Say we did not remove it | |
2879 | isync | |
2880 | blr ; Return... | |
9bccf70c | 2881 | |
de355530 A |
2882 | rbDone: stw r9,0(r3) ; Unlock |
2883 | mtmsr r0 ; Restore xlation and rupts | |
2884 | mr r3,r10 ; Pass back the removed block | |
2885 | isync | |
2886 | blr ; Return... | |
1c79356b | 2887 | |
de355530 A |
2888 | /* |
2889 | * hw_select_mappings(struct mappingflush *mappingflush) | |
2890 | * | |
2891 | * Input: PCA addr | |
2892 | * Ouput: up to 8 user mappings | |
2893 | * | |
2894 | * hw_select_mappings() scans every PCA mapping hash lists and select | |
2895 | * the last user mapping if it exists. | |
2896 | * | |
2897 | */ | |
1c79356b | 2898 | |
de355530 A |
2899 | .align 5 |
2900 | .globl EXT(hw_select_mappings) | |
1c79356b | 2901 | |
de355530 A |
2902 | LEXT(hw_select_mappings) |
2903 | mr r5,r3 ; Get the mapping flush addr | |
2904 | mfmsr r12 ; Get the MSR | |
2905 | rlwinm r12,r12,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
2906 | rlwinm r12,r12,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
2907 | mfsprg r9,2 ; Get feature flags | |
2908 | andi. r0,r12,0x7FCF ; Disable translation and interruptions | |
2909 | mtcrf 0x04,r9 ; Set the features | |
2910 | bt pfNoMSRirb,hvmNoMSR ; No MSR... | |
2911 | mtmsr r0 | |
2912 | isync | |
2913 | b hvmNoMSRx | |
2914 | hvmNoMSR: | |
2915 | mr r3,r0 ; Get the new MSR | |
2916 | li r0,loadMSR ; Get the MSR setter SC | |
2917 | sc | |
2918 | hvmNoMSRx: | |
2919 | mr r0,r12 | |
2920 | li r11,1 ; Get the locked value | |
2921 | ||
2922 | hvmptegLckx: | |
2923 | lwz r3,MFpcaptr(r5) ; Get the PCA pointer | |
2924 | lwarx r10,0,r3 ; Get the PTEG lock | |
2925 | mr. r10,r10 ; Is it locked? | |
2926 | bne- hvmptegLckwx ; Yeah... | |
2927 | stwcx. r11,0,r3 ; Take take it | |
2928 | bne- hvmptegLckx ; Someone else was trying, try again... | |
2929 | b hvmptegSXgx ; All done... | |
2930 | ||
2931 | .align 4 | |
2932 | ||
2933 | hvmptegLckwx: | |
2934 | mr. r10,r10 ; Check if it is already held | |
2935 | beq+ hvmptegLckx ; It's clear... | |
2936 | lwz r10,0(r3) ; Get lock word again... | |
2937 | b hvmptegLckwx ; Wait... | |
2938 | ||
2939 | .align 4 | |
2940 | ||
2941 | hvmptegSXgx: | |
2942 | isync ; Make sure we haven't used anything yet | |
2943 | ||
2944 | li r11,8 ; set count to 8 | |
2945 | ||
2946 | lwz r6,PCAhash(r3) ; load the first mapping hash list | |
2947 | la r12,PCAhash(r3) ; Point to the mapping hash area | |
2948 | la r4,MFmapping(r5) ; Point to the mapping flush mapping area | |
2949 | li r7,0 ; Load zero | |
2950 | stw r7,MFmappingcnt(r5) ; Set the current count to 0 | |
2951 | hvmnexthash: | |
2952 | li r10,0 ; Mapping test | |
2953 | ||
2954 | hvmfindmap: | |
2955 | mr. r6,r6 ; Test if the hash list current pointer is zero | |
2956 | beq hvmfindmapret ; Did we hit the end of the hash list | |
2957 | lwz r7,mmPTEv(r6) ; Pick up our virtual ID | |
2958 | rlwinm r8,r7,5,0,19 ; Pick VSID 20 lower bits | |
2959 | mr. r8,r8 | |
2960 | beq hvmfindmapnext ; Skip Kernel VSIDs | |
2961 | rlwinm r8,r7,1,0,3 ; Extract the Segment index | |
2962 | rlwinm r9,r7,22,4,9 ; Extract API 6 upper bits | |
2963 | or r8,r8,r9 ; Add to the virtual address | |
2964 | rlwinm r9,r7,31,6,25 ; Pick VSID 19 lower bits | |
2965 | xor r9,r9,r3 ; Exclusive or with the PCA address | |
2966 | rlwinm r9,r9,6,10,19 ; Extract API 10 lower bits | |
2967 | or r8,r8,r9 ; Add to the virtual address | |
2968 | ||
2969 | stw r8,4(r4) ; Store the virtual address | |
2970 | lwz r8,mmpmap(r6) ; Get the pmap | |
2971 | stw r8,0(r4) ; Store the pmap | |
2972 | li r10,1 ; Found one | |
2973 | ||
2974 | hvmfindmapnext: | |
2975 | lwz r6,mmhashnext(r6) ; Pick up next mapping block | |
2976 | b hvmfindmap ; Scan the next mapping | |
2977 | hvmfindmapret: | |
2978 | mr. r10,r10 ; Found mapping | |
2979 | beq hvmnexthashprep ; If not, do not update the mappingflush array | |
2980 | lwz r7,MFmappingcnt(r5) ; Get the current count | |
2981 | addi r7,r7,1 ; Increment the current count | |
2982 | stw r7,MFmappingcnt(r5) ; Store the current count | |
2983 | addi r4,r4,MFmappingSize ; Point to the next mapping flush entry | |
2984 | hvmnexthashprep: | |
2985 | addi r12,r12,4 ; Load the next hash list | |
2986 | lwz r6,0(r12) ; Load the next hash list entry | |
2987 | subi r11,r11,1 ; Decrement hash list index | |
2988 | mr. r11,r11 ; Test for a remaining hash list | |
2989 | bne hvmnexthash ; Loop to scan the next hash list | |
2990 | ||
2991 | li r10,0 | |
2992 | stw r10,0(r3) ; Unlock the hash list | |
2993 | mtmsr r0 ; Restore translation and interruptions | |
2994 | isync | |
2995 | blr | |
1c79356b | 2996 | |
de355530 A |
2997 | /* |
2998 | * vm_offset_t hw_cvp_blk(pmap_t pmap, vm_offset_t va) | |
2999 | * | |
3000 | * This is used to translate a virtual address within a block mapping entry | |
3001 | * to a physical address. If not found, 0 is returned. | |
3002 | * | |
3003 | */ | |
1c79356b | 3004 | |
de355530 A |
3005 | .align 5 |
3006 | .globl EXT(hw_cvp_blk) | |
1c79356b | 3007 | |
de355530 A |
3008 | LEXT(hw_cvp_blk) |
3009 | ||
3010 | mfsprg r9,2 ; Get feature flags | |
3011 | lwz r6,PMAP_PMAPVR(r3) ; Get the v to r translation | |
3012 | mfmsr r0 /* Save the MSR */ | |
3013 | rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
3014 | rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
3015 | rlwinm r12,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Clear interruptions */ | |
3016 | mtcrf 0x04,r9 ; Set the features | |
3017 | xor r3,r3,r6 ; Get real address of bmap anchor | |
3018 | rlwinm r12,r12,0,28,25 /* Clear IR and DR */ | |
3019 | la r3,PMAP_BMAPS(r3) ; Point to chain header | |
3020 | ||
3021 | bt pfNoMSRirb,hcbNoMSR ; No MSR... | |
3022 | ||
3023 | mtmsr r12 ; Translation and all off | |
3024 | isync ; Toss prefetch | |
3025 | b hcbNoMSRx | |
1c79356b | 3026 | |
de355530 A |
3027 | hcbNoMSR: |
3028 | mr r9,r0 | |
3029 | mr r8,r3 | |
3030 | li r0,loadMSR ; Get the MSR setter SC | |
3031 | mr r3,r12 ; Get new MSR | |
3032 | sc ; Set it | |
3033 | mr r3,r8 | |
3034 | mr r0,r9 | |
3035 | hcbNoMSRx: | |
3036 | ||
3037 | cbLck: lwarx r9,0,r3 ; Get the block map anchor and lock | |
3038 | rlwinm. r8,r9,0,31,31 ; Is it locked? | |
3039 | ori r8,r9,1 ; Set the lock | |
3040 | bne- cbLckw ; Yeah... | |
3041 | stwcx. r8,0,r3 ; Lock the bmap list | |
3042 | bne- cbLck ; Someone else was trying, try again... | |
3043 | b cbSXg ; All done... | |
3044 | ||
3045 | .align 4 | |
3046 | ||
3047 | cbLckw: rlwinm. r5,r9,0,31,31 ; Check if it is still held | |
3048 | beq+ cbLck ; Not no more... | |
3049 | lwz r9,0(r3) ; Get lock word again... | |
3050 | b cbLckw ; Check it out... | |
3051 | ||
3052 | .align 5 | |
3053 | ||
3054 | nop ; Force ISYNC to last instruction in IFETCH | |
3055 | nop | |
3056 | nop | |
3057 | nop | |
3058 | nop | |
3059 | ||
3060 | cbSXg: rlwinm. r11,r9,0,0,26 ; Clear out flags and lock | |
3061 | li r2,0 ; Assume we do not find anything | |
3062 | isync ; Make sure we have not used anything yet | |
3063 | ||
3064 | cbChk: mr. r11,r11 ; Is there more? | |
3065 | beq- cbDone ; No more... | |
3066 | lwz r5,bmstart(r11) ; Get the bottom of range | |
3067 | lwz r12,bmend(r11) ; Get the top of range | |
3068 | cmplw cr0,r4,r5 ; Are we before the entry? | |
3069 | cmplw cr1,r4,r12 ; Are we after of the entry? | |
3070 | cror cr1_eq,cr0_lt,cr1_gt ; Set cr1_eq if new not in range | |
3071 | beq- cr1,cbNo ; We are not in the range... | |
3072 | ||
3073 | lwz r2,bmPTEr(r11) ; Get the real part of the PTE | |
3074 | sub r5,r4,r5 ; Get offset into area | |
3075 | rlwinm r2,r2,0,0,19 ; Clean out everything but the page | |
3076 | add r2,r2,r5 ; Adjust the real address | |
3077 | ||
3078 | cbDone: stw r9,0(r3) ; Unlock it, we are done with it (no sync needed) | |
3079 | mtmsr r0 ; Restore translation and interrupts... | |
3080 | isync ; Make sure it is on | |
3081 | mr r3,r2 ; Set return physical address | |
1c79356b A |
3082 | blr ; Leave... |
3083 | ||
3084 | .align 5 | |
3085 | ||
de355530 A |
3086 | cbNo: lwz r11,bmnext(r11) ; Link next |
3087 | b cbChk ; Check it out... | |
1c79356b A |
3088 | |
3089 | ||
de355530 A |
3090 | /* |
3091 | * hw_set_user_space(pmap) | |
3092 | * hw_set_user_space_dis(pmap) | |
3093 | * | |
3094 | * Indicate whether memory space needs to be switched. | |
3095 | * We really need to turn off interrupts here, because we need to be non-preemptable | |
3096 | * | |
3097 | * hw_set_user_space_dis is used when interruptions are already disabled. Mind the | |
3098 | * register usage here. The VMM switch code in vmachmon.s that calls this | |
3099 | * know what registers are in use. Check that if these change. | |
3100 | */ | |
1c79356b | 3101 | |
1c79356b | 3102 | |
de355530 | 3103 | |
d7e50217 | 3104 | .align 5 |
de355530 | 3105 | .globl EXT(hw_set_user_space) |
1c79356b | 3106 | |
de355530 | 3107 | LEXT(hw_set_user_space) |
d7e50217 | 3108 | |
de355530 A |
3109 | mfmsr r10 /* Get the current MSR */ |
3110 | rlwinm r10,r10,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
3111 | rlwinm r10,r10,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
3112 | rlwinm r9,r10,0,MSR_EE_BIT+1,MSR_EE_BIT-1 /* Turn off 'rupts */ | |
3113 | mtmsr r9 /* Disable 'em */ | |
3114 | lwz r7,PMAP_PMAPVR(r3) ; Get the v to r translation | |
3115 | lwz r4,PMAP_SPACE(r3) ; Get the space | |
3116 | mfsprg r6,0 /* Get the per_proc_info address */ | |
3117 | xor r3,r3,r7 ; Get real address of bmap anchor | |
3118 | stw r4,PP_USERSPACE(r6) /* Show our new address space */ | |
3119 | stw r3,PP_USERPMAP(r6) ; Show our real pmap address | |
3120 | mtmsr r10 /* Restore interruptions */ | |
3121 | blr /* Return... */ | |
3122 | ||
d7e50217 | 3123 | .align 5 |
de355530 | 3124 | .globl EXT(hw_set_user_space_dis) |
d7e50217 | 3125 | |
de355530 | 3126 | LEXT(hw_set_user_space_dis) |
d7e50217 | 3127 | |
de355530 A |
3128 | lwz r7,PMAP_PMAPVR(r3) ; Get the v to r translation |
3129 | lwz r4,PMAP_SPACE(r3) ; Get the space | |
3130 | mfsprg r6,0 ; Get the per_proc_info address | |
3131 | xor r3,r3,r7 ; Get real address of bmap anchor | |
3132 | stw r4,PP_USERSPACE(r6) ; Show our new address space | |
3133 | stw r3,PP_USERPMAP(r6) ; Show our real pmap address | |
d7e50217 | 3134 | blr ; Return... |
d7e50217 | 3135 | |
d7e50217 | 3136 | |
de355530 A |
3137 | /* struct mapping *hw_cpv(struct mapping *mp) - Converts a physcial mapping CB address to virtual |
3138 | * | |
3139 | */ | |
1c79356b A |
3140 | |
3141 | .align 5 | |
de355530 | 3142 | .globl EXT(hw_cpv) |
1c79356b | 3143 | |
de355530 | 3144 | LEXT(hw_cpv) |
1c79356b | 3145 | |
de355530 A |
3146 | rlwinm. r4,r3,0,0,19 ; Round back to the mapping block allocation control block |
3147 | mfmsr r10 ; Get the current MSR | |
3148 | beq- hcpvret ; Skip if we are passed a 0... | |
3149 | rlwinm r10,r10,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
3150 | rlwinm r10,r10,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
3151 | andi. r9,r10,0x7FEF ; Turn off interrupts and data translation | |
3152 | mtmsr r9 ; Disable DR and EE | |
3153 | isync | |
d7e50217 | 3154 | |
de355530 A |
3155 | lwz r4,mbvrswap(r4) ; Get the conversion value |
3156 | mtmsr r10 ; Interrupts and DR back on | |
3157 | isync | |
3158 | xor r3,r3,r4 ; Convert to physical | |
d7e50217 | 3159 | |
de355530 | 3160 | hcpvret: rlwinm r3,r3,0,0,26 ; Clean out any flags |
1c79356b A |
3161 | blr |
3162 | ||
d7e50217 | 3163 | |
de355530 A |
3164 | /* struct mapping *hw_cvp(struct mapping *mp) - Converts a virtual mapping CB address to physcial |
3165 | * | |
3166 | * Translation must be on for this | |
3167 | * | |
3168 | */ | |
d7e50217 | 3169 | |
de355530 A |
3170 | .align 5 |
3171 | .globl EXT(hw_cvp) | |
d7e50217 | 3172 | |
de355530 | 3173 | LEXT(hw_cvp) |
d7e50217 | 3174 | |
de355530 A |
3175 | rlwinm r4,r3,0,0,19 ; Round back to the mapping block allocation control block |
3176 | rlwinm r3,r3,0,0,26 ; Clean out any flags | |
3177 | lwz r4,mbvrswap(r4) ; Get the conversion value | |
3178 | xor r3,r3,r4 ; Convert to virtual | |
3179 | blr | |
d7e50217 | 3180 | |
d7e50217 | 3181 | |
de355530 A |
3182 | /* int mapalc(struct mappingblok *mb) - Finds, allocates, and checks a free mapping entry in a block |
3183 | * | |
3184 | * Lock must already be held on mapping block list | |
3185 | * returns 0 if all slots filled. | |
3186 | * returns n if a slot is found and it is not the last | |
3187 | * returns -n if a slot os found and it is the last | |
3188 | * when n and -n are returned, the corresponding bit is cleared | |
3189 | * | |
3190 | */ | |
1c79356b A |
3191 | |
3192 | .align 5 | |
de355530 | 3193 | .globl EXT(mapalc) |
1c79356b | 3194 | |
de355530 | 3195 | LEXT(mapalc) |
1c79356b | 3196 | |
de355530 A |
3197 | lwz r4,mbfree(r3) ; Get the first mask |
3198 | lis r0,0x8000 ; Get the mask to clear the first free bit | |
3199 | lwz r5,mbfree+4(r3) ; Get the second mask | |
3200 | mr r12,r3 ; Save the return | |
3201 | cntlzw r8,r4 ; Get first free field | |
3202 | lwz r6,mbfree+8(r3) ; Get the third mask | |
3203 | srw. r9,r0,r8 ; Get bit corresponding to first free one | |
3204 | lwz r7,mbfree+12(r3) ; Get the fourth mask | |
3205 | cntlzw r10,r5 ; Get first free field in second word | |
3206 | andc r4,r4,r9 ; Turn it off | |
3207 | bne malcfnd0 ; Found one... | |
1c79356b | 3208 | |
de355530 A |
3209 | srw. r9,r0,r10 ; Get bit corresponding to first free one in second word |
3210 | cntlzw r11,r6 ; Get first free field in third word | |
3211 | andc r5,r5,r9 ; Turn it off | |
3212 | bne malcfnd1 ; Found one... | |
1c79356b | 3213 | |
de355530 A |
3214 | srw. r9,r0,r11 ; Get bit corresponding to first free one in third word |
3215 | cntlzw r10,r7 ; Get first free field in fourth word | |
3216 | andc r6,r6,r9 ; Turn it off | |
3217 | bne malcfnd2 ; Found one... | |
1c79356b | 3218 | |
de355530 A |
3219 | srw. r9,r0,r10 ; Get bit corresponding to first free one in second word |
3220 | li r3,0 ; Assume abject failure | |
3221 | andc r7,r7,r9 ; Turn it off | |
3222 | beqlr ; There are none any left... | |
1c79356b | 3223 | |
de355530 A |
3224 | addi r3,r10,96 ; Set the correct bit number |
3225 | stw r7,mbfree+12(r12) ; Actually allocate the slot | |
1c79356b | 3226 | |
de355530 A |
3227 | mapafin: or r4,r4,r5 ; Merge the first two allocation maps |
3228 | or r6,r6,r7 ; Then the last two | |
3229 | or. r4,r4,r6 ; Merge both halves | |
3230 | bnelr+ ; Return if some left for next time... | |
1c79356b | 3231 | |
de355530 | 3232 | neg r3,r3 ; Indicate we just allocated the last one |
1c79356b A |
3233 | blr ; Leave... |
3234 | ||
de355530 A |
3235 | malcfnd0: stw r4,mbfree(r12) ; Actually allocate the slot |
3236 | mr r3,r8 ; Set the correct bit number | |
3237 | b mapafin ; Exit now... | |
1c79356b | 3238 | |
de355530 A |
3239 | malcfnd1: stw r5,mbfree+4(r12) ; Actually allocate the slot |
3240 | addi r3,r10,32 ; Set the correct bit number | |
3241 | b mapafin ; Exit now... | |
1c79356b | 3242 | |
de355530 A |
3243 | malcfnd2: stw r6,mbfree+8(r12) ; Actually allocate the slot |
3244 | addi r3,r11,64 ; Set the correct bit number | |
3245 | b mapafin ; Exit now... | |
1c79356b A |
3246 | |
3247 | ||
de355530 A |
3248 | /* |
3249 | * Log out all memory usage | |
3250 | */ | |
1c79356b A |
3251 | |
3252 | .align 5 | |
de355530 | 3253 | .globl EXT(logmem) |
d7e50217 | 3254 | |
de355530 | 3255 | LEXT(logmem) |
d7e50217 | 3256 | |
de355530 A |
3257 | mfmsr r2 ; Get the MSR |
3258 | lis r10,hi16(EXT(DebugWork)) ; High part of area | |
3259 | rlwinm r2,r2,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off | |
3260 | lis r12,hi16(EXT(mem_actual)) ; High part of actual | |
3261 | rlwinm r2,r2,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off | |
3262 | andi. r0,r2,0x7FCF ; Interrupts and translation off | |
3263 | ori r10,r10,lo16(EXT(DebugWork)) ; Get the entry | |
3264 | mtmsr r0 ; Turn stuff off | |
3265 | ori r12,r12,lo16(EXT(mem_actual)) ; Get the actual | |
3266 | li r0,1 ; Get a one | |
3267 | ||
1c79356b A |
3268 | isync |
3269 | ||
de355530 A |
3270 | stw r0,4(r10) ; Force logging off |
3271 | lwz r0,0(r12) ; Get the end of memory | |
3272 | ||
3273 | lis r12,hi16(EXT(mem_size)) ; High part of defined memory | |
3274 | ori r12,r12,lo16(EXT(mem_size)) ; Low part of defined memory | |
3275 | lwz r12,0(r12) ; Make it end of defined | |
3276 | ||
3277 | cmplw r0,r12 ; Is there room for the data? | |
3278 | ble- logmemexit ; No, do not even try... | |
3279 | ||
3280 | stw r12,0(r12) ; Set defined memory size | |
3281 | stw r0,4(r12) ; Set the actual amount of memory | |
3282 | ||
3283 | lis r3,hi16(EXT(hash_table_base)) ; Hash table address | |
3284 | lis r4,hi16(EXT(hash_table_size)) ; Hash table size | |
3285 | lis r5,hi16(EXT(pmap_mem_regions)) ; Memory regions | |
3286 | lis r6,hi16(EXT(mapCtl)) ; Mappings | |
3287 | ori r3,r3,lo16(EXT(hash_table_base)) | |
3288 | ori r4,r4,lo16(EXT(hash_table_size)) | |
3289 | ori r5,r5,lo16(EXT(pmap_mem_regions)) | |
3290 | ori r6,r6,lo16(EXT(mapCtl)) | |
3291 | lwz r3,0(r3) | |
3292 | lwz r4,0(r4) | |
3293 | lwz r5,4(r5) ; Get the pointer to the phys_ent table | |
3294 | lwz r6,0(r6) ; Get the pointer to the current mapping block | |
3295 | stw r3,8(r12) ; Save the hash table address | |
3296 | stw r4,12(r12) ; Save the hash table size | |
3297 | stw r5,16(r12) ; Save the physent pointer | |
3298 | stw r6,20(r12) ; Save the mappings | |
3299 | ||
3300 | addi r11,r12,0x1000 ; Point to area to move hash table and PCA | |
3301 | ||
3302 | add r4,r4,r4 ; Double size for both | |
3303 | ||
3304 | copyhash: lwz r7,0(r3) ; Copy both of them | |
3305 | lwz r8,4(r3) | |
3306 | lwz r9,8(r3) | |
3307 | lwz r10,12(r3) | |
3308 | subic. r4,r4,0x10 | |
3309 | addi r3,r3,0x10 | |
3310 | stw r7,0(r11) | |
3311 | stw r8,4(r11) | |
3312 | stw r9,8(r11) | |
3313 | stw r10,12(r11) | |
3314 | addi r11,r11,0x10 | |
3315 | bgt+ copyhash | |
3316 | ||
3317 | rlwinm r4,r12,20,12,31 ; Get number of phys_ents | |
3318 | ||
3319 | copyphys: lwz r7,0(r5) ; Copy physents | |
3320 | lwz r8,4(r5) | |
3321 | subic. r4,r4,1 | |
3322 | addi r5,r5,8 | |
3323 | stw r7,0(r11) | |
3324 | stw r8,4(r11) | |
3325 | addi r11,r11,8 | |
3326 | bgt+ copyphys | |
3327 | ||
3328 | addi r11,r11,4095 ; Round up to next page | |
3329 | rlwinm r11,r11,0,0,19 | |
3330 | ||
3331 | lwz r4,4(r6) ; Get the size of the mapping area | |
3332 | ||
3333 | copymaps: lwz r7,0(r6) ; Copy the mappings | |
3334 | lwz r8,4(r6) | |
3335 | lwz r9,8(r6) | |
3336 | lwz r10,12(r6) | |
3337 | subic. r4,r4,0x10 | |
3338 | addi r6,r6,0x10 | |
3339 | stw r7,0(r11) | |
3340 | stw r8,4(r11) | |
3341 | stw r9,8(r11) | |
3342 | stw r10,12(r11) | |
3343 | addi r11,r11,0x10 | |
3344 | bgt+ copymaps | |
3345 | ||
3346 | sub r11,r11,r12 ; Get the total length we saved | |
3347 | stw r11,24(r12) ; Save the size | |
3348 | ||
3349 | logmemexit: mtmsr r2 ; Back to normal | |
3350 | li r3,0 | |
1c79356b A |
3351 | isync |
3352 | blr | |
3353 | ||
3354 |