|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
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.
11: *
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
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * This file is used to maintain the virtual to real mappings for a PowerPC machine.
24: * The code herein is primarily used to bridge between the pmap layer and the hardware layer.
25: * Currently, some of the function of this module is contained within pmap.c. We may want to move
26: * all of this into it (or most anyway) for the sake of performance. We shall see as we write it.
27: *
28: * We also depend upon the structure of the phys_entry control block. We do put some processor
29: * specific stuff in there.
30: *
31: */
32:
33: #include <cpus.h>
34: #include <debug.h>
35: #include <mach_kgdb.h>
36: #include <mach_vm_debug.h>
37: #include <db_machine_commands.h>
38:
39: #include <kern/thread.h>
40: #include <kern/thread_act.h>
41: #include <mach/vm_attributes.h>
42: #include <mach/vm_param.h>
43: #include <vm/vm_kern.h>
44: #include <vm/vm_map.h>
45: #include <vm/vm_page.h>
46: #include <kern/spl.h>
47:
48: #include <kern/misc_protos.h>
49: #include <ppc/misc_protos.h>
50: #include <ppc/proc_reg.h>
51:
52: #include <vm/pmap.h>
53: #include <ppc/pmap.h>
54: #include <ppc/pmap_internals.h>
55: #include <ppc/mem.h>
56:
57: #include <ppc/new_screen.h>
58: #include <ppc/Firmware.h>
59: #include <ppc/mappings.h>
60: #include <ppc/miscserv.h>
61: #include <ddb/db_output.h>
62:
63: #define PERFTIMES 0
64:
65: #if PERFTIMES && DEBUG
66: #define debugLog2(a, b, c) dbgLog2(a, b, c)
67: #else
68: #define debugLog2(a, b, c)
69: #endif
70:
71: autogenblok *AutoGenList; /* Anchor for the autogeb list */
72: space_t curr_spaceID = 0; /* Highest used space ID */
73: unsigned int incrVSID = 0; /* VSID increment value */
74: unsigned int mappingdeb0 = 0;
75: extern unsigned int hash_table_size;
76: extern unsigned int debsave0;
77: extern unsigned int dbdbdb; /* (TEST/DEBUG) */
78: extern vm_offset_t mem_size;
79: /*
80: * ppc_prot translates from the mach representation of protections to the PPC version.
81: * Calculation of it like this saves a memory reference - and maybe a couple of microseconds.
82: * It eliminates the used of this table.
83: * unsigned char ppc_prot[8] = { 0, 3, 2, 2, 3, 3, 2, 2 };
84: */
85:
86: #define ppc_prot(p) ((0xAFAC >> (p << 1)) & 3)
87:
88: /*
89: * mapping_space();
90: * This function is called to generate an address space ID. This space ID must be unique within
91: * the system. For the PowerPC, it is used to build the VSID. We build a VSID in the following
92: * way: space ID << 4 | segment. Since a VSID is 24 bits, and out of that, we reserve the last
93: * 4, so, we can have 2^20 (2M) unique IDs. Each pmap has a unique space ID, so we should be able
94: * to have 2M pmaps at a time, which we couldn't, we'd run out of memory way before then. The
95: * problem is that only a certain number of pmaps are kept in a free list and if that is full,
96: * they are release. This causes us to lose track of what space IDs are free to be reused.
97: * We can do 4 things: 1) not worry about it, 2) keep all free pmaps, 3) rebuild all mappings
98: * when the space ID wraps, or 4) scan the list of pmaps and find a free one.
99: *
100: * Yet another consideration is the hardware use of the VSID. It is used as part of the hash
101: * calculation for virtual address lookup. An improperly chosen value could potentially cause
102: * too many hashes to hit the same bucket, causing PTEG overflows. The actual hash function
103: * is (page index XOR vsid) mod number of ptegs. For a 32MB machine, using the suggested
104: * hash table size, there are 2^12 (8192) PTEGs. Remember, though, that the bottom 4 bits
105: * are reserved for the segment number, which means that we really have 2^(12-4) 512 space IDs
106: * before we start hashing to the same buckets with the same vaddrs. Also, within a space ID,
107: * every 8192 pages (32MB) within a segment will hash to the same bucket. That's 8 collisions
108: * per segment. So, a scan of every page for 256MB would fill 32 PTEGs completely, but
109: * with no overflow. I don't think that this is a problem.
110: *
111: * There may be a problem with the space ID, though. A new space ID is generate (mainly)
112: * whenever there is a fork. There shouldn't really be any problem because (for a 32MB
113: * machine) we can have 512 pmaps and still not have hash collisions for the same address.
114: * The potential problem, though, is if we get long-term pmaps that have space IDs that are
115: * the same modulo 512. We can reduce this problem by having the segment number be bits
116: * 0-3 of the space ID rather than 20-23. Doing this means that, in effect, corresponding
117: * vaddrs in different segments hash to the same PTEG. While this is somewhat of a problem,
118: * I don't think that it is as signifigant as the other, so, I'll make the space ID
119: * with segment first.
120: *
121: * The final, and biggest problem is the wrap, which will happen every 2^20 space IDs.
122: * While this is a problem that should only happen in periods counted in weeks, it can and
123: * will happen. This is assuming a monotonically increasing space ID. If we were to search
124: * for an inactive space ID, there could not be a wrap until there was 2^20 concurrent space IDs.
125: * That's pretty unlikely to happen. There couldn't be enough storage to support a million tasks.
126: * Another potential solution is to monitor for the wrap, and reorganize the space IDs when it happens.
127: * This is rather severe, and would have user-perceivable performance impact. It would be necessary
128: * to quiese all other processors, invalidate and purge the entire hash table, and then to reassign
129: * all space IDs in active pmaps. It may be better to amortize the problem by keeping pmaps in sorted
130: * order and keeping track of the lowest unused space ID. I'll think on this one and do a panic
131: * until I got it sussed.
132: */
133:
134: space_t mapping_space(void) { /* Generate a unique space ID */
135:
136: register space_t currSID, nextSID;
137:
138: while(1) { /* Keep trying until something happens */
139: currSID=curr_spaceID; /* Get a copy of the current ID */
140: if(!(nextSID = ((currSID + incrVSID) & SID_MAX))) { /* Get the next one and check if we wrapped */
141: panic("Address space ID wrapped; Temporarily fatal system error. Add more code here...\n"); /* Die */
142: }
143: if(hw_compare_and_store(currSID, nextSID, &curr_spaceID)) { /* Have we found a good one yet? */
144: debugLog2(0, nextSID, 0); /* Log mapping_space call */
145: return (nextSID); /* Yeah, return it... */
146: } /* save the new and exit if not, */
147: }
148: }
149:
150:
151: /*
152: * mapping_init();
153: * Do anything that needs to be done before the mapping system can be used.
154: * Hash table must be initialized before we call this.
155: *
156: * Calculate the SID increment. Currently we use size^(1/2) + size^(1/4) + 1;
157: */
158:
159: void mapping_init(void) {
160:
161: unsigned int tmp;
162:
163: __asm__ volatile("cntlzw %0, %1" : "=r" (tmp) : "r" (hash_table_size)); /* Get number of leading 0s */
164:
165: incrVSID = 1 << ((32 - tmp + 1) >> 1); /* Get ceiling of sqrt of table size */
166: incrVSID |= 1 << ((32 - tmp + 1) >> 2); /* Get ceiling of quadroot of table size */
167: incrVSID |= 1; /* Set bit and add 1 */
168: return;
169:
170: }
171:
172:
173: /*
174: * mapping_remove(space_t space, vm_offset_t va);
175: * Given a space ID and virtual address, this routine finds the mapping and removes if from
176: * both its PTEG hash list and the physical entry list. The mapping block will be added to
177: * the free list. If the free list threshold is reached, garbage collection will happen.
178: * We also kick back a return code to say whether or not we had one to remove.
179: *
180: * We have a strict ordering here: the mapping must be removed from the PTEG hash list before
181: * it can be removed from the physical entry list. This allows us to get by with only the PTEG
182: * hash lock at page fault time. The physical entry lock must be held while we remove the mapping
183: * from both lists. The PTEG lock is one of the lowest level locks. No PTE fault, interruptions,
184: * losing control, getting other locks, etc., are allowed when you hold it. You do, and you die.
185: * It's just that simple!
186: *
187: * When the phys_entry lock is held, the mappings chained to that one are guaranteed to stay around.
188: * However, a mapping's order on the PTEG hash chain is not. The interrupt handler uses the PTEG
189: * lock to control the hash cahin and may move the position of the mapping for MRU calculations.
190: *
191: * Note that mappings do not need to point to a physical entry. When they don't, it indicates
192: * the mapping is outside of physical memory and usually refers to a memory mapped device of
193: * some sort. Naturally, we can't lock what we don't have, so the phys entry lock and unlock
194: * routines return normally, but don't do anything.
195: */
196:
197: boolean_t mapping_remove(space_t space, vm_offset_t va) { /* Remove a single mapping for this VADDR
198: Returns TRUE if a mapping was found to remove */
199:
200: mapping *mp, *mpv;
201: spl_t s;
202:
203: debugLog2(1, va, space); /* start mapping_remove */
204: s=splhigh(); /* Don't bother me */
205:
206: mp = hw_lock_phys_vir(space, va); /* Lock the physical entry for this mapping */
207:
208: if(!mp) { /* Did we find one? */
209: splx(s); /* Restore the interrupt level */
210: debugLog2(2, 0, 0); /* end mapping_remove */
211: return FALSE; /* Didn't find any, return FALSE... */
212: }
213: if((unsigned int)mp&1) { /* Did we timeout? */
214: panic("mapping_remove: timeout locking physical entry\n"); /* Yeah, scream about it! */
215: splx(s); /* Restore the interrupt level */
216: return FALSE; /* Bad hair day, return FALSE... */
217: }
218:
219: mpv = hw_cpv(mp); /* Get virtual address of mapping */
220: if(mpv->pmap) { /* Check for a pmap */
221: #if DEBUG
222: if(hw_atomic_sub(&mpv->pmap->stats.resident_count, 1) < 0) panic("pmap resident count went negative\n");
223: #else
224: (void)hw_atomic_sub(&mpv->pmap->stats.resident_count, 1); /* Decrement the resident page count */
225: #endif
226: }
227:
228: hw_rem_map(mp); /* Remove the corresponding mapping */
229:
230: if(mpv->physent)hw_unlock_bit((unsigned int *)&mpv->physent->phys_link, PHYS_LOCK); /* Unlock physical entry associated with mapping */
231:
232: splx(s); /* Was there something you needed? */
233:
234: mapping_free(mpv); /* Add mapping to the free list */
235: debugLog2(2, 1, 0); /* end mapping_remove */
236: return TRUE; /* Tell them we did it */
237: }
238:
239: /*
240: * mapping_purge(struct phys_entry *pp) - release all mappings for this physent to the free list
241: *
242: * This guy releases any mappings that exist for a physical page.
243: * We get the lock on the phys_entry, and hold it through out this whole routine.
244: * That way, no one can change the queue out from underneath us. We keep fetching
245: * the physents mapping anchor until it is null, then we're done.
246: *
247: * For each mapping, we call the remove routine to remove it from the PTEG hash list and
248: * decriment the pmap's residency count. Then we release the mapping back to the free list.
249: *
250: */
251:
252: void mapping_purge(struct phys_entry *pp) { /* Remove all mappings for this physent */
253:
254: mapping *mp, *mpv;
255: spl_t s;
256:
257: s=splhigh(); /* Don't bother me */
258: debugLog2(3, pp->pte1, 0); /* start mapping_purge */
259:
260: if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) { /* Lock the physical entry */
261: panic("\nmapping_purge: Timeout attempting to lock physical entry at %08X: %08X %08X\n",
262: pp, pp->phys_link, pp->pte1); /* Complain about timeout */
263: }
264:
265: while(mp = (mapping *)((unsigned int)pp->phys_link & ~PHYS_FLAGS)) { /* Keep going so long as there's another */
266:
267: mpv = hw_cpv(mp); /* Get the virtual address */
268: if(mpv->pmap) { /* See if there is a pmap to worry about */
269: #if DEBUG
270: if(hw_atomic_sub(&mpv->pmap->stats.resident_count, 1) < 0) panic("pmap resident count went negative\n");
271: #else
272: (void)hw_atomic_sub(&mpv->pmap->stats.resident_count, 1); /* Decrement the resident page count */
273: #endif
274: }
275:
276: hw_rem_map(mp); /* Remove the mapping */
277: mapping_free(mpv); /* Add mapping to the free list */
278: }
279:
280: hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK); /* We're done, unlock the physical entry */
281:
282: debugLog2(4, pp->pte1, 0); /* end mapping_purge */
283: splx(s); /* Was there something you needed? */
284: return; /* Tell them we did it */
285: }
286:
287:
288: /*
289: * mapping_make(pmap, space, pp, va, spa, prot, attr) - map a virtual address to a real one
290: *
291: * This routine takes the given parameters, builds a mapping block, and queues it into the
292: * correct lists.
293: *
294: * The pmap and pp parameters can be null. This allows us to make a mapping that is not
295: * associated with any physical page or pmap. We may need this for certain I/O areas.
296: *
297: * If the pmap is null, we don't diddle with it, i.e., the residency counts.
298: * If the phys_entry address is null, we neither lock or chain into it.
299: */
300:
301: mapping *mapping_make(pmap_t pmap, space_t space, struct phys_entry *pp, vm_offset_t va, vm_offset_t pa, vm_prot_t prot, int attr) { /* Make an address mapping */
302:
303: register mapping *mp, *mpv;
304: spl_t s;
305:
306: debugLog2(5, va, pa); /* start mapping_purge */
307: mpv = mapping_alloc(); /* Get a spare mapping block */
308:
309: mpv->pmap = pmap; /* Initialize the pmap pointer */
310: mpv->physent = pp; /* Initialize the pointer to the physical entry */
311: mpv->PTEr = ((unsigned int)pa & ~(PAGE_SIZE - 1)) | attr<<3 | ppc_prot(prot); /* Build the real portion of the PTE */
312: mpv->PTEv = (((unsigned int)va >> 1) & 0x78000000) | (space << 7) | (((unsigned int)va >> 22) & 0x0000003F); /* Build the VSID */
313:
314: s=splhigh(); /* Don't bother from now on */
315:
316: mp = hw_cvp(mpv); /* Get the physical address of this */
317:
318: if(pp) { /* Is there a physical entry? */
319: if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) { /* Lock the physical entry */
320: panic("\nmapping_make: Timeout attempting to lock physical entry at %08X: %08X %08X\n",
321: pp, pp->phys_link, pp->pte1); /* Complain about timeout */
322: }
323:
324: mpv->next = (mapping *)((unsigned int)pp->phys_link & ~PHYS_FLAGS); /* Move the old anchor to the new mappings forward */
325: pp->phys_link = (mapping *)((unsigned int)mp | (unsigned int)pp->phys_link & PHYS_FLAGS); /* Point the anchor at us. Now we're on the list (keep the flags) */
326: }
327:
328: hw_add_map(mp, space, va); /* Stick it on the PTEG hash list */
329:
330: if(pmap) { /* If there is a pmap, adjust the residency count */
331: (void)hw_atomic_add(&mpv->pmap->stats.resident_count, 1); /* Increment the resident page count */
332: }
333:
334: if(pp)hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK); /* If we have one, unlock the physical entry */
335:
336: splx(s); /* Ok for interruptions now */
337: debugLog2(6, space, prot); /* end mapping_purge */
338: return mpv; /* Leave... */
339: }
340:
341:
342: /*
343: * mapping_remap(space_t space, vm_offset_t from, vm_offset_t to) - remap a physical address to a different virtual address
344: *
345: * This routine takes the given parameters, finds the mapping for the "from" address
346: * and removes it. Then it modifies the virtual address and adds it back.
347: *
348: * It returns failure if the "from" address is not mapped.
349: */
350:
351: int mapping_remap(space_t space, vm_offset_t from, vm_offset_t to) { /* Remap an address mapping */
352:
353: register mapping *mp, *mpv;
354: spl_t s;
355:
356: s=splhigh(); /* Don't bother from now on */
357:
358: mp = hw_lock_phys_vir(space, from); /* Lock the physical entry for this mapping */
359: debugLog2(7, from, to); /* start remap */
360: if(!mp) { /* Did we find one? */
361: splx(s); /* Restore the interrupt level */
362: return FALSE; /* Didn't find source, return FALSE... */
363: }
364: if((unsigned int)mp&1) { /* Did we timeout? */
365: panic("mapping_remap: timeout locking physical entry\n"); /* Yeah, scream about it! */
366: splx(s); /* Restore the interrupt level */
367: return FALSE; /* Bad hair day, return FALSE... */
368: }
369:
370: hw_rem_map(mp); /* Remove from the old address. Removes from both PTEG and physent lists */
371:
372: mpv = hw_cpv(mp); /* Convert to virtual address */
373:
374: mpv->PTEv = (((unsigned int)to >> 1) & 0x78000000) |
375: (space << 7) | (((unsigned int)to >> 22) & 0x0000003F); /* Rebuild the VSID */
376:
377: if(mpv->physent) { /* Is there a physical entry? */
378: mpv->next = (mapping *)((unsigned int)mpv->physent->phys_link & ~PHYS_FLAGS); /* Move the old anchor to the new mappings forward */
379: mpv->physent->phys_link = (mapping *)((unsigned int)mp | ((unsigned int)mpv->physent->phys_link & PHYS_FLAGS)); /* Point the anchor at us. Now we're back on the list (keep the flags) */
380: }
381:
382: hw_add_map(mp, space, to); /* Map it to the new one */
383:
384: if(mp->physent)hw_unlock_bit((unsigned int *)&mpv->physent->phys_link, PHYS_LOCK); /* Unlock physical entry associated with mapping */
385:
386: debugLog2(8, space, 0); /* end remap */
387: splx(s); /* Ok for interruptions now */
388: return TRUE; /* Leave... */
389: }
390:
391:
392: /*
393: * void mapping_protect(phys_entry *pp, vm_prot_t prot, boolean_t locked) - change the protection of a physical page
394: *
395: * This routine takes a physical entry and runs through all mappings attached to it and changes
396: * the protection. If there are PTEs associated with the mappings, they will be invalidated before
397: * the protection is changed. We don't try to save the PTE. We won't worry about the LRU calculations
398: * either (I don't think, maybe I'll change my mind later). There is no limitation on changes, e.g.,
399: * higher to lower, lower to higher.
400: *
401: * If locked is true, the physent is already locked and should not be unlocked at exit.
402: *
403: * Interruptions should be disabled at entry.
404: */
405:
406: void mapping_protect(struct phys_entry *pp, vm_prot_t prot, boolean_t locked) { /* Change protection of all mappings to page */
407:
408: debugLog2(9, pp->pte1, prot); /* end remap */
409: if(!locked) { /* Do we need to lock the physent? */
410: if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) { /* Lock the physical entry */
411: panic("\nmapping_protect: Timeout attempting to lock physical entry at %08X: %08X %08X\n",
412: pp, pp->phys_link, pp->pte1); /* Complain about timeout */
413: }
414: }
415:
416: hw_prot(pp, ppc_prot(prot)); /* Go set the protection on this physical page */
417:
418: if(!locked) hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK); /* We're done, unlock the physical entry */
419: debugLog2(10, pp->pte1, 0); /* end remap */
420:
421: return; /* Leave... */
422: }
423:
424: /*
425: * mapping_phys_attr(struct phys_entry *pp, vm_prot_t prot, unsigned int wimg) Sets the default physical page attributes
426: *
427: * This routine takes a physical entry and sets the physical attributes. There can be no mappings
428: * associated with this page when we do it.
429: */
430:
431: void mapping_phys_attr(struct phys_entry *pp, vm_prot_t prot, unsigned int wimg) { /* Sets the default physical page attributes */
432:
433: debugLog2(11, pp->pte1, prot); /* end remap */
434:
435: if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) { /* Lock the physical entry */
436: panic("\nmapping_phys_attr: Timeout attempting to lock physical entry at %08X: %08X %08X\n",
437: pp, pp->phys_link, pp->pte1); /* Complain about timeout */
438: }
439:
440: // if(pp->phys_link) panic("\nmapping_phys_attr: attempt to change default attributes when mappings exist!\n");
441:
442: hw_phys_attr(pp, ppc_prot(prot), wimg); /* Go set the default WIMG and protection */
443:
444: hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK); /* We're done, unlock the physical entry */
445: debugLog2(12, pp->pte1, wimg); /* end remap */
446:
447: return; /* Leave... */
448: }
449:
450: /*
451: * void mapping_invall(phys_entry *pp) - invalidates all ptes associated with a page
452: *
453: * This routine takes a physical entry and runs through all mappings attached to it and invalidates
454: * any PTEs it finds.
455: *
456: * Interruptions must be disabled and the physical entry locked at entry.
457: */
458:
459: void mapping_invall(struct phys_entry *pp) { /* Clear all PTEs pointing to a physical page */
460:
461: hw_inv_all(pp); /* Go set the change bit of a physical page */
462:
463: return; /* Leave... */
464: }
465:
466:
467: /*
468: * void mapping_clr_mod(phys_entry *pp) - clears the change bit of a physical page
469: *
470: * This routine takes a physical entry and runs through all mappings attached to it and turns
471: * off the change bit. If there are PTEs associated with the mappings, they will be invalidated before
472: * the change bit is changed. We don't try to save the PTE. We won't worry about the LRU calculations
473: * either (I don't think, maybe I'll change my mind later).
474: *
475: * Interruptions must be disabled and the physical entry locked at entry.
476: */
477:
478: void mapping_clr_mod(struct phys_entry *pp) { /* Clears the change bit of a physical page */
479:
480: hw_clr_mod(pp); /* Go clear the change bit of a physical page */
481: return; /* Leave... */
482: }
483:
484:
485: /*
486: * void mapping_set_mod(phys_entry *pp) - set the change bit of a physical page
487: *
488: * This routine takes a physical entry and runs through all mappings attached to it and turns
489: * on the change bit. If there are PTEs associated with the mappings, they will be invalidated before
490: * the change bit is changed. We don't try to save the PTE. We won't worry about the LRU calculations
491: * either (I don't think, maybe I'll change my mind later).
492: *
493: * Interruptions must be disabled and the physical entry locked at entry.
494: */
495:
496: void mapping_set_mod(struct phys_entry *pp) { /* Sets the change bit of a physical page */
497:
498: hw_set_mod(pp); /* Go set the change bit of a physical page */
499: return; /* Leave... */
500: }
501:
502:
503: /*
504: * void mapping_clr_ref(struct phys_entry *pp) - clears the reference bit of a physical page
505: *
506: * This routine takes a physical entry and runs through all mappings attached to it and turns
507: * off the reference bit. If there are PTEs associated with the mappings, they will be invalidated before
508: * the reference bit is changed. We don't try to save the PTE. We won't worry about the LRU calculations
509: * either (I don't think, maybe I'll change my mind later).
510: *
511: * Interruptions must be disabled at entry.
512: */
513:
514: void mapping_clr_ref(struct phys_entry *pp) { /* Clears the reference bit of a physical page */
515:
516: mapping *mp;
517:
518: debugLog2(13, pp->pte1, 0); /* end remap */
519: if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) { /* Lock the physical entry for this mapping */
520: panic("Lock timeout getting lock on physical entry\n"); /* Just die... */
521: }
522: hw_clr_ref(pp); /* Go clear the reference bit of a physical page */
523: hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK); /* Unlock physical entry */
524: debugLog2(14, pp->pte1, 0); /* end remap */
525: return; /* Leave... */
526: }
527:
528:
529: /*
530: * void mapping_set_ref(phys_entry *pp) - set the reference bit of a physical page
531: *
532: * This routine takes a physical entry and runs through all mappings attached to it and turns
533: * on the reference bit. If there are PTEs associated with the mappings, they will be invalidated before
534: * the reference bit is changed. We don't try to save the PTE. We won't worry about the LRU calculations
535: * either (I don't think, maybe I'll change my mind later).
536: *
537: * Interruptions must be disabled and the physical entry locked at entry.
538: */
539:
540: void mapping_set_ref(struct phys_entry *pp) { /* Sets the reference bit of a physical page */
541:
542: hw_set_ref(pp); /* Go set the reference bit of a physical page */
543: return; /* Leave... */
544: }
545:
546:
547: /*
548: * void mapping_tst_mod(phys_entry *pp) - test the change bit of a physical page
549: *
550: * This routine takes a physical entry and runs through all mappings attached to it and tests
551: * the changed bit. If there are PTEs associated with the mappings, they will be invalidated before
552: * the changed bit is tested. We don't try to save the PTE. We won't worry about the LRU calculations
553: * either (I don't think, maybe I'll change my mind later).
554: *
555: * Interruptions must be disabled and the physical entry locked at entry.
556: */
557:
558: boolean_t mapping_tst_mod(struct phys_entry *pp) { /* Tests the change bit of a physical page */
559:
560: return(hw_tst_mod(pp)); /* Go test the change bit of a physical page */
561: }
562:
563:
564: /*
565: * void mapping_tst_ref(phys_entry *pp) - tests the reference bit of a physical page
566: *
567: * This routine takes a physical entry and runs through all mappings attached to it and tests
568: * the reference bit. If there are PTEs associated with the mappings, they will be invalidated before
569: * the reference bit is changed. We don't try to save the PTE. We won't worry about the LRU calculations
570: * either (I don't think, maybe I'll change my mind later).
571: *
572: * Interruptions must be disabled and the physical entry locked at entry.
573: */
574:
575: boolean_t mapping_tst_ref(struct phys_entry *pp) { /* Tests the reference bit of a physical page */
576:
577: return(hw_tst_ref(pp)); /* Go test the reference bit of a physical page */
578: }
579:
580:
581: /*
582: * void mapping_phys_init(physent, wimg) - fills in the default processor dependent areas of the phys ent
583: *
584: * Currently, this sets the default word 1 of the PTE. The only bits set are the WIMG bits
585: */
586:
587: void mapping_phys_init(struct phys_entry *pp, unsigned int pa, unsigned int wimg) { /* Initializes hw specific storage attributes */
588:
589: pp->pte1 = (pa & -PAGE_SIZE) | ((wimg << 3) & 0x00000078); /* Set the WIMG and phys addr in the default PTE1 */
590:
591: return; /* Leave... */
592: }
593:
594:
595: /*
596: * mapping_adjust(void) - Releases free mapping blocks and/or allocates new ones
597: *
598: * This routine frees any mapping blocks queued to mapCtl.mapcrel. It also checks
599: * the number of free mappings remaining, and if below a threshold, replenishes them.
600: * The list will be replenshed from mapCtl.mapcrel if there are enough. Otherwise,
601: * a new one is allocated.
602: *
603: * This routine allocates and/or memory and must be called from a safe place.
604: * Currently, vm_pageout_scan is the safest place. We insure that the
605: */
606:
607: thread_call_t mapping_adjust_call;
608: static thread_call_data_t mapping_adjust_call_data;
609:
610: void mapping_adjust(void) { /* Adjust free mappings */
611:
612: kern_return_t retr;
613: mappingblok *mb, *mbn;
614: spl_t s;
615: int allocsize, i;
616:
617: if(mapCtl.mapcmin <= MAPPERBLOK) { /* Do the first time only */
618: mapCtl.mapcmin = mem_size >> 12; /* Make sure we have enough for all of physical memory */
619: #if DEBUG
620: kprintf("mapping_adjust: minimum entries rqrd = %08X\n", mapCtl.mapcmin);
621: kprintf("mapping_adjust: free = %08X; in use = %08X; release = %08X\n",
622: mapCtl.mapcfree, mapCtl.mapcinuse, mapCtl.mapcreln);
623: #endif
624: }
625:
626: s = splhigh(); /* Don't bother from now on */
627: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */
628: panic("mapping_adjust - timeout getting control lock (1)\n"); /* Tell all and die */
629: }
630:
631: if (mapping_adjust_call == NULL) {
632: thread_call_setup(&mapping_adjust_call_data, mapping_adjust, NULL);
633: mapping_adjust_call = &mapping_adjust_call_data;
634: }
635:
636: while(1) { /* Keep going until we've got enough */
637:
638: allocsize = mapCtl.mapcmin - mapCtl.mapcfree; /* Figure out how much we need */
639: if(allocsize < 1) break; /* Leave if we have all we need */
640:
641: if((unsigned int)(mbn = mapCtl.mapcrel)) { /* Can we rescue a free one? */
642: mapCtl.mapcrel = mbn->nextblok; /* Dequeue it */
643: mapCtl.mapcreln--; /* Back off the count */
644: allocsize = MAPPERBLOK; /* Show we allocated one block */
645: }
646: else { /* No free ones, try to get it */
647:
648: allocsize = (allocsize + MAPPERBLOK - 1) / MAPPERBLOK; /* Get the number of pages we need */
649: if(allocsize > (mapCtl.mapcfree / 2)) allocsize = (mapCtl.mapcfree / 2); /* Don't try for anything that we can't comfortably map */
650:
651: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */
652: splx(s); /* Restore 'rupts */
653:
654: for(; allocsize > 0; allocsize >>= 1) { /* Try allocating in descending halves */
655: retr = kmem_alloc_wired(kernel_map, (vm_offset_t *)&mbn, PAGE_SIZE * allocsize); /* Find a virtual address to use */
656: if((retr != KERN_SUCCESS) && (allocsize == 1)) { /* Did we find any memory at all? */
657: panic("Whoops... Not a bit of wired memory left for anyone\n");
658: }
659: if(retr == KERN_SUCCESS) break; /* We got some memory, bail out... */
660: }
661:
662: allocsize = allocsize * MAPPERBLOK; /* Convert pages to number of maps allocated */
663: s = splhigh(); /* Don't bother from now on */
664: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */
665: panic("mapping_adjust - timeout getting control lock (2)\n"); /* Tell all and die */
666: }
667: }
668: for(; allocsize > 0; allocsize -= MAPPERBLOK) { /* Release one block at a time */
669: mapping_free_init((vm_offset_t)mbn, 0, 1); /* Initialize a non-permanent block */
670: mbn = (mappingblok *)((unsigned int)mbn + PAGE_SIZE); /* Point to the next slot */
671: }
672: }
673:
674: if(mapCtl.mapcholdoff) { /* Should we hold off this release? */
675: mapCtl.mapcrecurse = 0; /* We are done now */
676: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */
677: splx(s); /* Restore 'rupts */
678: return; /* Return... */
679: }
680:
681: mbn = mapCtl.mapcrel; /* Get first pending release block */
682: mapCtl.mapcrel = 0; /* Dequeue them */
683: mapCtl.mapcreln = 0; /* Set count to 0 */
684:
685: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */
686: splx(s); /* Restore 'rupts */
687:
688: while((unsigned int)mbn) { /* Toss 'em all */
689: mb = mbn->nextblok; /* Get the next */
690: kmem_free(kernel_map, (vm_offset_t) mbn, PAGE_SIZE); /* Release this mapping block */
691: mbn = mb; /* Chain to the next */
692: }
693:
694: __asm__ volatile("sync"); /* Make sure all is well */
695: mapCtl.mapcrecurse = 0; /* We are done now */
696: return;
697: }
698:
699: /*
700: * mapping_free(mapping *mp) - release a mapping to the free list
701: *
702: * This routine takes a mapping and adds it to the free list.
703: * If this mapping make the block non-empty, we queue it to the free block list.
704: * NOTE: we might want to queue it to the end to keep quelch the pathalogical
705: * case when we get a mapping and free it repeatedly causing the block to chain and unchain.
706: * If this release fills a block and we are above the threshold, we release the block
707: */
708:
709: void mapping_free(struct mapping *mp) { /* Release a mapping */
710:
711: mappingblok *mb, *mbn;
712: spl_t s;
713: unsigned int full, mindx;
714:
715: mindx = ((unsigned int)mp & (PAGE_SIZE - 1)) >> 5; /* Get index to mapping */
716: mb = (mappingblok *)((unsigned int)mp & -PAGE_SIZE); /* Point to the mapping block */
717:
718: s = splhigh(); /* Don't bother from now on */
719: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */
720: panic("mapping_free - timeout getting control lock\n"); /* Tell all and die */
721: }
722:
723: full = !(mb->mapblokfree[0] | mb->mapblokfree[1] | mb->mapblokfree[2] | mb->mapblokfree[3]); /* See if full now */
724: mb->mapblokfree[mindx >> 5] |= (0x80000000 >> (mindx & 31)); /* Flip on the free bit */
725:
726: if(full) { /* If it was full before this: */
727: mb->nextblok = mapCtl.mapcnext; /* Move head of list to us */
728: mapCtl.mapcnext = mb; /* Chain us to the head of the list */
729: }
730:
731: mapCtl.mapcfree++; /* Bump free count */
732: mapCtl.mapcinuse--; /* Decriment in use count */
733:
734: mapCtl.mapcfreec++; /* Count total calls */
735:
736: if(mapCtl.mapcfree > mapCtl.mapcmin) { /* Should we consider releasing this? */
737: if(((mb->mapblokfree[0] | 0x80000000) & mb->mapblokfree[1] & mb->mapblokfree[2] & mb->mapblokfree[3])
738: == 0xFFFFFFFF) { /* See if empty now */
739:
740: if(mapCtl.mapcnext == mb) { /* Are we first on the list? */
741: mapCtl.mapcnext = mb->nextblok; /* Unchain us */
742: if(!((unsigned int)mapCtl.mapcnext)) mapCtl.mapclast = 0; /* If last, remove last */
743: }
744: else { /* We're not first */
745: for(mbn = mapCtl.mapcnext; mbn != 0; mbn = mbn->nextblok) { /* Search for our block */
746: if(mbn->nextblok == mb) break; /* Is the next one our's? */
747: }
748: if(!mbn) panic("mapping_free: attempt to release mapping block (%08X) not on list\n", mp);
749: mbn->nextblok = mb->nextblok; /* Dequeue us */
750: if(mapCtl.mapclast == mb) mapCtl.mapclast = mbn; /* If last, make our predecessor last */
751: }
752:
753: if(mb->mapblokflags & mbPerm) { /* Is this permanently assigned? */
754: mb->nextblok = mapCtl.mapcnext; /* Move chain head to us */
755: mapCtl.mapcnext = mb; /* Chain us to the head */
756: if(!((unsigned int)mb->nextblok)) mapCtl.mapclast = mb; /* If last, make us so */
757: }
758: else {
759: mapCtl.mapcfree -= MAPPERBLOK; /* Remove the block from the free count */
760: mapCtl.mapcreln++; /* Count on release list */
761: mb->nextblok = mapCtl.mapcrel; /* Move pointer */
762: mapCtl.mapcrel = mb; /* Chain us in front */
763: }
764: }
765: }
766:
767: if(mapCtl.mapcreln > MAPFRTHRSH) { /* Do we have way too many releasable mappings? */
768: if(hw_compare_and_store(0, 1, &mapCtl.mapcrecurse)) { /* Make sure we aren't recursing */
769: thread_call_enter(mapping_adjust_call); /* Go toss some */
770: }
771: }
772: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */
773: splx(s); /* Restore 'rupts */
774:
775: return; /* Bye, dude... */
776: }
777:
778:
779: /*
780: * mapping_alloc(void) - obtain a mapping from the free list
781: *
782: * This routine takes a mapping off of the free list and returns it's address.
783: *
784: * We do this by finding a free entry in the first block and allocating it.
785: * If this allocation empties the block, we remove it from the free list.
786: * If this allocation drops the total number of free entries below a threshold,
787: * we allocate a new block.
788: *
789: */
790:
791: mapping *mapping_alloc(void) { /* Obtain a mapping */
792:
793: register mapping *mp;
794: mappingblok *mb, *mbn;
795: spl_t s;
796: int mindx;
797: kern_return_t retr;
798:
799: s = splhigh(); /* Don't bother from now on */
800: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */
801: panic("mapping_alloc - timeout getting control lock\n"); /* Tell all and die */
802: }
803:
804: if(!(mb = mapCtl.mapcnext)) { /* Get the first block entry */
805: panic("mapping_alloc - free mappings exhausted\n"); /* Whine and moan */
806: }
807:
808:
809: if(!(mindx = mapalc(mb))) { /* Allocate a slot */
810: panic("mapping_alloc - empty mapping block detected at %08X\n", mb); /* Not allowed to find none */
811: }
812:
813: if(mindx < 0) { /* Did we just take the last one */
814: mindx = -mindx; /* Make positive */
815: mapCtl.mapcnext = mb->nextblok; /* Remove us from the list */
816: if(!((unsigned int)mapCtl.mapcnext)) mapCtl.mapclast = 0; /* Removed the last one */
817: }
818:
819: mapCtl.mapcfree--; /* Decrement free count */
820: mapCtl.mapcinuse++; /* Bump in use count */
821:
822: mapCtl.mapcallocc++; /* Count total calls */
823:
824: /*
825: * Note: in the following code, we will attempt to rescue blocks only one at a time.
826: * Eventually, after a few more mapping_alloc calls, we will catch up. If there are none
827: * rescueable, we will kick the misc scan who will allocate some for us. We only do this
828: * if we haven't already done it.
829: * For early boot, we are set up to only rescue one block at a time. This is because we prime
830: * the release list with as much as we need until threads start.
831: */
832: if(mapCtl.mapcfree < mapCtl.mapcmin) { /* See if we need to replenish */
833: if(mbn = mapCtl.mapcrel) { /* Try to rescue a block from impending doom */
834: mapCtl.mapcrel = mbn->nextblok; /* Pop the queue */
835: mapCtl.mapcreln--; /* Back off the count */
836: mapping_free_init((vm_offset_t)mbn, 0, 1); /* Initialize a non-permanent block */
837: }
838: else { /* We need to replenish */
839: if(hw_compare_and_store(0, 1, &mapCtl.mapcrecurse)) { /* Make sure we aren't recursing */
840: thread_call_enter(mapping_adjust_call); /* Go allocate some more */
841: }
842: }
843: }
844:
845: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */
846: splx(s); /* Restore 'rupts */
847:
848: mp = &((mapping *)mb)[mindx]; /* Point to the allocated mapping */
849: __asm__ volatile("dcbz 0,%0" : : "r" (mp)); /* Clean it up */
850: return mp; /* Send it back... */
851: }
852:
853:
854: /*
855: * void mapping_free_init(mb, perm) - Adds a block of storage to the free mapping list
856: *
857: * The mapping block is a page size area on a page boundary. It contains 1 header and 127
858: * mappings. This call adds and initializes a block for use.
859: *
860: * The header contains a chain link, bit maps, a virtual to real translation mask, and
861: * some statistics. Bit maps map each slot on the page (bit 0 is not used because it
862: * corresponds to the header). The translation mask is the XOR of the virtual and real
863: * addresses (needless to say, the block must be wired).
864: *
865: * We handle these mappings the same way as saveareas: the block is only on the chain so
866: * long as there are free entries in it.
867: *
868: * Empty blocks are garbage collected when there are at least mapCtl.mapcmin pages worth of free
869: * mappings. Blocks marked PERM won't ever be released.
870: *
871: * If perm is negative, the mapping is initialized, but immediately queued to the mapCtl.mapcrel
872: * list. We do this only at start up time. This is done because we only allocate blocks
873: * in the pageout scan and it doesn't start up until after we run out of the initial mappings.
874: * Therefore, we need to preallocate a bunch, but we don't want them to be permanent. If we put
875: * them on the release queue, the allocate routine will rescue them. Then when the
876: * pageout scan starts, all extra ones will be released.
877: *
878: */
879:
880:
881: void mapping_free_init(vm_offset_t mbl, int perm, boolean_t locked) {
882: /* Set's start and end of a block of mappings
883: perm indicates if the block can be released
884: or goes straight to the release queue .
885: locked indicates if the lock is held already */
886:
887: mappingblok *mb;
888: spl_t s;
889: int i;
890: unsigned int raddr;
891:
892: mb = (mappingblok *)mbl; /* Start of area */
893:
894:
895: if(perm >= 0) { /* See if we need to initialize the block */
896: if(perm) {
897: raddr = (unsigned int)mbl; /* Perm means V=R */
898: mb->mapblokflags = mbPerm; /* Set perm */
899: }
900: else {
901: raddr = kvtophys(mbl); /* Get real address */
902: mb->mapblokflags = 0; /* Set not perm */
903: }
904:
905: mb->mapblokvrswap = raddr ^ (unsigned int)mbl; /* Form translation mask */
906:
907: mb->mapblokfree[0] = 0x7FFFFFFF; /* Set first 32 (minus 1) free */
908: mb->mapblokfree[1] = 0xFFFFFFFF; /* Set next 32 free */
909: mb->mapblokfree[2] = 0xFFFFFFFF; /* Set next 32 free */
910: mb->mapblokfree[3] = 0xFFFFFFFF; /* Set next 32 free */
911: }
912:
913: s = splhigh(); /* Don't bother from now on */
914: if(!locked) { /* Do we need the lock? */
915: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */
916: panic("mapping_free_init - timeout getting control lock\n"); /* Tell all and die */
917: }
918: }
919:
920: if(perm < 0) { /* Direct to release queue? */
921: mb->nextblok = mapCtl.mapcrel; /* Move forward pointer */
922: mapCtl.mapcrel = mb; /* Queue us on in */
923: mapCtl.mapcreln++; /* Count the free block */
924: }
925: else { /* Add to the free list */
926:
927: mb->nextblok = 0; /* We always add to the end */
928: mapCtl.mapcfree += MAPPERBLOK; /* Bump count */
929:
930: if(!((unsigned int)mapCtl.mapcnext)) { /* First entry on list? */
931: mapCtl.mapcnext = mapCtl.mapclast = mb; /* Chain to us */
932: }
933: else { /* We are not the first */
934: mapCtl.mapclast->nextblok = mb; /* Point the last to us */
935: mapCtl.mapclast = mb; /* We are now last */
936: }
937: }
938:
939: if(!locked) { /* Do we need to unlock? */
940: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */
941: }
942: splx(s); /* Restore 'rupts */
943: return; /* All done, leave... */
944: }
945:
946:
947: /*
948: * void mapping_prealloc(unsigned int) - Preallocates mapppings for large request
949: *
950: * No locks can be held, because we allocate memory here.
951: * This routine needs a corresponding mapping_relpre call to remove the
952: * hold off flag so that the adjust routine will free the extra mapping
953: * blocks on the release list. I don't like this, but I don't know
954: * how else to do this for now...
955: *
956: */
957:
958: void mapping_prealloc(unsigned int size) { /* Preallocates mapppings for large request */
959:
960: int nmapb, i;
961: kern_return_t retr;
962: mappingblok *mbn;
963: spl_t s;
964:
965: s = splhigh(); /* Don't bother from now on */
966: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */
967: panic("mapping_prealloc - timeout getting control lock\n"); /* Tell all and die */
968: }
969:
970: nmapb = (size >> 12) + mapCtl.mapcmin; /* Get number of entries needed for this and the minimum */
971:
972: mapCtl.mapcholdoff++; /* Bump the hold off count */
973:
974: if((nmapb = (nmapb - mapCtl.mapcfree)) <= 0) { /* Do we already have enough? */
975: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */
976: splx(s); /* Restore 'rupts */
977: return;
978: }
979:
980: nmapb = (nmapb + MAPPERBLOK - 1) / MAPPERBLOK; /* Get number of blocks to get */
981:
982: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */
983: splx(s); /* Restore 'rupts */
984:
985: for(i = 0; i < nmapb; i++) { /* Allocate 'em all */
986: retr = kmem_alloc_wired(kernel_map, (vm_offset_t *)&mbn, PAGE_SIZE); /* Find a virtual address to use */
987: if(retr != KERN_SUCCESS) { /* Did we get some memory? */
988: panic("Whoops... Not a bit of wired memory left for anyone\n");
989: }
990: mapping_free_init((vm_offset_t)mbn, -1, 0); /* Initialize on to the release queue */
991: }
992: }
993:
994: /*
995: * void mapping_relpre(void) - Releases preallocation release hold off
996: *
997: * This routine removes the
998: * hold off flag so that the adjust routine will free the extra mapping
999: * blocks on the release list. I don't like this, but I don't know
1000: * how else to do this for now...
1001: *
1002: */
1003:
1004: void mapping_relpre(void) { /* Releases release hold off */
1005:
1006: spl_t s;
1007:
1008: s = splhigh(); /* Don't bother from now on */
1009: if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */
1010: panic("mapping_relpre - timeout getting control lock\n"); /* Tell all and die */
1011: }
1012: if(--mapCtl.mapcholdoff < 0) { /* Back down the hold off count */
1013: panic("mapping_relpre: hold-off count went negative\n");
1014: }
1015:
1016: hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */
1017: splx(s); /* Restore 'rupts */
1018: }
1019:
1020: /*
1021: * void mapping_free_prime(void) - Primes the mapping block release list
1022: *
1023: * See mapping_free_init.
1024: * No locks can be held, because we allocate memory here.
1025: * One processor running only.
1026: *
1027: */
1028:
1029: void mapping_free_prime(void) { /* Primes the mapping block release list */
1030:
1031: int nmapb, i;
1032: kern_return_t retr;
1033: mappingblok *mbn;
1034:
1035: nmapb = (mapCtl.mapcfree + mapCtl.mapcinuse + MAPPERBLOK - 1) / MAPPERBLOK; /* Get permanent allocation */
1036: nmapb = nmapb * 4; /* Get 4 times our initial allocation */
1037:
1038: #if DEBUG
1039: kprintf("mapping_free_prime: free = %08X; in use = %08X; priming = %08X\n",
1040: mapCtl.mapcfree, mapCtl.mapcinuse, nmapb);
1041: #endif
1042:
1043: for(i = 0; i < nmapb; i++) { /* Allocate 'em all */
1044: retr = kmem_alloc_wired(kernel_map, (vm_offset_t *)&mbn, PAGE_SIZE); /* Find a virtual address to use */
1045: if(retr != KERN_SUCCESS) { /* Did we get some memory? */
1046: panic("Whoops... Not a bit of wired memory left for anyone\n");
1047: }
1048: mapping_free_init((vm_offset_t)mbn, -1, 0); /* Initialize onto release queue */
1049: }
1050: }
1051:
1052: /*
1053: * vm_offset_t mapping_p2v(space_t space, phys_entry *pp) - Finds first virtual mapping of a physical page in a space
1054: *
1055: * Gets a lock on the physical entry. Then it searches the list of attached mappings for one with
1056: * the same space. If it finds it, it returns the virtual address.
1057: */
1058:
1059: vm_offset_t mapping_p2v(space_t space, struct phys_entry *pp) { /* Finds first virtual mapping of a physical page in a space */
1060:
1061: spl_t s;
1062: register mapping *mp, *mpv;
1063: vm_offset_t va;
1064:
1065: if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) { /* Try to get the lock on the physical entry */
1066: splx(s); /* Restore 'rupts */
1067: panic("mapping_p2v: timeout getting lock on physent\n"); /* Arrrgghhhh! */
1068: return(0); /* Should die before here */
1069: }
1070:
1071: va = 0; /* Assume failure */
1072:
1073: for(mpv = hw_cpv(pp->phys_link); mpv; mp = hw_cpv(mp->next)) { /* Scan 'em all */
1074:
1075: if(!(((mpv->PTEv >> 7) & 0x000FFFFF) == space)) continue; /* Skip all the rest if this is not the right space... */
1076:
1077: va = ((((unsigned int)mpv->PTEhash & -64) << 5) ^ (space << 12)) & 0x003FF000; /* Backward hash to the wrapped VADDR */
1078: va = va | ((mpv->PTEv << 8) & 0xF0000000); /* Move in the segment number */
1079: va = va | ((mpv->PTEv << 22) & 0x0FC00000); /* Add in the API for the top of the address */
1080: break; /* We're done now, pass virtual address back */
1081: }
1082:
1083: hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK); /* Unlock the physical entry */
1084: splx(s); /* Restore 'rupts */
1085: return(va); /* Return the result or 0... */
1086: }
1087:
1088: /*
1089: * kvtophys(addr)
1090: *
1091: * Convert a kernel virtual address to a physical address
1092: */
1093: vm_offset_t kvtophys(vm_offset_t va) {
1094:
1095: register mapping *mp, *mpv;
1096: register vm_offset_t pa;
1097: spl_t s;
1098:
1099: s=splhigh(); /* Don't bother from now on */
1100: mp = hw_lock_phys_vir(PPC_SID_KERNEL, va); /* Find mapping and lock the physical entry for this mapping */
1101:
1102: if((unsigned int)mp&1) { /* Did the lock on the phys entry time out? */
1103: splx(s); /* Restore 'rupts */
1104: panic("kvtophys: timeout obtaining lock on physical entry (vaddr=%08X)\n", va); /* Scream bloody murder! */
1105: return 0;
1106: }
1107:
1108: if(!mp) { /* If it was not found, or no physical entry */
1109: splx(s); /* Restore 'rupts */
1110: return 0; /* Return 0 */
1111: }
1112:
1113: mpv = hw_cpv(mp); /* Convert to virtual addressing */
1114:
1115: if(!mpv->physent) { /* Was there a physical entry? */
1116: pa = (vm_offset_t)((mpv->PTEr & -PAGE_SIZE) | ((unsigned int)va & (PAGE_SIZE-1))); /* Get physical address from physent */
1117: }
1118: else {
1119: pa = (vm_offset_t)((mpv->physent->pte1 & -PAGE_SIZE) | ((unsigned int)va & (PAGE_SIZE-1))); /* Get physical address from physent */
1120: hw_unlock_bit((unsigned int *)&mpv->physent->phys_link, PHYS_LOCK); /* Unlock the physical entry */
1121: }
1122:
1123: splx(s); /* Restore 'rupts */
1124: return pa; /* Return the physical address... */
1125: }
1126:
1127: /*
1128: * phystokv(addr)
1129: *
1130: * Convert a physical address to a kernel virtual address if
1131: * there is a mapping, otherwise return NULL
1132: */
1133:
1134: vm_offset_t phystokv(vm_offset_t pa) {
1135:
1136: struct phys_entry *pp;
1137: vm_offset_t va;
1138:
1139: pp = pmap_find_physentry(pa); /* Find the physical entry */
1140: if (PHYS_NULL == pp) {
1141: return (vm_offset_t)NULL; /* If none, return null */
1142: }
1143: if(!(va=mapping_p2v(PPC_SID_KERNEL, pp))) {
1144: return 0; /* Can't find it, return 0... */
1145: }
1146: return (va | (pa & (PAGE_SIZE-1))); /* Build and return VADDR... */
1147:
1148: }
1149:
1150: /*
1151: * Enters translations into the autogen maps.
1152: *
1153: * Not implemented yet, just stubbed out...
1154: */
1155:
1156: boolean_t autogen_map(space_t space, vm_offset_t va, vm_offset_t spa, vm_offset_t epa, vm_prot_t prot, int attr) { /* Build an autogen area */
1157:
1158: return(0); /* Just return false for now */
1159: }
1160:
1161:
1162: /*
1163: * Dumps out the mapping stuff associated with a virtual address
1164: */
1165: void dumpaddr(space_t space, vm_offset_t va) {
1166:
1167: mapping *mp, *mpv;
1168: vm_offset_t pa;
1169: spl_t s;
1170:
1171: s=splhigh(); /* Don't bother me */
1172:
1173: mp = hw_lock_phys_vir(space, va); /* Lock the physical entry for this mapping */
1174: if(!mp) { /* Did we find one? */
1175: splx(s); /* Restore the interrupt level */
1176: printf("dumpaddr: virtual address (%08X) not mapped\n", va);
1177: return; /* Didn't find any, return FALSE... */
1178: }
1179: if((unsigned int)mp&1) { /* Did we timeout? */
1180: panic("dumpaddr: timeout locking physical entry for virtual address (%08X)\n", va); /* Yeah, scream about it! */
1181: splx(s); /* Restore the interrupt level */
1182: return; /* Bad hair day, return FALSE... */
1183: }
1184: printf("dumpaddr: space=%08X; vaddr=%08X\n", space, va); /* Say what address were dumping */
1185: mpv = hw_cpv(mp); /* Get virtual address of mapping */
1186: dumpmapping(mpv);
1187: if(mpv->physent) {
1188: dumppca(mpv);
1189: hw_unlock_bit((unsigned int *)&mpv->physent->phys_link, PHYS_LOCK); /* Unlock physical entry associated with mapping */
1190: }
1191: splx(s); /* Was there something you needed? */
1192: return; /* Tell them we did it */
1193: }
1194:
1195:
1196:
1197: /*
1198: * Prints out a mapping control block
1199: *
1200: */
1201:
1202: void dumpmapping(struct mapping *mp) { /* Dump out a mapping */
1203:
1204: printf("Dump of mapping block: %08X\n", mp); /* Header */
1205: printf(" next: %08X\n", mp->next);
1206: printf(" hashnext: %08X\n", mp->hashnext);
1207: printf(" PTEhash: %08X\n", mp->PTEhash);
1208: printf(" PTEent: %08X\n", mp->PTEent);
1209: printf(" physent: %08X\n", mp->physent);
1210: printf(" PTEv: %08X\n", mp->PTEv);
1211: printf(" PTEr: %08X\n", mp->PTEr);
1212: printf(" pmap: %08X\n", mp->pmap);
1213:
1214: if(mp->physent) { /* Print physent if it exists */
1215: printf("Associated physical entry: %08X %08X\n", mp->physent->phys_link, mp->physent->pte1);
1216: }
1217: else {
1218: printf("Associated physical entry: none\n");
1219: }
1220:
1221: dumppca(mp); /* Dump out the PCA information */
1222:
1223: return;
1224: }
1225:
1226: /*
1227: * Prints out a PTEG control area
1228: *
1229: */
1230:
1231: void dumppca(struct mapping *mp) { /* PCA */
1232:
1233: PCA *pca;
1234: unsigned int *pteg;
1235:
1236: pca = (PCA *)((unsigned int)mp->PTEhash&-64); /* Back up to the start of the PCA */
1237: pteg=(unsigned int *)((unsigned int)pca-(((hash_table_base&0x0000FFFF)+1)<<16));
1238: printf(" Dump of PCA: %08X\n", pca); /* Header */
1239: printf(" PCAlock: %08X\n", pca->PCAlock);
1240: printf(" PCAallo: %08X\n", pca->flgs.PCAallo);
1241: printf(" PCAhash: %08X %08X %08X %08X\n", pca->PCAhash[0], pca->PCAhash[1], pca->PCAhash[2], pca->PCAhash[3]);
1242: printf(" %08X %08X %08X %08X\n", pca->PCAhash[4], pca->PCAhash[5], pca->PCAhash[6], pca->PCAhash[7]);
1243: printf("Dump of PTEG: %08X\n", pteg); /* Header */
1244: printf(" %08X %08X %08X %08X\n", pteg[0], pteg[1], pteg[2], pteg[3]);
1245: printf(" %08X %08X %08X %08X\n", pteg[4], pteg[5], pteg[6], pteg[7]);
1246: printf(" %08X %08X %08X %08X\n", pteg[8], pteg[9], pteg[10], pteg[11]);
1247: printf(" %08X %08X %08X %08X\n", pteg[12], pteg[13], pteg[14], pteg[15]);
1248: return;
1249: }
1250:
1251: /*
1252: * Dumps starting with a physical entry
1253: */
1254:
1255: void dumpphys(struct phys_entry *pp) { /* Dump from physent */
1256:
1257: mapping *mp;
1258: PCA *pca;
1259: unsigned int *pteg;
1260:
1261: printf("Dump from physical entry %08X: %08X %08X\n", pp, pp->phys_link, pp->pte1);
1262: mp = hw_cpv(pp->phys_link);
1263: while(mp) {
1264: dumpmapping(mp);
1265: dumppca(mp);
1266: mp = hw_cpv(mp->next);
1267: }
1268:
1269: return;
1270: }
1271:
1272: /*
1273: * void ignore_zero_fault(boolean_t) - Sets up to ignore or honor any fault on
1274: * page 0 access for the current thread.
1275: *
1276: * If parameter is TRUE, faults are ignored
1277: * If parameter is FALSE, faults are honored
1278: *
1279: */
1280:
1281: void ignore_zero_fault(boolean_t type) { /* Sets up to ignore or honor any fault on page 0 access for the current thread */
1282:
1283: if(type) current_act()->mact.specFlags |= ignoreZeroFault; /* Ignore faults on page 0 */
1284: else current_act()->mact.specFlags &= ~ignoreZeroFault; /* Honor faults on page 0 */
1285:
1286: return; /* Return the result or 0... */
1287: }
1288:
1289:
1290:
1291:
1292:
1293:
1294:
1295:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.