]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/hw_vm.s
xnu-344.49.tar.gz
[apple/xnu.git] / osfmk / ppc / hw_vm.s
CommitLineData
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
109LEXT(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
150hamNoMSR: 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
157hamNoMSRx:
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
173ptegLckx: 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
182ptegLckwx: 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
189ptegSXgx: 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
256LEXT(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
296hlpNoMSR: mr r3,r0 ; Get the new MSR
297 li r0,loadMSR ; Get the MSR setter SC
298 sc ; Set it
299hlpNoMSRx:
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
315ptegLcka: 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
325ptegLckwa: 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 332ptegSXga: 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 338findmapa:
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
348vbail: 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
362chkmapa: 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
404findmapb: 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
414penterr: li r3,1 /* Set timeout */
415 b vbail /* Return in abject failure... */
416
417 .align 5
d7e50217 418
de355530
A
419chkmapb: 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
454LEXT(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
477lmvNoMSR:
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 486lmvNoMSRx:
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
497ptegLck1: 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
506ptegLckw1: 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
513ptegSXg1: 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
518srchmaps: 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
527mapok: 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
553tlbhang1: 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
580its603a: 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
586nopte: 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
595mrgrc: 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
600nadamrg: 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
609srchpmap: 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
618mapok1: 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
639nophys: 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
677LEXT(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
703hpNoMSR:
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
711hpNoMSRx:
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
725protcng: 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
732protnext: 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
741protLck1: 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
750protLckw1: 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 757protSXg1: 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
782tlbhangp: 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
801its603p: 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
817protmod: 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
822protul: 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
833protdone: 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
866LEXT(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
891hpvNoMSR:
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
899hpvNoMSRx:
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
916protvLck1: 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
925protvLckw1: 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
932protvSXg1: 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
957tlbhangpv: 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
976its603pv: 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
995protvmod: 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
1000pvnophys: 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
1040LEXT(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
1065havNoMSR:
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
1073havNoMSRx:
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
1088attrvLck1: 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
1097attrvLckw1: 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 1104attrvSXg1: 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
1128tlbhangav: 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
1147its603av: 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
1166attrvmod: 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
1171avnophys: 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
1180attrflsh: 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
1187attrimvl: 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
1230LEXT(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 1240LEXT(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
1253LEXT(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
1268LEXT(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 1278LEXT(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
1288LEXT(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
1297LEXT(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 1310hw_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
1334comnmap:
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
1342hpcNoMSR:
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
1350hpcNoMSRx:
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
1359commnext: 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 1367commnxtch: li r12,1 /* Get the locked value */
1c79356b 1368
de355530
A
1369commLck1: 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
1378commLckw1: 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 1385commSXg1: 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
1406tlbhangco: 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
1427its603co: 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
1442commmod: 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 1448commul: lwz r6,mmPTEr(r10) ; Get the real part
9bccf70c 1449
de355530
A
1450commulnl: 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
1477commdone: 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
1492commcng: 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
1512commtst: 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
1529commtcb: rlwinm r3,r8,25,31,31 ; Copy change bit to bit 31
1530
1531commfini: 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 1567LEXT(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
1585htrNoMSR:
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
1593htrNoMSRx:
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
1605htrLck1: 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
1614htrLckw1: 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 1621htrSXg1: 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
1645htrtlbhang: 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
1664htr603: 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
1683htrmrc: 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
1688htrnopte: 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
1692htrnorst: 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
1706htrcset: 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 1724LEXT(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
1757hpaNoMSR:
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
1765hpaNoMSRx:
1766
1767atmattr: 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 1805LEXT(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
1839gotIfetch: mr r7,r8 ; IFETCH info is in SRR1
1840 lwz r6,savesrr0(r13) /* Get the instruction address */
1c79356b 1841
de355530
A
1842ckIfProt: 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
1876notsuper: addi r5,r5,PMAP_SEGS ; Get offset to table
1877 lwzx r3,r3,r5 ; Get the VSID
1878
1879havevsid: 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
1911ptegLck: 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
1920ptegLckw: 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 1931ptegSXg: 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
1938findmap: 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
1963gotphys: lwz r2,mmPTEr(r12) ; Get the second part of the PTE
1964 b insert /* Go insert into the PTEG... */
1965
1966MustBeOK: 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
2011tryAuto: 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
2028bmInKernel:
2029#ifndef CHIP_ERRATA_MAX_V1
2030 lwarx r9,0,r10
2031#endif /* CHIP_ERRATA_MAX_V1 */
2032
2033bmapLck: 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
2043bmapLckw: 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
2054bmapSXg: 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
2058bmapNone: 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
2066realFault: 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
2081findAuto: 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
2093faGot:
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
2131insert: 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 */
2226wasauto: 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
2247tlbhang: 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
2276its603: 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
2286findold: 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
2305nomove: 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
2316mrgmrcx: 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
2326slamit: 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
2345bebad: 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 2357ENTRY(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
2374lraNoMSR:
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
2380lraNoMSRx:
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
2398ckbat1: 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
2409ckbat2: 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
2420ckbat3: 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
2431fndbat: 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
2437notkernsp: 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
2452fndpte: 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
2466gotxlate: 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 2488LEXT(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
2507habNoMSR:
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
2515habNoMSRx:
2516
2517abLck: 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
2527abLckw: 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
2537abSXg: 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
2548abChk: 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
2567abRet:
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
2574abChkD: 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 2612LEXT(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
2631hrbNoMSR:
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
2639hrbNoMSRx:
2640 li r7,0
2641 cmp cr5,r0,r7 ; Request to invalidate the ptes
2642 b rbLck
d7e50217 2643
de355530
A
2644rbunlink:
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
2649rbLck: 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
2659rbLckw: 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
2669rbSXg: 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
2675rbChk: 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
2694rbnFirst:
2695 stw r2,bmnext(r12) ; Unchain us
2696 sync
2697 b rbDone
2698
2699rbblkRem:
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
2715rbblkRemcont:
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
2721rbblkRemcont1:
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
2733rbfullblk:
2734 stw r6,bmcurrent(r10) ; Update the current page
9bccf70c 2735
de355530
A
2736rbcont:
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
2755rbHash: 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
2760rbLcka: 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
2768rbLckwa: 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
2773rbSXga: 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
2787rbSlot1: bf 1,rbSlot2 ; No autogen here
2788 stw r7,0x08(r11) ; Invalidate PTE
2789rbSlot2: bf 2,rbSlot3 ; No autogen here
2790 stw r7,0x10(r11) ; Invalidate PTE
2791rbSlot3: bf 3,rbSlot4 ; No autogen here
2792 stw r7,0x18(r11) ; Invalidate PTE
2793rbSlot4: bf 4,rbSlot5 ; No autogen here
2794 stw r7,0x20(r11) ; Invalidate PTE
2795rbSlot5: bf 5,rbSlot6 ; No autogen here
2796 stw r7,0x28(r11) ; Invalidate PTE
2797rbSlot6: bf 6,rbSlot7 ; No autogen here
2798 stw r7,0x30(r11) ; Invalidate PTE
2799rbSlot7: bf 7,rbSlotx ; No autogen here
2800 stw r7,0x38(r11) ; Invalidate PTE
2801rbSlotx:
2802
2803rbAintNone: 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
2825rbTlbL: 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
2832rbTlbN: 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
2849rbits603a: 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
2861rbpendret:
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
2870rbMT: 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
2876rbPerm: 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
2882rbDone: 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
2902LEXT(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
2914hvmNoMSR:
2915 mr r3,r0 ; Get the new MSR
2916 li r0,loadMSR ; Get the MSR setter SC
2917 sc
2918hvmNoMSRx:
2919 mr r0,r12
2920 li r11,1 ; Get the locked value
2921
2922hvmptegLckx:
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
2933hvmptegLckwx:
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
2941hvmptegSXgx:
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
2951hvmnexthash:
2952 li r10,0 ; Mapping test
2953
2954hvmfindmap:
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
2974hvmfindmapnext:
2975 lwz r6,mmhashnext(r6) ; Pick up next mapping block
2976 b hvmfindmap ; Scan the next mapping
2977hvmfindmapret:
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
2984hvmnexthashprep:
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
3008LEXT(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
3027hcbNoMSR:
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
3035hcbNoMSRx:
3036
3037cbLck: 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
3047cbLckw: 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
3060cbSXg: 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
3064cbChk: 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
3078cbDone: 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
3086cbNo: 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 3107LEXT(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 3126LEXT(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 3144LEXT(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 3160hcpvret: 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 3173LEXT(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 3195LEXT(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
3227mapafin: 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
3235malcfnd0: 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
3239malcfnd1: 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
3243malcfnd2: 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 3255LEXT(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
3304copyhash: 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
3319copyphys: 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
3333copymaps: 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
3349logmemexit: mtmsr r2 ; Back to normal
3350 li r3,0
1c79356b
A
3351 isync
3352 blr
3353
3354