]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | /* skiplists.s | |
30 | * | |
31 | * These are the subroutines that manage the skip-list data structures used for the | |
32 | * resident mappings for each pmap. We used to use a much simpler hash-based scheme, | |
33 | * but it didn't scale well for 64-bit address spaces and multi-GB real memories. | |
34 | * Here's a brief tutorial on skip-lists: | |
35 | * | |
36 | * The basic idea is that each mapping is on one or more singly-linked lists, sorted | |
37 | * in increasing order by virtual address. The number of lists a mapping is on is an | |
38 | * invariant property determined when the mapping is created, using an exponentially- | |
39 | * distributed random number. Every mapping is on the first list. Ideally, each | |
40 | * successive list has only 1/F as many nodes on it as the previous, where F is the | |
41 | * "fanout." With a max of n lists, up to F**n nodes can be handled optimally. | |
42 | * | |
43 | * Searching, adding, and deleting from a skip-list can all be done in O(ln(n)) time. | |
44 | * Because the first skip-list is just a sorted list of all mappings, it is also | |
45 | * efficient to purge a sparsely populated pmap of all the mappings in a large range, | |
46 | * for example when tearing down an address space. Large-range deletes are the | |
47 | * primary advantage of skip-lists over a hash, btw. | |
48 | * | |
49 | * We currently use a fanout of 4 and a maximum of 12 lists (cf kSkipListFanoutShift | |
50 | * and kSkipListMaxLists.) Thus, we can optimally handle pmaps with as many as 4**12 | |
51 | * pages, which is 64GB of resident physical memory per pmap. Pmaps can be larger than | |
52 | * this, albeit with diminishing efficiency. | |
53 | * | |
54 | * The major problem with skip-lists is that we could waste a lot of space with 12 | |
55 | * 64-bit link fields in every mapping. So we currently have two sizes of mappings: | |
56 | * 64-byte nodes with 4 list links, and 128-byte nodes with 12. Only one in every | |
57 | * (4**4)==256 mappings requires the larger node, so the average size is 64.25 bytes. | |
58 | * In practice, the additional complexity of the variable node size is entirely | |
59 | * contained in the allocate and free routines. | |
60 | * | |
61 | * The other, mostly theoretic problem with skip-lists is that they have worst cases | |
62 | * where performance becomes nearly linear. These worst-cases are quite rare but there | |
63 | * is no practical way to prevent them. | |
64 | */ | |
65 | ||
66 | ||
67 | ; set nonzero to accumulate skip-list stats on a per-map basis: | |
68 | #define SKIPLISTSTATS 1 | |
69 | ||
70 | ; cr7 bit set when mapSearchFull() finds a match on a high list: | |
71 | #define bFullFound 28 | |
72 | ||
73 | #include <assym.s> | |
74 | #include <debug.h> | |
75 | #include <ppc/asm.h> | |
76 | #include <ppc/proc_reg.h> | |
77 | #include <ppc/exception.h> | |
78 | ||
79 | ||
80 | /* | |
81 | * ********************* | |
82 | * * m a p S e a r c h * | |
83 | * ********************* | |
84 | * | |
85 | * Given a pmap and a virtual address (VA), find the mapping for that address. | |
86 | * This is the fast call, that does not set up the previous-ptr vector or make | |
87 | * consistency checks. When called: | |
88 | * the pmap is locked (shared or exclusive) | |
89 | * translation is off, interrupts masked | |
90 | * 64-bit mode is enabled (if on a 64-bit machine) | |
91 | * cr6 is loaded with the corresponding feature flags (in particular, pf64Bit) | |
92 | * r3 = pmap ptr | |
93 | * r4 = high 32 bits of key to search for (0 if a 32-bit processor) | |
94 | * r5 = low 32 bits of key (low 12 bits may be nonzero garbage) | |
95 | * r7 = mpFlags field if found. Undefined if not | |
96 | * | |
97 | * We return the mapping ptr (or 0) in r3, and the next VA (or 0 if no more) in r4 and r5. | |
98 | * Except for cr6 (which is global), we trash nonvolatile regs. Called both on 32- and 64-bit | |
99 | * machines, though we quickly branch into parallel code paths. | |
100 | */ | |
101 | .text | |
102 | .align 5 | |
103 | .globl EXT(mapSearch) | |
104 | LEXT(mapSearch) | |
105 | lbz r7,pmapCurLists(r3) ; get largest #lists any mapping is on | |
106 | la r8,pmapSkipLists+4(r3) ; point to lists in pmap, assuming 32-bit machine | |
107 | rlwinm r5,r5,0,0,19 ; zero low 12 bits of key | |
108 | mr r6,r3 ; save pmap ptr here so we can accumulate statistics | |
109 | li r9,0 ; initialize prev ptr | |
110 | addic. r7,r7,-1 ; get base-0 number of last list, and test for 0 | |
111 | li r2,0 ; initialize count of mappings visited | |
112 | slwi r7,r7,3 ; get offset of last list in use | |
113 | blt-- mapSrchPmapEmpty ; pmapCurLists==0 (ie, no mappings) | |
114 | lwzx r3,r8,r7 ; get 32-bit ptr to 1st mapping in highest list | |
115 | bf-- pf64Bitb,mapSrch32c ; skip if 32-bit processor | |
116 | subi r8,r8,4 ; we use all 64 bits of ptrs | |
117 | rldimi r5,r4,32,0 ; r5 <- 64-bit va | |
118 | ldx r3,r8,r7 ; get 64-bit ptr to 1st mapping in highest list | |
119 | b mapSrch64c ; enter 64-bit search loop | |
120 | ||
121 | ||
122 | ; 64-bit processors. Check next mapping. | |
123 | ; r2 = count of mappings visited so far | |
124 | ; r3 = current mapping ptr | |
125 | ; r4 = va of current mapping (ie, of r3) | |
126 | ; r5 = va to search for (the "key") (low 12 bits are 0) | |
127 | ; r6 = pmap ptr | |
128 | ; r7 = current skip list number * 8 | |
129 | ; r8 = ptr to skip list vector of mapping pointed to by r9 (or pmap, if r9==0) | |
130 | ; r9 = prev ptr, or 0 if none | |
131 | ||
132 | .align 5 | |
133 | mapSrch64a: ; loop over each mapping | |
134 | ld r4,mpVAddr(r3) ; get va for this mapping (plus flags in low 12 bits) | |
135 | addi r2,r2,1 ; count mappings visited | |
136 | rldicr r4,r4,0,51 ; zero low 12 bits of mapping va | |
137 | cmpld cr1,r5,r4 ; compare the vas | |
138 | blt cr1,mapSrch64d ; key is less, try next list | |
139 | la r8,mpList0(r3) ; point to skip list vector in this mapping | |
140 | mr r9,r3 ; remember prev ptr | |
141 | beq-- cr1,mapSrch64Found ; this is the correct mapping | |
142 | ldx r3,r7,r8 ; get ptr to next mapping in current list | |
143 | mapSrch64c: | |
144 | mr. r3,r3 ; was there another mapping on current list? | |
145 | bne++ mapSrch64a ; was another, so loop | |
146 | mapSrch64d: | |
147 | subic. r7,r7,8 ; move on to next list offset | |
148 | ldx r3,r7,r8 ; get next mapping on next list (if any) | |
149 | bge++ mapSrch64c ; loop to try next list | |
150 | ||
151 | ; Mapping not found, check to see if prev node was a block mapping or nested pmap. | |
152 | ; If not, or if our address is not covered by the block or nested map, return 0. | |
153 | ; Note the advantage of keeping the check for block mappings (and nested pmaps) | |
154 | ; out of the inner loop; we do the special case work at most once per search, and | |
155 | ; never for the most-common case of finding a scalar mapping. The full searches | |
156 | ; must check _in_ the inner loop, to get the prev ptrs right. | |
157 | ||
158 | mr. r9,r9 ; was there a prev ptr? | |
159 | li r3,0 ; assume we are going to return null | |
160 | ld r4,pmapSkipLists(r6) ; assume prev ptr null... so next is first | |
161 | beq-- mapSrch64Exit ; prev ptr was null, search failed | |
162 | lwz r0,mpFlags(r9) ; get flag bits from prev mapping | |
163 | lhz r11,mpBSize(r9) ; get #pages/#segments in block/submap mapping | |
164 | ||
165 | rlwinm r0,r0,mpBSub+1,31,31 ; 0 if 4K bsu or 1 if 32MB bsu | |
166 | ld r10,mpVAddr(r9) ; re-fetch base address of prev ptr | |
167 | ori r0,r0,0x3216 ; OR in 0x00003216 (0x3200 and a base rotate of 22) | |
168 | addi r11,r11,1 ; Convert 0-based to 1-based | |
169 | rlwnm r0,r0,r0,27,31 ; Rotate to get 12 or 25 | |
170 | ld r4,mpList0(r9) ; get 64-bit ptr to next mapping, if any | |
171 | sld r11,r11,r0 ; Get the length in bytes | |
172 | rldicr r10,r10,0,51 ; zero low 12 bits of mapping va | |
173 | subi r0,r11,4096 ; get offset last page in mapping | |
174 | add r10,r10,r0 ; r10 <- last page in this mapping | |
175 | cmpld r5,r10 ; does this mapping cover our page? | |
176 | bgt mapSrch64Exit ; no, search failed | |
177 | mr r3,r9 ; yes, we found it | |
178 | ||
179 | ; found the mapping | |
180 | ; r2 = count of nodes visited | |
181 | ; r3 = the mapping | |
182 | ; r6 = pmap ptr | |
183 | ||
184 | mapSrch64Found: ; WARNING: can drop down to here | |
185 | ld r4,mpList0(r3) ; get ptr to next mapping | |
186 | lwz r7,mpFlags(r3) ; Get the flags for our caller | |
187 | ||
188 | ; r2 = count of nodes visited | |
189 | ; r3 = return value (ie, found mapping or 0) | |
190 | ; r4 = next mapping (or 0 if none) | |
191 | ; r6 = pmap ptr | |
192 | ; r7 = mpFlags | |
193 | ||
194 | mapSrch64Exit: ; WARNING: can drop down to here | |
195 | mr. r5,r4 ; next ptr null? | |
196 | #if SKIPLISTSTATS | |
197 | lwz r10,pmapSearchCnt(r6) ; prepare to accumulate statistics | |
198 | ld r8,pmapSearchVisits(r6) | |
199 | addi r10,r10,1 ; count searches | |
200 | add r8,r8,r2 ; count nodes visited | |
201 | stw r10,pmapSearchCnt(r6) | |
202 | std r8,pmapSearchVisits(r6) | |
203 | #endif | |
204 | beqlr- ; next ptr was null, so return 0 in r4 and r5 | |
205 | lwz r5,mpVAddr+4(r4) ; get VA of next node | |
206 | lwz r4,mpVAddr+0(r4) | |
207 | blr | |
208 | ||
209 | ||
210 | ; 32-bit processors. Check next mapping. | |
211 | ; r2 = count of mappings visited so far | |
212 | ; r3 = current mapping ptr | |
213 | ; r4 = va of current mapping (ie, of r3) | |
214 | ; r5 = va to search for (the "key") (low 12 bits are 0) | |
215 | ; r6 = pmap ptr | |
216 | ; r7 = current skip list number * 8 | |
217 | ; r8 = ptr to skip list vector of mapping pointed to by r9 (or pmap, if r9==0) | |
218 | ; r9 = prev ptr, or 0 if none | |
219 | ||
220 | .align 4 | |
221 | mapSrch32a: ; loop over each mapping | |
222 | lwz r4,mpVAddr+4(r3) ; get va for this mapping (plus flags in low 12 bits) | |
223 | addi r2,r2,1 ; count mappings visited | |
224 | rlwinm r4,r4,0,0,19 ; zero low 12 bits of mapping va | |
225 | cmplw cr1,r5,r4 ; compare the vas | |
226 | blt cr1,mapSrch32d ; key is less, try next list | |
227 | la r8,mpList0+4(r3) ; point to skip list vector in this mapping | |
228 | mr r9,r3 ; remember prev ptr | |
229 | beq- cr1,mapSrch32Found ; this is the correct mapping | |
230 | lwzx r3,r7,r8 ; get ptr to next mapping in current list | |
231 | mapSrch32c: | |
232 | mr. r3,r3 ; was there another mapping on current list? | |
233 | bne+ mapSrch32a ; was another, so loop | |
234 | mapSrch32d: | |
235 | subic. r7,r7,8 ; move on to next list offset | |
236 | lwzx r3,r7,r8 ; get next mapping on next list (if any) | |
237 | bge+ mapSrch32c ; loop to try next list | |
238 | ||
239 | ; Mapping not found, check to see if prev node was a block mapping or nested pmap. | |
240 | ; If not, or if our address is not covered by the block or nested map, return 0. | |
241 | ; Note the advantage of keeping the check for block mappings (and nested pmaps) | |
242 | ; out of the inner loop; we do the special case work at most once per search, and | |
243 | ; never for the most-common case of finding a scalar mapping. The full searches | |
244 | ; must check _in_ the inner loop, to get the prev ptrs right. | |
245 | ||
246 | mr. r9,r9 ; was there a prev ptr? | |
247 | li r3,0 ; assume we are going to return null | |
248 | lwz r4,pmapSkipLists+4(r6) ; assume prev ptr null... so next is first | |
249 | beq- mapSrch32Exit ; prev ptr was null, search failed | |
250 | lwz r0,mpFlags(r9) ; get flag bits from prev mapping | |
251 | lhz r11,mpBSize(r9) ; get #pages/#segments in block/submap mapping | |
252 | lwz r10,mpVAddr+4(r9) ; re-fetch base address of prev ptr | |
253 | ||
254 | rlwinm r0,r0,mpBSub+1,31,31 ; Rotate to get 0 if 4K bsu or 1 if 32MB bsu | |
255 | addi r11,r11,1 ; Convert 0-based to 1-based | |
256 | ori r0,r0,0x3216 ; OR in 0x00003216 (0x3200 and a base rotate of 22) | |
257 | rlwnm r0,r0,r0,27,31 ; Rotate to get 12 or 25 | |
258 | lwz r4,mpList0+4(r9) ; get ptr to next mapping, if any | |
259 | slw r11,r11,r0 ; Get length in bytes | |
260 | rlwinm r10,r10,0,0,19 ; zero low 12 bits of block mapping va | |
261 | subi r0,r11,4096 ; get address of last page in submap | |
262 | add r10,r10,r0 ; r10 <- last page in this mapping | |
263 | cmplw r5,r10 ; does this mapping cover our page? | |
264 | bgt mapSrch32Exit ; no, search failed | |
265 | mr r3,r9 ; yes, we found it | |
266 | ||
267 | ; found the mapping | |
268 | ; r2 = count of nodes visited | |
269 | ; r3 = the mapping | |
270 | ; r6 = pmap ptr | |
271 | ||
272 | mapSrch32Found: ; WARNING: can drop down to here | |
273 | lwz r4,mpList0+4(r3) ; get ptr to next mapping | |
274 | lwz r7,mpFlags(r3) ; Get mpFlags for our caller | |
275 | ; r2 = count of nodes visited | |
276 | ; r3 = return value (ie, found mapping or 0) | |
277 | ; r4 = next mapping (or 0 if none) | |
278 | ; r6 = pmap ptr | |
279 | ; r7 = mpFlags | |
280 | ||
281 | mapSrch32Exit: | |
282 | mr. r5,r4 ; next ptr null? | |
283 | #if SKIPLISTSTATS | |
284 | lwz r10,pmapSearchCnt(r6) ; prepare to accumulate statistics | |
285 | lwz r8,pmapSearchVisits(r6) | |
286 | lwz r9,pmapSearchVisits+4(r6) | |
287 | addi r10,r10,1 ; count searches | |
288 | addc r9,r9,r2 ; count nodes visited | |
289 | addze r8,r8 | |
290 | stw r10,pmapSearchCnt(r6) | |
291 | stw r8,pmapSearchVisits(r6) | |
292 | stw r9,pmapSearchVisits+4(r6) | |
293 | #endif | |
294 | beqlr- ; next ptr was null, so return 0 in r4 and r5 | |
295 | lwz r5,mpVAddr+4(r4) ; get VA of next node | |
296 | lwz r4,mpVAddr+0(r4) | |
297 | blr | |
298 | ||
299 | ; Here when the pmap is empty (ie, pmapCurLists==0), both in 32 and 64-bit mode, | |
300 | ; and from both mapSearch and mapSearchFull. | |
301 | ; r6 = pmap ptr | |
302 | ||
303 | mapSrchPmapEmpty: | |
304 | li r3,0 ; return null | |
305 | li r4,0 ; return 0 as virtual address of next node | |
306 | li r5,0 | |
307 | #if SKIPLISTSTATS | |
308 | lwz r7,pmapSearchCnt(r6) ; prepare to accumulate statistics | |
309 | addi r7,r7,1 ; count searches | |
310 | stw r7,pmapSearchCnt(r6) | |
311 | #endif | |
312 | blr | |
313 | ||
314 | ||
315 | /* | |
316 | * ***************************** | |
317 | * * m a p S e a r c h F u l l * | |
318 | * ***************************** | |
319 | * | |
320 | * Given a pmap and a virtual address (VA), find the mapping for that address. | |
321 | * This is the "full" call, that sets up a vector of ptrs to the previous node | |
322 | * (or to the pmap, if there is no previous node) for each list that the mapping | |
323 | * in on. We also make consistency checks on the skip-lists. When called: | |
324 | * the pmap is locked (shared or exclusive) | |
325 | * translation is off, interrupts masked | |
326 | * 64-bit mode is enabled (if on a 64-bit machine) | |
327 | * cr6 is loaded with the corresponding feature flags (in particular, pf64Bit) | |
328 | * r3 = pmap ptr | |
329 | * r4 = high 32 bits of key to search for (0 if a 32-bit processor) | |
330 | * r5 = low 32 bits of key (low 12 bits may be nonzero garbage) | |
331 | * | |
332 | * We return the mapping ptr (or 0) in r3, and the next VA (or 0 if no more) in r4 and r5. | |
333 | * Except for cr6 (which is global), we trash nonvolatile regs. Called both on 32- and 64-bit | |
334 | * machines, though we quickly branch into parallel code paths. | |
335 | */ | |
336 | .text | |
337 | .align 5 | |
338 | .globl EXT(mapSearchFull) | |
339 | LEXT(mapSearchFull) | |
340 | lbz r7,pmapCurLists(r3) ; get largest #lists any mapping is on | |
341 | la r8,pmapSkipLists+4(r3) ; point to lists in pmap, assuming 32-bit machine | |
342 | rlwinm r5,r5,0,0,19 ; zero low 12 bits of key | |
343 | mr r6,r3 ; save pmap ptr here so we can accumulate statistics | |
344 | li r2,0 ; initialize count of mappings visited | |
345 | mfsprg r12,0 ; get the per-proc data ptr | |
346 | crclr bFullFound ; we have not found the mapping yet | |
347 | addic. r7,r7,-1 ; get base-0 number of last list, and test for 0 | |
348 | subi r9,r8,mpList0+4 ; initialize prev ptr to be a fake mapping | |
349 | slwi r7,r7,3 ; get (offset*8) of last list | |
350 | la r12,skipListPrev+4(r12) ; point to vector of prev ptrs, assuming 32-bit machine | |
351 | blt-- mapSrchPmapEmpty ; pmapCurLists==0 (ie, no mappings) | |
352 | lwzx r3,r8,r7 ; get 32-bit ptr to 1st mapping in highest list | |
353 | li r10,0 ; initialize prev ptrs VA to 0 too | |
354 | bf-- pf64Bitb,mapSrchFull32c ; skip if 32-bit processor | |
355 | subi r8,r8,4 ; we use all 64 bits of ptrs | |
356 | subi r12,r12,4 | |
357 | rldimi r5,r4,32,0 ; r5 <- 64-bit va | |
358 | ldx r3,r8,r7 ; get 64-bit ptr to 1st mapping in highest list | |
359 | b mapSrchFull64c ; enter 64-bit search loop | |
360 | ||
361 | ||
362 | ; 64-bit processors. Check next mapping. | |
363 | ; r2 = count of mappings visited so far | |
364 | ; r3 = current mapping ptr | |
365 | ; r4 = va of current mapping (ie, of r3) | |
366 | ; r5 = va to search for (the "key") (low 12 bits are 0) | |
367 | ; r6 = pmap ptr | |
368 | ; r7 = current skip list number * 8 | |
369 | ; r8 = ptr to skip list vector of mapping pointed to by r9 | |
370 | ; r9 = prev ptr, ie highest mapping that comes before search target (initially the pmap) | |
371 | ; r10 = lowest expected next va, 0 at the beginning of the search | |
372 | ; r12 = ptr to the skipListPrev vector in the per-proc | |
373 | ||
374 | .align 5 | |
375 | mapSrchFull64a: ; loop over each mapping | |
376 | addi r2,r2,1 ; count mappings visited | |
377 | lwz r0,mpFlags(r3) ; get mapping flag bits | |
378 | lhz r11,mpBSize(r3) ; get #pages/#segments in block/submap mapping | |
379 | ld r4,mpVAddr(r3) ; get va for this mapping (plus flags in low 12 bits) | |
380 | ||
381 | rlwinm r0,r0,mpBSub+1,31,31 ; Rotate to get 0 if 4K bsu or 1 if 32MB bsu | |
382 | addi r11,r11,1 ; Convert 0-based to 1-based | |
383 | ori r0,r0,0x3216 ; OR in 0x00003216 (0x3200 and a base rotate of 22) | |
384 | rlwnm r0,r0,r0,27,31 ; Rotate to get 12 or 25 | |
385 | sld r11,r11,r0 ; Get the length in bytes | |
386 | rldicr r4,r4,0,51 ; zero low 12 bits of mapping va | |
387 | addic. r0,r11,-4096 ; get offset last page in mapping (set cr0_eq if 1 page) | |
388 | ||
389 | cmpld cr5,r10,r4 ; make sure VAs come in strictly ascending order | |
390 | cmpld cr1,r5,r4 ; compare the vas | |
391 | bgt-- cr5,mapSkipListPanic ; die if keys are out of order | |
392 | ||
393 | blt cr1,mapSrchFull64d ; key is less, try next list | |
394 | beq cr1,mapSrchFull64Found ; this is the correct mapping | |
395 | bne-- cr0,mapSrchFull64e ; handle mapping larger than one page | |
396 | mapSrchFull64b: | |
397 | la r8,mpList0(r3) ; point to skip list vector in this mapping | |
398 | mr r9,r3 ; current becomes previous | |
399 | ldx r3,r7,r8 ; get ptr to next mapping in current list | |
400 | addi r10,r4,0x1000 ; Get the lowest VA we can get next | |
401 | mapSrchFull64c: | |
402 | mr. r3,r3 ; was there another mapping on current list? | |
403 | bne++ mapSrchFull64a ; was another, so loop | |
404 | mapSrchFull64d: | |
405 | stdx r9,r7,r12 ; save prev ptr in per-proc vector | |
406 | subic. r7,r7,8 ; move on to next list offset | |
407 | ldx r3,r7,r8 ; get next mapping on next list (if any) | |
408 | bge++ mapSrchFull64c ; loop to try next list | |
409 | ||
410 | ; Mapping not found, return 0 and next higher key | |
411 | ||
412 | li r3,0 ; return null | |
413 | bt-- bFullFound,mapSkipListPanic ; panic if it was on earlier list | |
414 | ld r4,mpList0(r9) ; get 64-bit ptr to next mapping, if any | |
415 | b mapSrch64Exit | |
416 | ||
417 | ; Block mapping or nested pmap, and key > base. We must compute the va of | |
418 | ; the end of the block to see if key fits within it. | |
419 | ||
420 | mapSrchFull64e: | |
421 | add r4,r4,r0 ; r4 <- last page in this mapping | |
422 | cmpld r5,r4 ; does this mapping cover our page? | |
423 | bgt mapSrchFull64b ; no, try next mapping (r4 is advanced to end of range) | |
424 | ||
425 | ||
426 | ; found the mapping | |
427 | ; r2 = count of nodes visited | |
428 | ; r3 = the mapping | |
429 | ; r6 = pmap ptr | |
430 | ; r7 = current skip list number * 8 | |
431 | ; r8 = ptr to prev mappings (ie, r9) skip-list vector | |
432 | ; r9 = prev ptr, ie highest mapping that comes before search target | |
433 | ; r10 = prev mappings va | |
434 | ; r12 = ptr to the skipListPrev vector in the per-proc | |
435 | ||
436 | mapSrchFull64Found: ; WARNING: can drop down to here | |
437 | cmpwi r7,0 ; are we in the last skip-list? | |
438 | crset bFullFound ; remember that we found the mapping | |
439 | bne mapSrchFull64d ; mapSearchFull must search all lists to get prev ptrs | |
440 | ld r4,mpList0(r3) ; get ptr to next mapping | |
441 | stdx r9,r7,r12 ; save prev ptr in last list | |
442 | lwz r7,mpFlags(r3) ; Get the flags for our caller | |
443 | b mapSrch64Exit | |
444 | ||
445 | ||
446 | ; 32-bit processors. Check next mapping. | |
447 | ; r2 = count of nodes visited | |
448 | ; r3 = ptr to next mapping in current list | |
449 | ; r5 = va to search for (the "key") (low 12 bits are 0) | |
450 | ; r6 = pmap ptr | |
451 | ; r7 = current skip list number * 8 | |
452 | ; r8 = ptr to skip list vector of mapping pointed to by r9 | |
453 | ; r9 = prev ptr, ie highest mapping that comes before search target (initially the pmap) | |
454 | ; r10 = lowest expected next va, 0 at the beginning of the search | |
455 | ; r12 = ptr to the skipListPrev vector in the per-proc | |
456 | ||
457 | .align 4 | |
458 | mapSrchFull32a: ; loop over each mapping | |
459 | addi r2,r2,1 ; count mappings visited | |
460 | lwz r0,mpFlags(r3) ; get mapping flag bits | |
461 | lhz r11,mpBSize(r3) ; get #pages/#segments in block/submap mapping | |
462 | lwz r4,mpVAddr+4(r3) ; get va for this mapping (plus flags in low 12 bits) | |
463 | ||
464 | rlwinm r0,r0,mpBSub+1,31,31 ; Rotate to get 0 if 4K bsu or 1 if 32MB bsu | |
465 | addi r11,r11,1 ; Convert 0-based to 1-based | |
466 | ori r0,r0,0x3216 ; OR in 0x00003216 (0x3200 and a base rotate of 22) | |
467 | rlwnm r0,r0,r0,27,31 ; Rotate to get 12 or 25 | |
468 | slw r11,r11,r0 ; Get the length in bytes | |
469 | rlwinm r4,r4,0,0,19 ; zero low 12 bits of mapping va | |
470 | addic. r0,r11,-4096 ; get offset last page in mapping (set cr0_eq if 1 page) | |
471 | ||
472 | cmplw cr0,r10,r4 ; make sure VAs come in strictly ascending order | |
473 | cmplw cr1,r5,r4 ; compare the vas | |
474 | bgt- cr0,mapSkipListPanic ; die if keys are out of order | |
475 | ||
476 | blt cr1,mapSrchFull32d ; key is less than this va, try next list | |
477 | beq cr1,mapSrchFull32Found ; this is the correct mapping | |
478 | bne- cr0,mapSrchFull32e ; handle mapping larger than one page | |
479 | mapSrchFull32b: | |
480 | la r8,mpList0+4(r3) ; point to skip list vector in this mapping | |
481 | mr r9,r3 ; current becomes previous | |
482 | lwzx r3,r7,r8 ; get ptr to next mapping in current list | |
483 | addi r10,r4,0x1000 ; Get the lowest VA we can get next | |
484 | mapSrchFull32c: | |
485 | mr. r3,r3 ; next becomes current | |
486 | bne+ mapSrchFull32a ; was another, so loop | |
487 | mapSrchFull32d: | |
488 | stwx r9,r7,r12 ; save prev ptr in per-proc vector | |
489 | subic. r7,r7,8 ; move on to next list offset | |
490 | lwzx r3,r7,r8 ; get next mapping on lower list (if any) | |
491 | bge+ mapSrchFull32c ; loop to try next list | |
492 | ||
493 | ; mapping not found, return 0 and next-key | |
494 | ||
495 | li r3,0 ; return null | |
496 | bt- bFullFound,mapSkipListPanic ; panic if it was on an earlier list | |
497 | lwz r4,mpList0+4(r9) ; get ptr to next mapping | |
498 | b mapSrch32Exit | |
499 | ||
500 | ; Block mapping or nested pmap, and key > base. We must compute the va of | |
501 | ; the end of the block to see if our key fits within it. | |
502 | ||
503 | mapSrchFull32e: | |
504 | add r4,r4,r0 ; r4 <- last page in this mapping | |
505 | cmplw r5,r4 ; does this mapping cover our page? | |
506 | bgt mapSrchFull32b ; no, try next mapping | |
507 | ||
508 | ||
509 | ; found the mapping | |
510 | ; r2 = count of nodes visited | |
511 | ; r3 = the mapping | |
512 | ; r6 = pmap ptr | |
513 | ; r7 = current skip list number * 8 | |
514 | ; r9 = prev ptr, ie highest mapping that comes before search target, or 0 | |
515 | ; r10 = prev mappings va | |
516 | ; r12 = ptr to the skipListPrev vector in the per-proc | |
517 | ||
518 | mapSrchFull32Found: ; WARNING: can drop down to here | |
519 | cmpwi r7,0 ; are we in the last skip-list? | |
520 | crset bFullFound ; remember that we found the mapping | |
521 | bne mapSrchFull32d ; mapSearchFull must search all lists to get prev ptrs | |
522 | lwz r4,mpList0+4(r3) ; get ptr to next mapping | |
523 | stwx r9,r7,r12 ; save prev ptr in last list | |
524 | lwz r7,mpFlags(r3) ; Get mpFlags for our caller | |
525 | b mapSrch32Exit | |
526 | ||
527 | ||
528 | /* | |
529 | * ********************* | |
530 | * * m a p I n s e r t * | |
531 | * ********************* | |
532 | * | |
533 | * Insert a mapping into pmap skip-lists. The caller has already called mapSearchFull to | |
534 | * determine that this mapping does not overlap other mappings in the pmap. As a side effect | |
535 | * of calling mapSearchFull, the per-proc skipListPrev array is set up with a vector of the | |
536 | * previous ptrs for each skip list. When called: | |
537 | * the pmap is locked (exclusive) | |
538 | * translation is off, interrupts masked | |
539 | * 64-bit mode is enabled (if on a 64-bit machine) | |
540 | * mapSearchFull has just been called for this mappings key | |
541 | * cr6 is loaded with the corresponding feature flags (in particular, pf64Bit) | |
542 | * r3 = pmap ptr | |
543 | * r4 = mapping ptr | |
544 | * | |
545 | * There is no return value. Except for cr6 (which is global), we trash nonvolatile regs. | |
546 | */ | |
547 | ||
548 | .align 5 | |
549 | .globl EXT(mapInsert) | |
550 | LEXT(mapInsert) | |
551 | lwz r8,mpFlags(r4) ; get this mappings flags | |
552 | lbz r7,pmapCurLists(r3) ; get current max# lists any mapping is on | |
553 | la r10,pmapSkipLists+4(r3) ; r10 <-- base of pmap list headers, assuming 32-bit machine | |
554 | la r11,mpList0+4(r4) ; r11 <-- base of this mappings list vector | |
555 | mfsprg r12,0 ; get ptr to our per-proc | |
556 | andi. r9,r8,mpLists ; get #lists this mapping is on (1<=n<=27) | |
557 | la r12,skipListPrev+4(r12) ; r12 <-- base of prev ptr vector | |
558 | sub. r6,r9,r7 ; is this mapping on more lists than any other? | |
559 | slwi r8,r9,3 ; get #lists * 8 | |
560 | subi r8,r8,8 ; get offset to topmost (last) list in use | |
561 | bf-- pf64Bitb,mapIns32 ; handle 32-bit processor | |
562 | subi r10,r10,4 ; we use all 8 bytes of the ptr fields | |
563 | subi r11,r11,4 | |
564 | subi r12,r12,4 | |
565 | ble++ mapIns64a ; not new max #lists | |
566 | ||
567 | ; 64-bit processor: We must increase pmapCurLists. Since mapSearchFull() only | |
568 | ; sets up the first pmapCurLists prev ptrs, we must initialize the new ones to | |
569 | ; point to the pmap. While we are at it, we verify that the unused list hdrs in | |
570 | ; the pmap are 0. | |
571 | ||
572 | cmpwi r9,kSkipListMaxLists ; in range? | |
573 | stb r9,pmapCurLists(r3) ; remember new max | |
574 | mtctr r6 ; set up count of new lists | |
575 | mr r5,r8 ; copy offset to last list | |
576 | subi r0,r10,mpList0 ; r0 <-- fake mapping ptr (to pmap) for null prev ptrs | |
577 | bgt-- mapSkipListPanic ; choke if this mapping is on too many lists | |
578 | mapIns64NewList: | |
579 | ldx r6,r5,r10 ; get pmap list head | |
580 | stdx r0,r5,r12 ; initialize prev ptr | |
581 | subi r5,r5,8 ; get next list offset | |
582 | cmpdi r6,0 ; was list hdr null? | |
583 | bdnzt cr0_eq,mapIns64NewList ; loop if more lists to initialize and list hdr was 0 | |
584 | bne-- mapSkipListPanic ; die if pmap list hdr was not null | |
585 | b mapIns64a | |
586 | ||
587 | ; 64-bit processor: loop over each list this mapping is on | |
588 | ; r4 = mapping | |
589 | ; r8 = next list offset | |
590 | ; r10 = ptr to base of pmap list header vector | |
591 | ; r11 = ptr to base of new mappings list vector | |
592 | ; r12 = ptr to base of prev ptr vector in per-proc | |
593 | ||
594 | .align 5 | |
595 | mapIns64a: | |
596 | ldx r5,r8,r12 ; get prev ptr from per-proc vector | |
597 | cmpwi cr1,r8,0 ; more to go? | |
598 | la r7,mpList0(r5) ; get base of prev mappings list vector | |
599 | ldx r9,r8,r7 ; *** | |
600 | stdx r4,r8,r7 ; * insert new mapping in middle of this list | |
601 | stdx r9,r8,r11 ; *** | |
602 | subi r8,r8,8 ; get next list offset | |
603 | bne++ cr1,mapIns64a ; more lists to go | |
604 | blr ; done | |
605 | ||
606 | ; Handle 32-bit processor. First, increase pmapCurLists if necessary; cr0 is bgt | |
607 | ; iff the new mapping has more lists. Since mapSearchFull() only sets up the first | |
608 | ; pmapCurLists prev ptrs, we must initialize any new ones to point to the pmap. | |
609 | ; While we are at it, we verify that the unused list hdrs in the pmap are 0. | |
610 | ||
611 | mapIns32: | |
612 | ble+ mapIns32a ; skip if new mapping does not use extra lists | |
613 | cmpwi r9,kSkipListMaxLists ; in range? | |
614 | stb r9,pmapCurLists(r3) ; remember new max | |
615 | mtctr r6 ; set up count of new lists | |
616 | mr r5,r8 ; copy offset to last list | |
617 | subi r0,r10,mpList0+4 ; r0 <-- fake mapping ptr (to pmap) for null prev ptrs | |
618 | bgt- mapSkipListPanic ; choke if this mapping is on too many lists | |
619 | mapIns32NewList: | |
620 | lwzx r6,r5,r10 ; get pmap list head | |
621 | stwx r0,r5,r12 ; initialize prev ptr | |
622 | subi r5,r5,8 ; get next list offset | |
623 | cmpwi r6,0 ; was list hdr null? | |
624 | bdnzt cr0_eq,mapIns32NewList ; loop if more lists to initialize and list hdr was 0 | |
625 | bne- mapSkipListPanic ; die if pmap list hdr was not null | |
626 | b mapIns32a | |
627 | ||
628 | ; 32-bit processor: loop over each list this mapping is on | |
629 | ; r4 = mapping | |
630 | ; r8 = next list offset | |
631 | ; r10 = ptr to base of pmap list header vector | |
632 | ; r11 = ptr to base of new mappings list vector | |
633 | ; r12 = ptr to base of prev ptr vector | |
634 | ||
635 | .align 4 | |
636 | mapIns32a: | |
637 | lwzx r5,r8,r12 ; get prev ptr from per-proc vector | |
638 | cmpwi cr1,r8,0 ; more to go? | |
639 | la r7,mpList0+4(r5) ; get base of prev mappings list vector | |
640 | lwzx r9,r8,r7 ; *** | |
641 | stwx r4,r8,r7 ; * insert new mapping in middle of this list | |
642 | stwx r9,r8,r11 ; *** | |
643 | subi r8,r8,8 ; get next list offset | |
644 | bne+ cr1,mapIns32a ; more lists to go | |
645 | blr ; done | |
646 | ||
647 | ||
648 | /* | |
649 | * ********************* | |
650 | * * m a p R e m o v e * | |
651 | * ********************* | |
652 | * | |
653 | * Remove a mapping from pmap skip-lists. The caller has already called mapSearchFull to | |
654 | * find the mapping, which sets up the skipListPrev array with a vector of the previous | |
655 | * ptrs for each skip list. When called: | |
656 | * the pmap is locked (exclusive) | |
657 | * translation is off, interrupts masked | |
658 | * 64-bit mode is enabled (if on a 64-bit machine) | |
659 | * mapSearchFull has just been called for this mappings key | |
660 | * cr6 is loaded with the corresponding feature flags (in particular, pf64Bit) | |
661 | * r3 = pmap ptr | |
662 | * r4 = mapping ptr | |
663 | * | |
664 | * There is no return value. Except for cr6 (which is global), we trash nonvolatile regs. | |
665 | */ | |
666 | ||
667 | .align 5 | |
668 | .globl EXT(mapRemove) | |
669 | LEXT(mapRemove) | |
670 | lwz r8,mpFlags(r4) ; get this mappings flags | |
671 | lbz r10,pmapCurLists(r3) ; get current #lists in use | |
672 | la r11,mpList0+4(r4) ; r11 <-- base of this mappings list vector | |
673 | mfsprg r12,0 ; get ptr to our per-proc | |
674 | andi. r9,r8,mpLists ; get #lists this mapping is on (1<=n<=27) | |
675 | slwi r8,r9,3 ; get #lists * 8 | |
676 | cmpw cr5,r9,r10 ; compare mpLists to pmapCurLists | |
677 | la r12,skipListPrev+4(r12) ; r12 <-- base of prev ptr vector | |
678 | bgt-- cr5,mapSkipListPanic ; die if mpLists > pmapCurLists | |
679 | subi r8,r8,8 ; get offset to topmast (last) list this mapping is in | |
680 | bf-- pf64Bitb,mapRem32a ; skip if 32-bit processor | |
681 | subi r11,r11,4 ; we use all 64 bits of list links on 64-bit machines | |
682 | subi r12,r12,4 | |
683 | b mapRem64a | |
684 | ||
685 | ; 64-bit processor: loop over each list this mapping is on | |
686 | ; r3 = pmap | |
687 | ; r4 = mapping | |
688 | ; r8 = offset to next list | |
689 | ; r10 = pmapCurLists | |
690 | ; r11 = ptr to base of mapping list vector | |
691 | ; r12 = ptr to base of prev ptr vector in per-proc | |
692 | ; cr5 = beq if (mpLists == pmapCurLists) | |
693 | ||
694 | .align 5 | |
695 | mapRem64a: | |
696 | ldx r5,r8,r12 ; get prev ptr from per-proc vector | |
697 | ldx r9,r8,r11 ; get next ptr from mapping | |
698 | cmpwi cr1,r8,0 ; more to go? | |
699 | la r7,mpList0(r5) ; get base of prev mappings list vector | |
700 | stdx r9,r8,r7 ; point to next from prev | |
701 | subi r8,r8,8 ; get next list offset | |
702 | bne++ cr1,mapRem64a ; loop if another list to unlink from | |
703 | ||
704 | ; Did we reduce #lists in use by removing last mapping in last list? | |
705 | ||
706 | bnelr++ cr5 ; if (mpLists!=pmapCurLists) cannot have removed last map | |
707 | la r5,pmapSkipLists(r3) ; point to vector of list hdrs | |
708 | mapRem64b: | |
709 | subic. r10,r10,1 ; get base-0 list# | |
710 | slwi r8,r10,3 ; get offset to last list | |
711 | ldx r0,r8,r5 ; get last list ptr | |
712 | cmpdi cr1,r0,0 ; null? | |
713 | bnelr cr1 ; not null, so we are done | |
714 | stb r10,pmapCurLists(r3) ; was null, so decrement pmapCurLists | |
715 | bgt mapRem64b ; loop to see if more than one list was emptied | |
716 | blr | |
717 | ||
718 | ||
719 | ; 32-bit processor: loop over each list this mapping is on | |
720 | ; r3 = pmap | |
721 | ; r4 = mapping | |
722 | ; r8 = offset to next list | |
723 | ; r10 = pmapCurLists | |
724 | ; r11 = ptr to base of mapping list vector | |
725 | ; r12 = ptr to base of prev ptr vector in per-proc | |
726 | ; cr5 = beq if (mpLists == pmapCurLists) | |
727 | ||
728 | .align 4 | |
729 | mapRem32a: | |
730 | lwzx r5,r8,r12 ; get prev ptr from per-proc vector | |
731 | lwzx r9,r8,r11 ; get next ptr from mapping | |
732 | cmpwi cr1,r8,0 ; more to go? | |
733 | la r7,mpList0+4(r5) ; get base of prev mappings list vector | |
734 | stwx r9,r8,r7 ; point to next from prev | |
735 | subi r8,r8,8 ; get next list offset | |
736 | bne+ cr1,mapRem32a ; loop if another list to unlink from | |
737 | ||
738 | ; Did we reduce #lists in use by removing last mapping in last list? | |
739 | ||
740 | bnelr+ cr5 ; if (mpLists!=pmapCurLists) cannot have removed last map | |
741 | la r5,pmapSkipLists+4(r3) ; point to vector of list hdrs | |
742 | mapRem32b: | |
743 | subic. r10,r10,1 ; get base-0 list# | |
744 | slwi r8,r10,3 ; get offset to last list | |
745 | lwzx r0,r8,r5 ; get last list ptr | |
746 | cmpwi cr1,r0,0 ; null? | |
747 | bnelr cr1 ; not null, so we are done | |
748 | stb r10,pmapCurLists(r3) ; was null, so decrement pmapCurLists | |
749 | bgt mapRem32b ; loop to see if more than one list was emptied | |
750 | blr | |
751 | ||
752 | ||
753 | /* | |
754 | * ************************* | |
755 | * * m a p S e t L i s t s * | |
756 | * ************************* | |
757 | * | |
758 | * Called to decide how many skip-lists the next mapping will be on. For each pmap, | |
759 | * we maintain a psuedo-random sequence based on a linear feedback shift register. The | |
760 | * next number is generated by rotating the old value left by 1 and XORing with a | |
761 | * polynomial (actually 4 8-bit polynomials concatanated) and adding 1. | |
762 | * The simple (unclamped) number of lists a mapping is on is the number of trailing 0s | |
763 | * in the pseudo-random sequence, shifted by the (log2-1) of the fanout F, plus one. | |
764 | * This seems to give us a near perfect distribution, in the sense that about F times more nodes | |
765 | * are allocated on n lists, as are on (n+1) lists. | |
766 | * | |
767 | * At one point we used a simple counter to assign lists. While this gave perfect | |
768 | * distribution, there were certain access pattern that would drive a worst case | |
769 | * distribution (e.g., insert low, then high, then low, etc.). Unfortunately, | |
770 | * these patterns were not too uncommon. We changed to a less-than-perfect assignment, | |
771 | * but one that works consistently across all known access patterns. | |
772 | * | |
773 | * Also, we modify the "simple" trailing-0-based list count, to account for an important | |
774 | * observation: because VM does a lot of removing and restoring of mappings in the process of | |
775 | * doing copy-on-write etc, it is common to have the pmap's "random number" (ie, the | |
776 | * count of created mappings) be much larger than the number of mappings currently in the | |
777 | * pmap. This means the simple list count will often be larger than justified by the number of | |
778 | * mappings in the pmap. To avoid this common situation, we clamp the list count to be no more | |
779 | * than ceil(logBaseF(pmapResidentCnt)). | |
780 | * | |
781 | * Finally, we also clamp the list count to kSkipListMaxLists. | |
782 | * | |
783 | * We are passed the pmap ptr in r3. Called with translation on, interrupts enabled, | |
784 | * and in 32-bit mode. | |
785 | */ | |
786 | .align 5 | |
787 | .globl EXT(mapSetLists) | |
788 | LEXT(mapSetLists) | |
789 | lwz r5,pmapRandNum(r3) ; get the per-pmap counter of mapping creates | |
790 | lwz r4,pmapResidentCnt(r3) ; get number of mappings in this pmap | |
791 | lis r11,hi16(0xA7CBF5B9) ; Get polynomial (I just made this up...) | |
792 | li r0,-1 ; get a mask of 1s | |
793 | ori r11,r11,lo16(0xA7CBF5B9) ; Get polynomial (I just made this up...) | |
794 | rlwinm r5,r5,1,0,31 ; Rotate | |
795 | cntlzw r7,r4 ; get magnitude of pmapResidentCnt | |
796 | xor r5,r5,r11 ; Munge with poly | |
797 | srw r7,r0,r7 ; r7 <- mask for magnitude of pmapResidentCnt | |
798 | addi r6,r5,1 ; increment pmapRandNum non-atomically | |
799 | andc r8,r5,r6 ; get a mask for trailing zeroes in pmapRandNum | |
800 | stw r6,pmapRandNum(r3) ; update "random number" | |
801 | and r8,r8,r7 ; clamp trailing 0s to magnitude of pmapResidentCnt | |
802 | rlwinm r8,r8,0,32-(kSkipListMaxLists*(kSkipListFanoutShift+1))+1,31 ; clamp to kSkipListMaxLists | |
803 | cntlzw r9,r8 ; count leading 0s in the mask | |
804 | subfic r10,r9,32 ; r10 <- trailing zero count | |
805 | srwi r11,r10,kSkipListFanoutShift ; shift by 1 if fanout is 4, 2 if 8, etc | |
806 | addi r3,r11,1 ; every mapping is on at least one list | |
807 | blr | |
808 | ||
809 | ||
810 | /* | |
811 | * ************************************* | |
812 | * * m a p S k i p L i s t V e r i f y * | |
813 | * ************************************* | |
814 | * | |
815 | * This does a fairly thorough sweep through a pmaps skip-list data structure, doing | |
816 | * consistency checks. It is typically called (from hw_exceptions.s) from debug or | |
817 | * instrumented builds. It is probably not a good idea to call this in production builds, | |
818 | * as it must run with exceptions disabled and can take a long time to verify a big pmap. | |
819 | * It runs in O(n*ln(n)). | |
820 | * | |
821 | * Called on a bl, with the pmap ptr in r20. We assume the pmap is locked (shared) and | |
822 | * that EE and DR are off. We check all 64 bits of ptrs even on 32-bit machines. | |
823 | * We use r20-r31, cr0, cr1, and cr7. If we return, no inconsistencies were found. | |
824 | * | |
825 | * You will notice we make little attempt to schedule the code; clarity is deemed more | |
826 | * important than speed. | |
827 | */ | |
828 | ||
829 | ||
830 | /* | |
831 | * mapSkipListVerifyC is a version that is callable from C. | |
832 | * This should be called only from the debugger, IT DOES NOT LOCK THE PMAP!!!! | |
833 | */ | |
834 | ||
835 | .globl EXT(mapSkipListVerifyC) | |
836 | LEXT(mapSkipListVerifyC) | |
837 | ||
838 | stwu r1,-(FM_ALIGN((31-13+1)*4)+FM_SIZE)(r1) ; Make some space on the stack | |
839 | mflr r0 ; Save the link register | |
840 | stmw r13,FM_ARG0(r1) ; Save all registers | |
841 | stw r0,(FM_ALIGN((31-13+1)*4)+FM_SIZE+FM_LR_SAVE)(r1) ; Save the return | |
842 | ||
843 | lwz r15,pmapvr(r3) ; Get the V to R translation | |
844 | lwz r16,pmapvr+4(r3) ; Get the V to R translation | |
845 | mr r19,r4 ; Save register dump area | |
846 | ||
847 | bl EXT(mapSetUp) ; Get set up | |
848 | ||
849 | mr r17,r11 | |
850 | xor r20,r3,r16 ; Translate 32-bit portion | |
851 | bf-- pf64Bitb,mslvc32a ; Skip if 32-bit... | |
852 | ||
853 | rldimi r20,r15,32,0 ; Shift the fixed upper part of the physical over and cram in top | |
854 | ||
855 | mslvc32a: lis r18,hi16(EXT(DebugWork)) | |
856 | ori r18,r18,lo16(EXT(DebugWork)) | |
857 | li r0,0x4262 | |
858 | stw r0,4(r18) ; Make sure the test knows to run | |
859 | ||
860 | bl EXT(mapSkipListVerify) ; Run the test | |
861 | ||
862 | li r0,0 | |
863 | stw r0,4(r18) ; Remove explicit call flag | |
864 | ||
865 | bt++ pf64Bitb,mslvc64a ; This is 64-bit... | |
866 | ||
867 | mtmsr r17 ; Restore enables/translation/etc. | |
868 | isync | |
869 | ||
870 | li r0,0 | |
871 | stw r0,0x000+0(r19) | |
872 | stw r0,0x000+4(r19) | |
873 | stw r0,0x008+0(r19) | |
874 | stw r1,0x008+4(r19) | |
875 | stw r0,0x010+0(r19) | |
876 | stw r2,0x010+4(r19) | |
877 | stw r0,0x018+0(r19) | |
878 | stw r3,0x018+4(r19) | |
879 | stw r0,0x020+0(r19) | |
880 | stw r4,0x020+4(r19) | |
881 | stw r0,0x028+0(r19) | |
882 | stw r5,0x028+4(r19) | |
883 | stw r0,0x030+0(r19) | |
884 | stw r6,0x030+4(r19) | |
885 | stw r0,0x038+0(r19) | |
886 | stw r7,0x038+4(r19) | |
887 | stw r0,0x040+0(r19) | |
888 | stw r8,0x040+4(r19) | |
889 | stw r0,0x048+0(r19) | |
890 | stw r9,0x048+4(r19) | |
891 | stw r0,0x050+0(r19) | |
892 | stw r10,0x050+4(r19) | |
893 | stw r0,0x058+0(r19) | |
894 | stw r11,0x058+4(r19) | |
895 | stw r0,0x060+0(r19) | |
896 | stw r12,0x060+4(r19) | |
897 | stw r0,0x068+0(r19) | |
898 | stw r13,0x068+4(r19) | |
899 | stw r0,0x070+0(r19) | |
900 | stw r14,0x070+4(r19) | |
901 | stw r0,0x078+0(r19) | |
902 | stw r15,0x078+4(r19) | |
903 | stw r0,0x080+0(r19) | |
904 | stw r16,0x080+4(r19) | |
905 | stw r0,0x088+0(r19) | |
906 | stw r17,0x088+4(r19) | |
907 | stw r0,0x090+0(r19) | |
908 | stw r18,0x090+4(r19) | |
909 | stw r0,0x098+0(r19) | |
910 | stw r19,0x098+4(r19) | |
911 | stw r0,0x0A0+0(r19) | |
912 | stw r20,0x0A0+4(r19) | |
913 | stw r0,0x0A8+0(r19) | |
914 | stw r21,0x0A8+4(r19) | |
915 | stw r0,0x0B0+0(r19) | |
916 | stw r22,0x0B0+4(r19) | |
917 | stw r0,0x0B8+0(r19) | |
918 | stw r23,0x0B8+4(r19) | |
919 | stw r0,0x0C0+0(r19) | |
920 | stw r24,0x0C0+4(r19) | |
921 | stw r0,0x0C8+0(r19) | |
922 | stw r25,0x0C8+4(r19) | |
923 | stw r0,0x0D0+0(r19) | |
924 | stw r26,0x0D0+4(r19) | |
925 | stw r0,0x0D8+0(r19) | |
926 | stw r27,0x0D8+4(r19) | |
927 | stw r0,0x0E0+0(r19) | |
928 | stw r28,0x0E0+4(r19) | |
929 | stw r0,0x0E8+0(r19) | |
930 | stw r29,0x0E8+4(r19) | |
931 | stw r0,0x0F0+0(r19) | |
932 | stw r30,0x0F0+4(r19) | |
933 | stw r0,0x0F8+0(r19) | |
934 | stw r31,0x0F8+4(r19) | |
935 | ||
936 | b mslvcreturn ; Join common... | |
937 | ||
938 | mslvc64a: mtmsrd r17 ; Restore enables/translation/etc. | |
939 | isync | |
940 | ||
941 | std r0,0x000(r19) | |
942 | std r1,0x008(r19) | |
943 | std r2,0x010(r19) | |
944 | std r3,0x018(r19) | |
945 | std r4,0x020(r19) | |
946 | std r5,0x028(r19) | |
947 | std r6,0x030(r19) | |
948 | std r7,0x038(r19) | |
949 | std r8,0x040(r19) | |
950 | std r9,0x048(r19) | |
951 | std r10,0x050(r19) | |
952 | std r11,0x058(r19) | |
953 | std r12,0x060(r19) | |
954 | std r13,0x068(r19) | |
955 | std r14,0x070(r19) | |
956 | std r15,0x078(r19) | |
957 | std r16,0x080(r19) | |
958 | std r17,0x088(r19) | |
959 | std r18,0x090(r19) | |
960 | std r19,0x098(r19) | |
961 | std r20,0x0A0(r19) | |
962 | std r21,0x0A8(r19) | |
963 | std r22,0x0B0(r19) | |
964 | std r23,0x0B8(r19) | |
965 | std r24,0x0C0(r19) | |
966 | std r25,0x0C8(r19) | |
967 | std r26,0x0D0(r19) | |
968 | std r27,0x0D8(r19) | |
969 | std r28,0x0E0(r19) | |
970 | std r29,0x0E8(r19) | |
971 | std r30,0x0F0(r19) | |
972 | std r31,0x0F8(r19) | |
973 | ||
974 | ||
975 | mslvcreturn: | |
976 | lwz r0,(FM_ALIGN((31-13+1)*4)+FM_SIZE+FM_LR_SAVE)(r1) ; Get the return | |
977 | lmw r13,FM_ARG0(r1) ; Get the registers | |
978 | mtlr r0 ; Restore the return | |
979 | lwz r1,0(r1) ; Pop the stack | |
980 | blr | |
981 | ||
982 | ||
983 | .globl EXT(mapSkipListVerify) | |
984 | LEXT(mapSkipListVerify) | |
985 | mflr r31 ; save LR so we can bl to mapVerifyDie | |
986 | ||
987 | ; If we have already found an inconsistency and died, don not do so again, to | |
988 | ; avoid a loop. | |
989 | ||
990 | lis r27,hi16(EXT(DebugWork)) | |
991 | ori r27,r27,lo16(EXT(DebugWork)) | |
992 | lwz r0,4(r27) ; Get the explicit entry flag | |
993 | lwz r27,0(r27) ; Get lockout | |
994 | cmplwi r0,0x4262 ; Should we run anyway? | |
995 | beq-- mslvAnyway ; Yes... | |
996 | cmpwi r27,0 ; have we already found an error? | |
997 | bnelr-- ; yes, just return wo checking again | |
998 | ||
999 | mslvAnyway: | |
1000 | ; Not recursive call, so initialize. | |
1001 | ||
1002 | mfsprg r23,2 ; get the feature flags | |
1003 | mtcrf 0x02,r23 ; put pf64Bit where we can test it | |
1004 | lbz r26,pmapCurLists(r20) ; get #lists that are in use | |
1005 | lwz r21,pmapResidentCnt(r20); get #mappings in this pmap | |
1006 | cmpwi r26,kSkipListMaxLists ; in range? | |
1007 | bgtl-- mapVerifyDie ; pmapCurLists is too big | |
1008 | ||
1009 | ; To prevent infinite loops, set limit of (pmapCurLists*pmapResidentCnt) iterations. | |
1010 | ; Since we walk each list this is the max number of mappings we could visit. | |
1011 | ||
1012 | li r23,0 ; initialize count | |
1013 | mapVer0: | |
1014 | subic. r26,r26,1 ; loop pmapCurLists times (but at least once) | |
1015 | add r23,r23,r21 ; compute (pmapCurLists*pmapResidentCnt) | |
1016 | bgt mapVer0 ; this will be a 64-bit qty on 64-bit machines | |
1017 | ||
1018 | li r22,kSkipListMaxLists ; initialize list# | |
1019 | bf-- pf64Bitb,mapVer32 ; go handle a 32-bit processor | |
1020 | ||
1021 | ; 64-bit machine. | |
1022 | ; | |
1023 | ; Loop over each list, counting mappings in each. We first check whether or not | |
1024 | ; the list is empty (ie, if the pmapSlipLists ptr is null.) All lists above | |
1025 | ; pmapCurLists should be empty, and no list at or below pmapCurLists should be. | |
1026 | ; r20 = pmap ptr | |
1027 | ; r21 = decrementing counter of mappings in this pmap | |
1028 | ; r22 = next list# (1...kSkipListMaxLists) | |
1029 | ; r23 = decrementing counter for infinite loop check | |
1030 | ||
1031 | mapVer64: | |
1032 | slwi r25,r22,3 ; get offset to next skiplist | |
1033 | la r26,pmapSkipLists(r20) ; get ptr to base of skiplist vector | |
1034 | subi r25,r25,8 | |
1035 | ldx r26,r25,r26 ; get 1st mapping on this list, if any | |
1036 | lbz r28,pmapCurLists(r20) ; get #lists in use | |
1037 | cmpdi cr6,r26,0 ; set cr6_eq if this list is null ("null") | |
1038 | cmpw cr7,r22,r28 ; set cr7_gt if this list is > pmapCurLists ("high") | |
1039 | crxor cr0_eq,cr6_eq,cr7_gt ; cr0_eq <-- (null & !high) | (!null & high) | |
1040 | beql-- mapVerifyDie ; die if this list is null when it should not be, etc | |
1041 | b mapVer64g | |
1042 | ||
1043 | ; Loop over each node in the list. | |
1044 | ; r20 = pmap ptr | |
1045 | ; r21 = decrementing counter of mappings in this pmap | |
1046 | ; r22 = this list# (1...kSkipListMaxLists) | |
1047 | ; r23 = decrementing counter for infinite loop check | |
1048 | ; r25 = offset to this skiplist (ie, ((r22<<3)-8)) | |
1049 | ; r26 = mapping | |
1050 | ||
1051 | mapVer64a: | |
1052 | lwz r29,mpFlags(r26) ; get bits for this mapping | |
1053 | ld r28,mpVAddr(r26) ; get key | |
1054 | subic. r23,r23,1 ; check for loops | |
1055 | bltl-- mapVerifyDie ; we have visited > (pmapCurLists*pmapResidentCnt) nodes | |
1056 | andi. r30,r26,mpBasicSize-1 ; test address for alignment | |
1057 | bnel-- mapVerifyDie ; not aligned | |
1058 | andi. r27,r29,mpLists ; get #lists this mapping is supposed to be on | |
1059 | cmpw cr1,r27,r22 ; is it supposed to be on this list? | |
1060 | bltl-- cr1,mapVerifyDie ; mappings mpLists is too low | |
1061 | cmpwi r27,kSkipListMaxLists ; too big? | |
1062 | bgtl-- mapVerifyDie ; mappings mpLists > max | |
1063 | rldicr r28,r28,0,51 ; clear low 12 bits of va | |
1064 | bne++ cr1,mapVer64f ; jump if this is not highest list for this node | |
1065 | ||
1066 | ; This is the "highest" (last) list this mapping is on. | |
1067 | ; Do some additional checks (so we only do them once per mapping.) | |
1068 | ; First, if a block mapping or nested pmap, compute block end. | |
1069 | ||
1070 | lhz r27,mpBSize(r26) ; get #pages or #segments | |
1071 | rlwinm r29,r29,mpBSub+1,31,31 ; Rotate to get 0 if 4K bsu or 1 if 32MB bsu | |
1072 | addi r27,r27,1 ; units of nested pmap are (#segs-1) | |
1073 | ori r29,r29,0x3216 ; OR in 0x00003216 (0x3200 and a base rotate of 22) | |
1074 | rlwnm r29,r29,r29,27,31 ; Rotate to get 12 or 25 | |
1075 | subi r21,r21,1 ; count mappings in this pmap | |
1076 | sld r29,r27,r29 ; Get the length in bytes | |
1077 | subi r29,r29,4096 ; get offset to last byte in nested pmap | |
1078 | ||
1079 | ; Here with r29 = size of block - 4k, or 0 if mapping is a scalar page. | |
1080 | ||
1081 | add r24,r28,r29 ; r24 <- address of last valid page in this mapping | |
1082 | la r28,mpList0(r26) ; get base of this mappings vector | |
1083 | lwz r27,mpFlags(r26) ; Get the number of lists | |
1084 | andi. r27,r27,mpLists ; get #lists this mapping is on (1<=n<=27) | |
1085 | cmplwi r27,mpBasicLists ; Into bigger mapping? | |
1086 | li r27,mpBasicLists*8-8 ; Assume normal | |
1087 | ble+ mapVer64c ; It is... | |
1088 | li r27,kSkipListMaxLists*8-8 ; initialize list offset for inner loop | |
1089 | ||
1090 | ; Inner loop over each list link in this mappingss mpList vector. | |
1091 | ; r24 = address of last valid page in this mapping | |
1092 | ; r27 = offset for next list in inner loop | |
1093 | ; r28 = base of this mappings list links | |
1094 | ||
1095 | mapVer64c: | |
1096 | cmpw cr1,r27,r25 ; higher, lower, or same? | |
1097 | ldx r29,r27,r28 ; get link to next mapping at this level | |
1098 | mr. r29,r29 ; null? | |
1099 | beq mapVer64d ; link null, which is always OK | |
1100 | bgtl-- cr1,mapVerifyDie ; a mapping has a non-null list higher than its mpLists | |
1101 | ld r30,mpVAddr(r29) ; get next mappings va | |
1102 | rldicr r30,r30,0,51 ; zero low 12 bits | |
1103 | cmpld r30,r24 ; compare next key with ours | |
1104 | blel-- mapVerifyDie ; a next node has key <= to ours | |
1105 | mapVer64d: | |
1106 | subic. r27,r27,8 ; move on to next list | |
1107 | bne++ mapVer64c ; loop if more to go | |
1108 | ||
1109 | ; Next node on current list, or next list if current done, or return if no more lists. | |
1110 | ||
1111 | mapVer64f: | |
1112 | la r28,mpList0(r26) ; get base of this mappings vector | |
1113 | ldx r26,r25,r28 ; get next mapping on this list | |
1114 | mapVer64g: | |
1115 | mr. r26,r26 ; is there one? | |
1116 | bne++ mapVer64a ; yes, handle | |
1117 | subic. r22,r22,1 ; is there another list? | |
1118 | bgt++ mapVer64 ; loop if so | |
1119 | ||
1120 | cmpwi r21,0 ; did we find all the mappings in the pmap? | |
1121 | bnel-- mapVerifyDie ; no | |
1122 | mtlr r31 ; restore return address | |
1123 | li r3,0 | |
1124 | blr | |
1125 | ||
1126 | ||
1127 | ; Handle 32-bit machine. | |
1128 | ||
1129 | mapVer32: | |
1130 | lwz r24,mpFlags(r20) ; Get number of lists | |
1131 | la r30,pmapSkipLists(r20) ; first, check the pmap list hdrs | |
1132 | andi. r24,r24,mpLists ; Clean the number of lists | |
1133 | bl mapVerUpperWordsAre0 ; are the upper words of each list all 0? | |
1134 | ||
1135 | ; Loop over each list, counting mappings in each. We first check whether or not | |
1136 | ; the list is empty. All lists above pmapCurLists should be empty, and no list | |
1137 | ; at or below pmapCurLists should be. | |
1138 | ; | |
1139 | ; r20 = pmap ptr | |
1140 | ; r21 = decrementing counter of mappings in this pmap | |
1141 | ; r22 = next list# (1...kSkipListMaxLists) | |
1142 | ; r23 = decrementing counter for infinite loop check | |
1143 | ||
1144 | mapVer32NextList: | |
1145 | lbz r28,pmapCurLists(r20) ; get #lists in use | |
1146 | slwi r25,r22,3 ; get offset to next skiplist | |
1147 | la r26,pmapSkipLists+4(r20) ; get ptr to base of skiplist vector | |
1148 | subi r25,r25,8 | |
1149 | lwzx r26,r25,r26 ; get the 1st mapping on this list, or 0 | |
1150 | cmpw cr7,r22,r28 ; set cr7_gt if this list is > pmapCurLists ("high") | |
1151 | cmpwi cr6,r26,0 ; set cr6_eq if this list is null ("null") | |
1152 | crxor cr0_eq,cr6_eq,cr7_gt ; cr0_eq <-- (null & !high) | (!null & high) | |
1153 | beql- mapVerifyDie ; die if this list is null when it should not be, etc | |
1154 | b mapVer32g | |
1155 | ||
1156 | ; Loop over each node in the list. | |
1157 | ; r20 = pmap ptr | |
1158 | ; r21 = decrementing counter of mappings in this pmap | |
1159 | ; r22 = this list# (1...kSkipListMaxLists) | |
1160 | ; r23 = decrementing counter for infinite loop check | |
1161 | ; r25 = offset to this skiplist (ie, ((r22<<3)-8)) | |
1162 | ; r26 = mapping | |
1163 | ||
1164 | mapVer32a: | |
1165 | lwz r29,mpFlags(r26) ; get bits for this mapping | |
1166 | andi. r30,r26,mpBasicSize-1 ; test address for alignment | |
1167 | lwz r24,mpVAddr+0(r26) ; get upper word of key | |
1168 | bnel- mapVerifyDie ; mapping address not 64-byte aligned | |
1169 | lwz r28,mpVAddr+4(r26) ; get lower word of key | |
1170 | subic. r23,r23,1 ; check for loops | |
1171 | bltl- mapVerifyDie ; we have visited > (pmapCurLists*pmapResidentCnt) nodes | |
1172 | cmpwi r24,0 ; upper word of key (ie, va) should be 0 | |
1173 | bnel- mapVerifyDie ; was not | |
1174 | andi. r27,r29,mpLists ; get #lists this mapping is supposed to be on | |
1175 | cmpw cr1,r27,r22 ; is it supposed to be on this list? | |
1176 | bltl- cr1,mapVerifyDie ; mappings mpLists is too low | |
1177 | cmpwi r27,kSkipListMaxLists ; too big? | |
1178 | bgtl- mapVerifyDie ; mappings mpLists > max | |
1179 | rlwinm r28,r28,0,0,19 ; clear low 12 bits of va | |
1180 | bne+ cr1,mapVer32f ; jump if this is not highest list for this node | |
1181 | ||
1182 | ; This is the "highest" (last) list this mapping is on. | |
1183 | ; Do some additional checks (so we only do them once per mapping.) | |
1184 | ; First, make sure upper words of the mpList vector are 0. | |
1185 | ||
1186 | lhz r27,mpBSize(r26) ; get #blocks | |
1187 | rlwinm r29,r29,mpBSub+1,31,31 ; Rotate to get 0 if 4K bsu or 1 if 32MB bsu | |
1188 | addi r27,r27,1 ; units of nested pmap are (#segs-1) | |
1189 | ori r29,r29,0x3216 ; OR in 0x00003216 (0x3200 and a base rotate of 22) | |
1190 | rlwnm r29,r29,r29,27,31 ; Rotate to get 12 or 25 | |
1191 | subi r21,r21,1 ; count mappings in this pmap | |
1192 | slw r29,r27,r29 ; Get the length in bytes | |
1193 | subi r29,r29,4096 ; get offset to last byte in nested pmap | |
1194 | ||
1195 | lwz r24,mpFlags(r26) ; Get number of lists | |
1196 | la r30,mpList0(r26) ; point to base of skiplist vector | |
1197 | andi. r24,r24,mpLists ; Clean the number of lists | |
1198 | bl mapVerUpperWordsAre0 ; make sure upper words are all 0 (uses r24 and r27) | |
1199 | ||
1200 | ; Here with r29 = size of block - 4k, or 0 if mapping is a scalar page. | |
1201 | ||
1202 | add r24,r28,r29 ; r24 <- address of last valid page in this mapping | |
1203 | la r28,mpList0+4(r26) ; get base of this mappings vector | |
1204 | lwz r27,mpFlags(r26) ; Get the number of lists | |
1205 | andi. r27,r27,mpLists ; get #lists this mapping is on (1<=n<=27) | |
1206 | cmplwi r27,mpBasicLists ; Into bigger mapping? | |
1207 | li r27,mpBasicLists*8-8 ; Assume normal | |
1208 | ble+ mapVer32c ; It is... | |
1209 | li r27,kSkipListMaxLists*8-8 ; initialize list offset for inner loop | |
1210 | ||
1211 | ; Inner loop over each list in this mappings mpList vector. | |
1212 | ; r24 = address of last valid page in this mapping | |
1213 | ; r27 = offset for next list in inner loop | |
1214 | ; r28 = base of this mappings list links | |
1215 | ||
1216 | mapVer32c: | |
1217 | cmpw cr1,r27,r25 ; higher, lower, or same? | |
1218 | lwzx r29,r27,r28 ; get link to next mapping at this level | |
1219 | mr. r29,r29 ; null? | |
1220 | beq mapVer32d ; link null, which is always OK | |
1221 | ||
1222 | ||
1223 | bgtl- cr1,mapVerifyDie ; a mapping has a non-null list higher than its mpLists | |
1224 | lwz r30,mpVAddr+4(r29) ; get next mappings va | |
1225 | rlwinm r30,r30,0,0,19 ; zero low 12 bits | |
1226 | cmplw r30,r24 ; compare next key with ours | |
1227 | blel- mapVerifyDie ; a next node has key <= to ours | |
1228 | mapVer32d: | |
1229 | subic. r27,r27,8 ; move on to next list | |
1230 | bne+ mapVer32c ; loop if more to go | |
1231 | ||
1232 | ; Next node on current list, or next list if current done, or return if no more lists. | |
1233 | ||
1234 | mapVer32f: | |
1235 | la r28,mpList0+4(r26) ; get base of this mappings vector again | |
1236 | lwzx r26,r25,r28 ; get next mapping on this list | |
1237 | mapVer32g: | |
1238 | mr. r26,r26 ; is there one? | |
1239 | bne+ mapVer32a ; yes, handle | |
1240 | subic. r22,r22,1 ; is there another list? | |
1241 | bgt+ mapVer32NextList ; loop if so | |
1242 | ||
1243 | cmpwi r21,0 ; did we find all the mappings in the pmap? | |
1244 | bnel- mapVerifyDie ; no | |
1245 | mtlr r31 ; restore return address | |
1246 | li r3,0 | |
1247 | blr | |
1248 | ||
1249 | ; Subroutine to verify that the upper words of a vector of kSkipListMaxLists | |
1250 | ; doublewords are 0. | |
1251 | ; r30 = ptr to base of vector | |
1252 | ; Uses r24 and r27. | |
1253 | ||
1254 | mapVerUpperWordsAre0: | |
1255 | cmplwi r24,mpBasicLists ; Do we have more than basic? | |
1256 | li r24,mpBasicLists*8 ; Assume basic | |
1257 | ble++ mapVerUpper1 ; We have the basic size | |
1258 | li r24,kSkipListMaxLists*8 ; Use max size | |
1259 | ||
1260 | mapVerUpper1: | |
1261 | subic. r24,r24,8 ; get offset to next doubleword | |
1262 | lwzx r27,r24,r30 ; get upper word | |
1263 | cmpwi cr1,r27,0 ; 0 ? | |
1264 | bne- cr1,mapVerifyDie ; die if not, passing callers LR | |
1265 | bgt+ mapVerUpper1 ; loop if more to go | |
1266 | blr | |
1267 | ||
1268 | ; bl here if mapSkipListVerify detects an inconsistency. | |
1269 | ||
1270 | mapVerifyDie: | |
1271 | mflr r3 | |
1272 | mtlr r31 ; Restore return | |
1273 | lis r31,hi16(EXT(DebugWork)) | |
1274 | ori r31,r31,lo16(EXT(DebugWork)) | |
1275 | lwz r0,4(r31) ; Get the explicit entry flag | |
1276 | cmplwi r0,0x4262 ; Should we run anyway? | |
1277 | beqlr-- ; Explicit call, return... | |
1278 | ||
1279 | li r0,1 | |
1280 | stw r0,0(r31) ; Lock out further calls | |
1281 | BREAKPOINT_TRAP ; hopefully, enter debugger | |
1282 | b .-4 | |
1283 | ||
1284 | ||
1285 | /* | |
1286 | * Panic (choke, to be exact) because of messed up skip lists. The LR points back | |
1287 | * to the original caller of the skip-list function. | |
1288 | */ | |
1289 | ||
1290 | mapSkipListPanic: ; skip-lists are screwed up | |
1291 | lis r0,hi16(Choke) | |
1292 | ori r0,r0,lo16(Choke) | |
1293 | li r3,failSkipLists ; get choke code | |
1294 | sc ; choke | |
1295 | b .-4 | |
1296 | ||
1297 |