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