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