]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
2d21ac55 | 2 | * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
8f6c56a5 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
8f6c56a5 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | /* | |
29 | * This file is used to maintain the virtual to real mappings for a PowerPC machine. | |
30 | * The code herein is primarily used to bridge between the pmap layer and the hardware layer. | |
31 | * Currently, some of the function of this module is contained within pmap.c. We may want to move | |
32 | * all of this into it (or most anyway) for the sake of performance. We shall see as we write it. | |
33 | * | |
34 | * We also depend upon the structure of the phys_entry control block. We do put some processor | |
35 | * specific stuff in there. | |
36 | * | |
37 | */ | |
38 | ||
1c79356b A |
39 | #include <debug.h> |
40 | #include <mach_kgdb.h> | |
41 | #include <mach_vm_debug.h> | |
42 | #include <db_machine_commands.h> | |
43 | ||
91447636 | 44 | #include <mach/mach_types.h> |
1c79356b A |
45 | #include <mach/vm_attributes.h> |
46 | #include <mach/vm_param.h> | |
91447636 A |
47 | |
48 | #include <kern/kern_types.h> | |
49 | #include <kern/thread.h> | |
50 | #include <kern/spl.h> | |
51 | #include <kern/misc_protos.h> | |
52 | ||
55e303ae | 53 | #include <vm/vm_fault.h> |
1c79356b A |
54 | #include <vm/vm_kern.h> |
55 | #include <vm/vm_map.h> | |
56 | #include <vm/vm_page.h> | |
91447636 | 57 | #include <vm/pmap.h> |
1c79356b | 58 | |
55e303ae | 59 | #include <ppc/exception.h> |
1c79356b A |
60 | #include <ppc/misc_protos.h> |
61 | #include <ppc/proc_reg.h> | |
1c79356b | 62 | #include <ppc/pmap.h> |
1c79356b | 63 | #include <ppc/mem.h> |
1c79356b A |
64 | #include <ppc/new_screen.h> |
65 | #include <ppc/Firmware.h> | |
66 | #include <ppc/mappings.h> | |
67 | #include <ddb/db_output.h> | |
68 | ||
55e303ae | 69 | #include <console/video_console.h> /* (TEST/DEBUG) */ |
1c79356b A |
70 | |
71 | #define PERFTIMES 0 | |
72 | ||
1c79356b A |
73 | vm_map_t mapping_map = VM_MAP_NULL; |
74 | ||
55e303ae | 75 | unsigned int incrVSID = 0; /* VSID increment value */ |
1c79356b | 76 | unsigned int mappingdeb0 = 0; |
55e303ae A |
77 | unsigned int mappingdeb1 = 0; |
78 | int ppc_max_adrsp; /* Maximum address spaces */ | |
79 | ||
80 | addr64_t *mapdebug; /* (BRINGUP) */ | |
81 | extern unsigned int DebugWork; /* (BRINGUP) */ | |
82 | ||
55e303ae A |
83 | void mapping_verify(void); |
84 | void mapping_phys_unused(ppnum_t pa); | |
85 | ||
2d21ac55 A |
86 | int nx_enabled = 1; /* enable no-execute protection */ |
87 | int allow_data_exec = VM_ABI_32; /* 32-bit apps may execute data by default, 64-bit apps may not */ | |
88 | int allow_stack_exec = VM_ABI_32; /* 32-bit apps may execute from the stack by default, 64-bit apps may not */ | |
0c530ab8 | 89 | |
1c79356b | 90 | /* |
91447636 A |
91 | * ppc_prot translates Mach's representation of protections to that of the PPC hardware. |
92 | * For Virtual Machines (VMM), we also provide translation entries where the output is | |
93 | * the same as the input, allowing direct specification of PPC protections. Mach's | |
94 | * representations are always in the range 0..7, so they always fall into the first | |
95 | * 8 table entries; direct translations are placed in the range 8..16, so they fall into | |
96 | * the second half of the table. | |
97 | * | |
1c79356b | 98 | */ |
91447636 | 99 | |
0c530ab8 | 100 | unsigned char ppc_prot[16] = { 4, 7, 6, 6, 3, 3, 2, 2, /* Mach -> PPC translations */ |
91447636 | 101 | 0, 1, 2, 3, 4, 5, 6, 7 }; /* VMM direct translations */ |
1c79356b | 102 | |
0c530ab8 A |
103 | |
104 | ||
105 | vm_prot_t getProtPPC(int key, boolean_t disable_NX) { | |
106 | vm_prot_t prot; | |
107 | ||
108 | prot = ppc_prot[key & 0xF]; | |
109 | ||
110 | if (key <= 7 && disable_NX == TRUE) | |
111 | prot &= ~mpN; | |
112 | ||
113 | return (prot); | |
114 | } | |
115 | ||
116 | ||
1c79356b A |
117 | /* |
118 | * About PPC VSID generation: | |
119 | * | |
120 | * This function is called to generate an address space ID. This space ID must be unique within | |
121 | * the system. For the PowerPC, it is used to build the VSID. We build a VSID in the following | |
122 | * way: space ID << 4 | segment. Since a VSID is 24 bits, and out of that, we reserve the last | |
123 | * 4, so, we can have 2^20 (2M) unique IDs. Each pmap has a unique space ID, so we should be able | |
124 | * to have 2M pmaps at a time, which we couldn't, we'd run out of memory way before then. The | |
125 | * problem is that only a certain number of pmaps are kept in a free list and if that is full, | |
126 | * they are release. This causes us to lose track of what space IDs are free to be reused. | |
127 | * We can do 4 things: 1) not worry about it, 2) keep all free pmaps, 3) rebuild all mappings | |
128 | * when the space ID wraps, or 4) scan the list of pmaps and find a free one. | |
129 | * | |
130 | * Yet another consideration is the hardware use of the VSID. It is used as part of the hash | |
131 | * calculation for virtual address lookup. An improperly chosen value could potentially cause | |
132 | * too many hashes to hit the same bucket, causing PTEG overflows. The actual hash function | |
133 | * is (page index XOR vsid) mod number of ptegs. For a 32MB machine, using the suggested | |
134 | * hash table size, there are 2^12 (8192) PTEGs. Remember, though, that the bottom 4 bits | |
135 | * are reserved for the segment number, which means that we really have 2^(12-4) 512 space IDs | |
136 | * before we start hashing to the same buckets with the same vaddrs. Also, within a space ID, | |
137 | * every 8192 pages (32MB) within a segment will hash to the same bucket. That's 8 collisions | |
138 | * per segment. So, a scan of every page for 256MB would fill 32 PTEGs completely, but | |
139 | * with no overflow. I don't think that this is a problem. | |
140 | * | |
141 | * There may be a problem with the space ID, though. A new space ID is generate (mainly) | |
142 | * whenever there is a fork. There shouldn't really be any problem because (for a 32MB | |
143 | * machine) we can have 512 pmaps and still not have hash collisions for the same address. | |
144 | * The potential problem, though, is if we get long-term pmaps that have space IDs that are | |
145 | * the same modulo 512. We can reduce this problem by having the segment number be bits | |
146 | * 0-3 of the space ID rather than 20-23. Doing this means that, in effect, corresponding | |
147 | * vaddrs in different segments hash to the same PTEG. While this is somewhat of a problem, | |
148 | * I don't think that it is as signifigant as the other, so, I'll make the space ID | |
149 | * with segment first. | |
150 | * | |
151 | * The final, and biggest problem is the wrap, which will happen every 2^20 space IDs. | |
152 | * While this is a problem that should only happen in periods counted in weeks, it can and | |
153 | * will happen. This is assuming a monotonically increasing space ID. If we were to search | |
154 | * for an inactive space ID, there could not be a wrap until there was 2^20 concurrent space IDs. | |
155 | * That's pretty unlikely to happen. There couldn't be enough storage to support a million tasks. | |
156 | * | |
157 | * So, what we do is to keep all active pmaps in a chain (anchored from kernel_pmap and | |
158 | * locked by free_pmap_lock) that is sorted in VSID sequence order. | |
159 | * | |
160 | * Whenever we need a VSID, we walk the list looking for the next in the sequence from | |
161 | * the last that was freed. The we allocate that. | |
162 | * | |
163 | * NOTE: We must be called with interruptions off and free_pmap_lock held. | |
164 | * | |
165 | */ | |
166 | ||
167 | /* | |
168 | * mapping_init(); | |
169 | * Do anything that needs to be done before the mapping system can be used. | |
170 | * Hash table must be initialized before we call this. | |
171 | * | |
172 | * Calculate the SID increment. Currently we use size^(1/2) + size^(1/4) + 1; | |
173 | */ | |
174 | ||
175 | void mapping_init(void) { | |
176 | ||
55e303ae | 177 | unsigned int tmp, maxeff, rwidth; |
d7e50217 | 178 | |
55e303ae | 179 | ppc_max_adrsp = maxAdrSp; /* Set maximum address spaces */ |
1c79356b | 180 | |
55e303ae | 181 | maxeff = 32; /* Assume 32-bit */ |
91447636 | 182 | if(PerProcTable[0].ppe_vaddr->pf.Available & pf64Bit) maxeff = 64; /* Is this a 64-bit machine? */ |
d7e50217 | 183 | |
91447636 | 184 | rwidth = PerProcTable[0].ppe_vaddr->pf.pfMaxVAddr - maxAdrSpb; /* Reduce address width by width of address space ID */ |
55e303ae | 185 | if(rwidth > maxeff) rwidth = maxeff; /* If we still have more virtual than effective, clamp at effective */ |
de355530 | 186 | |
55e303ae | 187 | vm_max_address = 0xFFFFFFFFFFFFFFFFULL >> (64 - rwidth); /* Get maximum effective address supported */ |
91447636 | 188 | vm_max_physical = 0xFFFFFFFFFFFFFFFFULL >> (64 - PerProcTable[0].ppe_vaddr->pf.pfMaxPAddr); /* Get maximum physical address supported */ |
de355530 | 189 | |
91447636 | 190 | if(PerProcTable[0].ppe_vaddr->pf.Available & pf64Bit) { /* Are we 64 bit? */ |
55e303ae A |
191 | tmp = 12; /* Size of hash space */ |
192 | } | |
193 | else { | |
194 | __asm__ volatile("cntlzw %0, %1" : "=r" (tmp) : "r" (hash_table_size)); /* Get number of leading 0s */ | |
195 | tmp = 32 - tmp; /* Size of hash space */ | |
196 | } | |
de355530 | 197 | |
55e303ae A |
198 | incrVSID = 1 << ((tmp + 1) >> 1); /* Get ceiling of sqrt of table size */ |
199 | incrVSID |= 1 << ((tmp + 1) >> 2); /* Get ceiling of quadroot of table size */ | |
200 | incrVSID |= 1; /* Set bit and add 1 */ | |
de355530 | 201 | |
55e303ae | 202 | return; |
1c79356b | 203 | |
de355530 | 204 | } |
1c79356b | 205 | |
55e303ae | 206 | |
1c79356b | 207 | /* |
55e303ae A |
208 | * mapping_remove(pmap_t pmap, addr64_t va); |
209 | * Given a pmap and virtual address, this routine finds the mapping and unmaps it. | |
210 | * The mapping block will be added to | |
211 | * the free list. If the free list threshold is reached, garbage collection will happen. | |
0b4e3aa0 | 212 | * |
55e303ae A |
213 | * We also pass back the next higher mapped address. This is done so that the higher level |
214 | * pmap_remove function can release a range of addresses simply by calling mapping_remove | |
215 | * in a loop until it finishes the range or is returned a vaddr of 0. | |
0b4e3aa0 | 216 | * |
55e303ae | 217 | * Note that if the mapping is not found, we return the next VA ORed with 1 |
0b4e3aa0 A |
218 | * |
219 | */ | |
0b4e3aa0 | 220 | |
55e303ae A |
221 | addr64_t mapping_remove(pmap_t pmap, addr64_t va) { /* Remove a single mapping for this VADDR |
222 | Returns TRUE if a mapping was found to remove */ | |
0b4e3aa0 | 223 | |
91447636 | 224 | mapping_t *mp; |
55e303ae | 225 | addr64_t nextva; |
91447636 | 226 | ppnum_t pgaddr; |
de355530 | 227 | |
91447636 A |
228 | va &= ~PAGE_MASK; /* Scrub noise bits */ |
229 | ||
230 | do { /* Keep trying until we truely fail */ | |
55e303ae | 231 | mp = hw_rem_map(pmap, va, &nextva); /* Remove a mapping from this pmap */ |
91447636 | 232 | } while (mapRtRemove == ((unsigned int)mp & mapRetCode)); |
de355530 | 233 | |
91447636 A |
234 | switch ((unsigned int)mp & mapRetCode) { |
235 | case mapRtOK: | |
236 | break; /* Mapping removed */ | |
237 | case mapRtNotFnd: | |
238 | return (nextva | 1); /* Nothing found to unmap */ | |
239 | default: | |
2d21ac55 | 240 | panic("mapping_remove: hw_rem_map failed - pmap = %p, va = %016llX, code = %p\n", |
91447636 A |
241 | pmap, va, mp); |
242 | break; | |
de355530 | 243 | } |
91447636 A |
244 | |
245 | pgaddr = mp->mpPAddr; /* Get page number from mapping */ | |
de355530 | 246 | |
55e303ae | 247 | mapping_free(mp); /* Add mapping to the free list */ |
91447636 A |
248 | |
249 | if ((pmap->pmapFlags & pmapVMhost) && pmap->pmapVmmExt) { | |
250 | /* If this is an assisted host, scrub any guest mappings */ | |
251 | unsigned int idx; | |
252 | phys_entry_t *physent = mapping_phys_lookup(pgaddr, &idx); | |
253 | /* Get physent for our physical page */ | |
254 | if (!physent) { /* No physent, could be in I/O area, so exit */ | |
255 | return (nextva); | |
256 | } | |
257 | ||
258 | do { /* Iterate 'till all guest mappings are gone */ | |
259 | mp = hw_scrub_guest(physent, pmap); /* Attempt to scrub a guest mapping */ | |
260 | switch ((unsigned int)mp & mapRetCode) { | |
261 | case mapRtGuest: /* Found a guest mapping */ | |
262 | case mapRtNotFnd: /* Mapping was there, but disappeared, must retry */ | |
263 | case mapRtEmpty: /* No guest mappings left to scrub */ | |
264 | break; | |
265 | default: | |
2d21ac55 | 266 | panic("mapping_remove: hw_scrub_guest failed - physent = %p, code = %p\n", |
91447636 A |
267 | physent, mp); /* Cry havoc, cry wrack, |
268 | at least we die with harness on our backs */ | |
269 | break; | |
270 | } | |
271 | } while (mapRtEmpty != ((unsigned int)mp & mapRetCode)); | |
272 | } | |
1c79356b | 273 | |
55e303ae A |
274 | return nextva; /* Tell them we did it */ |
275 | } | |
de355530 | 276 | |
1c79356b | 277 | /* |
55e303ae | 278 | * mapping_make(pmap, va, pa, flags, size, prot) - map a virtual address to a real one |
1c79356b A |
279 | * |
280 | * This routine takes the given parameters, builds a mapping block, and queues it into the | |
281 | * correct lists. | |
282 | * | |
55e303ae A |
283 | * pmap (virtual address) is the pmap to map into |
284 | * va (virtual address) is the 64-bit virtual address that is being mapped | |
285 | * pa (physical page number) is the physical page number (i.e., physcial address >> 12). This is | |
286 | * a 32-bit quantity. | |
287 | * Flags: | |
288 | * block if 1, mapping is a block, size parameter is used. Note: we do not keep | |
289 | * reference and change information or allow protection changes of blocks. | |
290 | * any changes must first unmap and then remap the area. | |
291 | * use attribute Use specified attributes for map, not defaults for physical page | |
292 | * perm Mapping is permanent | |
293 | * cache inhibited Cache inhibited (used if use attribute or block set ) | |
294 | * guarded Guarded access (used if use attribute or block set ) | |
3a60a9f5 | 295 | * size size of block in pages - 1 (not used if not block) |
55e303ae A |
296 | * prot VM protection bits |
297 | * attr Cachability/Guardedness | |
298 | * | |
299 | * Returns 0 if mapping was successful. Returns vaddr that overlaps/collides. | |
300 | * Returns 1 for any other failure. | |
301 | * | |
302 | * Note that we make an assumption that all memory in the range 0f 0x0000000080000000 to 0x00000000FFFFFFFF is reserved | |
303 | * for I/O and default the cache attrubutes appropriately. The caller is free to set whatever they want however. | |
304 | * | |
305 | * If there is any physical page that is not found in the physent table, the mapping is forced to be a | |
306 | * block mapping of length 1. This keeps us from trying to update a physent during later mapping use, | |
307 | * e.g., fault handling. | |
308 | * | |
1c79356b | 309 | * |
1c79356b A |
310 | */ |
311 | ||
55e303ae | 312 | addr64_t mapping_make(pmap_t pmap, addr64_t va, ppnum_t pa, unsigned int flags, unsigned int size, vm_prot_t prot) { /* Make an address mapping */ |
1c79356b | 313 | |
91447636 A |
314 | register mapping_t *mp; |
315 | addr64_t colladdr, psmask; | |
316 | unsigned int pindex, mflags, pattr, wimg, rc; | |
317 | phys_entry_t *physent; | |
318 | int nlists, pcf; | |
0c530ab8 | 319 | boolean_t disable_NX = FALSE; |
de355530 | 320 | |
55e303ae A |
321 | pindex = 0; |
322 | ||
323 | mflags = 0x01000000; /* Start building mpFlags field (busy count = 1) */ | |
91447636 A |
324 | |
325 | pcf = (flags & mmFlgPcfg) >> 24; /* Get the physical page config index */ | |
326 | if(!(pPcfg[pcf].pcfFlags)) { /* Validate requested physical page configuration */ | |
2d21ac55 | 327 | panic("mapping_make: invalid physical page configuration request - pmap = %p, va = %016llX, cfg = %d\n", |
91447636 A |
328 | pmap, va, pcf); |
329 | } | |
330 | ||
331 | psmask = (1ULL << pPcfg[pcf].pcfPSize) - 1; /* Mask to isolate any offset into a page */ | |
332 | if(va & psmask) { /* Make sure we are page aligned on virtual */ | |
2d21ac55 | 333 | panic("mapping_make: attempt to map unaligned vaddr - pmap = %p, va = %016llX, cfg = %d\n", |
91447636 A |
334 | pmap, va, pcf); |
335 | } | |
336 | if(((addr64_t)pa << 12) & psmask) { /* Make sure we are page aligned on physical */ | |
2d21ac55 | 337 | panic("mapping_make: attempt to map unaligned paddr - pmap = %p, pa = %08X, cfg = %d\n", |
91447636 A |
338 | pmap, pa, pcf); |
339 | } | |
1c79356b | 340 | |
91447636 A |
341 | mflags |= (pcf << (31-mpPcfgb)); /* Insert physical page configuration index */ |
342 | ||
55e303ae | 343 | if(!(flags & mmFlgBlock)) { /* Is this a block map? */ |
1c79356b | 344 | |
55e303ae A |
345 | size = 1; /* Set size to 1 page if not block */ |
346 | ||
347 | physent = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ | |
348 | if(!physent) { /* Did we find the physical page? */ | |
349 | mflags |= mpBlock; /* Force this to a block if no physent */ | |
55e303ae A |
350 | pattr = 0; /* Assume normal, non-I/O memory */ |
351 | if((pa & 0xFFF80000) == 0x00080000) pattr = mmFlgCInhib | mmFlgGuarded; /* If this page is in I/O range, set I/O attributes */ | |
1c79356b | 352 | } |
91447636 | 353 | else pattr = ((physent->ppLink & (ppI | ppG)) >> 60); /* Get the default attributes from physent */ |
de355530 | 354 | |
55e303ae | 355 | if(flags & mmFlgUseAttr) pattr = flags & (mmFlgCInhib | mmFlgGuarded); /* Use requested attributes */ |
1c79356b | 356 | } |
55e303ae A |
357 | else { /* This is a block */ |
358 | ||
359 | pattr = flags & (mmFlgCInhib | mmFlgGuarded); /* Use requested attributes */ | |
360 | mflags |= mpBlock; /* Show that this is a block */ | |
3a60a9f5 A |
361 | |
362 | if(size > pmapSmallBlock) { /* Is it one? */ | |
363 | if(size & 0x00001FFF) return mapRtBadSz; /* Fail if bigger than 256MB and not a 32MB multiple */ | |
364 | size = size >> 13; /* Convert to 32MB chunks */ | |
365 | mflags = mflags | mpBSu; /* Show 32MB basic size unit */ | |
366 | } | |
de355530 | 367 | } |
1c79356b | 368 | |
55e303ae A |
369 | wimg = 0x2; /* Set basic PPC wimg to 0b0010 - Coherent */ |
370 | if(pattr & mmFlgCInhib) wimg |= 0x4; /* Add cache inhibited if we need to */ | |
371 | if(pattr & mmFlgGuarded) wimg |= 0x1; /* Add guarded if we need to */ | |
1c79356b | 372 | |
55e303ae | 373 | mflags = mflags | (pindex << 16); /* Stick in the physical entry table index */ |
1c79356b | 374 | |
55e303ae | 375 | if(flags & mmFlgPerm) mflags |= mpPerm; /* Set permanent mapping */ |
1c79356b | 376 | |
55e303ae | 377 | size = size - 1; /* Change size to offset */ |
3a60a9f5 | 378 | if(size > 0xFFFF) return mapRtBadSz; /* Leave if size is too big */ |
1c79356b | 379 | |
55e303ae | 380 | nlists = mapSetLists(pmap); /* Set number of lists this will be on */ |
de355530 | 381 | |
55e303ae A |
382 | mp = mapping_alloc(nlists); /* Get a spare mapping block with this many lists */ |
383 | ||
384 | /* the mapping is zero except that the mpLists field is set */ | |
385 | mp->mpFlags |= mflags; /* Add in the rest of the flags to mpLists */ | |
386 | mp->mpSpace = pmap->space; /* Set the address space/pmap lookup ID */ | |
91447636 | 387 | mp->u.mpBSize = size; /* Set the size */ |
55e303ae A |
388 | mp->mpPte = 0; /* Set the PTE invalid */ |
389 | mp->mpPAddr = pa; /* Set the physical page number */ | |
0c530ab8 A |
390 | |
391 | if ( !nx_enabled || (pmap->pmapFlags & pmapNXdisabled) ) | |
392 | disable_NX = TRUE; | |
393 | ||
394 | mp->mpVAddr = (va & ~mpHWFlags) | (wimg << 3) | getProtPPC(prot, disable_NX); /* Add the protection and attributes to the field */ | |
395 | ||
55e303ae A |
396 | while(1) { /* Keep trying... */ |
397 | colladdr = hw_add_map(pmap, mp); /* Go add the mapping to the pmap */ | |
91447636 A |
398 | rc = colladdr & mapRetCode; /* Separate return code */ |
399 | colladdr &= ~mapRetCode; /* Clean up collision effective address */ | |
55e303ae | 400 | |
91447636 A |
401 | switch (rc) { |
402 | case mapRtOK: | |
3a60a9f5 | 403 | return mapRtOK; /* Mapping added successfully */ |
91447636 A |
404 | |
405 | case mapRtRemove: /* Remove in progress */ | |
406 | (void)mapping_remove(pmap, colladdr); /* Lend a helping hand to another CPU doing block removal */ | |
407 | continue; /* Retry mapping add */ | |
408 | ||
409 | case mapRtMapDup: /* Identical mapping already present */ | |
410 | mapping_free(mp); /* Free duplicate mapping */ | |
3a60a9f5 | 411 | return mapRtOK; /* Return success */ |
91447636 A |
412 | |
413 | case mapRtSmash: /* Mapping already present but does not match new mapping */ | |
414 | mapping_free(mp); /* Free duplicate mapping */ | |
3a60a9f5 A |
415 | return (colladdr | mapRtSmash); /* Return colliding address, with some dirt added to avoid |
416 | confusion if effective address is 0 */ | |
91447636 | 417 | default: |
2d21ac55 | 418 | panic("mapping_make: hw_add_map failed - collision addr = %016llX, code = %02X, pmap = %p, va = %016llX, mapping = %p\n", |
91447636 | 419 | colladdr, rc, pmap, va, mp); /* Die dead */ |
1c79356b | 420 | } |
1c79356b | 421 | |
1c79356b A |
422 | } |
423 | ||
91447636 | 424 | return 1; /* Unreachable, but pleases compiler */ |
1c79356b A |
425 | } |
426 | ||
427 | ||
428 | /* | |
55e303ae | 429 | * mapping *mapping_find(pmap, va, *nextva, full) - Finds a mapping |
1c79356b | 430 | * |
55e303ae A |
431 | * Looks up the vaddr and returns the mapping and the next mapped va |
432 | * If full is true, it will descend through all nested pmaps to find actual mapping | |
1c79356b | 433 | * |
55e303ae | 434 | * Must be called with interruptions disabled or we can hang trying to remove found mapping. |
1c79356b | 435 | * |
55e303ae A |
436 | * Returns 0 if not found and the virtual address of the mapping if it is |
437 | * Note that the mappings busy count is bumped. It is the responsibility of the caller | |
438 | * to drop the count. If this is not done, any attempt to remove the mapping will hang. | |
1c79356b | 439 | * |
55e303ae | 440 | * NOTE: The nextva field is not valid when full is TRUE. |
1c79356b | 441 | * |
1c79356b A |
442 | * |
443 | */ | |
444 | ||
91447636 | 445 | mapping_t *mapping_find(pmap_t pmap, addr64_t va, addr64_t *nextva, int full) { /* Make an address mapping */ |
de355530 | 446 | |
91447636 | 447 | register mapping_t *mp; |
55e303ae A |
448 | addr64_t curva; |
449 | pmap_t curpmap; | |
450 | int nestdepth; | |
de355530 | 451 | |
55e303ae A |
452 | curpmap = pmap; /* Remember entry */ |
453 | nestdepth = 0; /* Set nest depth */ | |
91447636 | 454 | curva = (addr64_t)va; /* Set current va */ |
de355530 | 455 | |
55e303ae | 456 | while(1) { |
1c79356b | 457 | |
55e303ae A |
458 | mp = hw_find_map(curpmap, curva, nextva); /* Find the mapping for this address */ |
459 | if((unsigned int)mp == mapRtBadLk) { /* Did we lock up ok? */ | |
2d21ac55 | 460 | panic("mapping_find: pmap lock failure - rc = %p, pmap = %p\n", mp, curpmap); /* Die... */ |
1c79356b | 461 | } |
55e303ae | 462 | |
91447636 | 463 | if(!mp || ((mp->mpFlags & mpType) < mpMinSpecial) || !full) break; /* Are we done looking? */ |
1c79356b | 464 | |
91447636 A |
465 | if((mp->mpFlags & mpType) != mpNest) { /* Don't chain through anything other than a nested pmap */ |
466 | mapping_drop_busy(mp); /* We have everything we need from the mapping */ | |
2d21ac55 | 467 | mp = NULL; /* Set not found */ |
55e303ae | 468 | break; |
1c79356b | 469 | } |
1c79356b | 470 | |
55e303ae | 471 | if(nestdepth++ > 64) { /* Have we nested too far down? */ |
2d21ac55 | 472 | panic("mapping_find: too many nested pmaps - va = %016llX, curva = %016llX, pmap = %p, curpmap = %p\n", |
55e303ae | 473 | va, curva, pmap, curpmap); |
1c79356b | 474 | } |
55e303ae A |
475 | |
476 | curva = curva + mp->mpNestReloc; /* Relocate va to new pmap */ | |
477 | curpmap = (pmap_t) pmapTrans[mp->mpSpace].pmapVAddr; /* Get the address of the nested pmap */ | |
478 | mapping_drop_busy(mp); /* We have everything we need from the mapping */ | |
479 | ||
1c79356b A |
480 | } |
481 | ||
55e303ae | 482 | return mp; /* Return the mapping if we found one */ |
1c79356b A |
483 | } |
484 | ||
1c79356b | 485 | /* |
91447636 | 486 | * void mapping_protect(pmap_t pmap, addt_t va, vm_prot_t prot, addr64_t *nextva) - change the protection of a virtual page |
1c79356b | 487 | * |
55e303ae A |
488 | * This routine takes a pmap and virtual address and changes |
489 | * the protection. If there are PTEs associated with the mappings, they will be invalidated before | |
490 | * the protection is changed. | |
1c79356b | 491 | * |
55e303ae A |
492 | * We return success if we change the protection or if there is no page mapped at va. We return failure if |
493 | * the va corresponds to a block mapped area or the mapping is permanant. | |
de355530 | 494 | * |
1c79356b A |
495 | * |
496 | */ | |
1c79356b | 497 | |
91447636 A |
498 | void |
499 | mapping_protect(pmap_t pmap, addr64_t va, vm_prot_t prot, addr64_t *nextva) { /* Change protection of a virtual page */ | |
1c79356b | 500 | |
55e303ae | 501 | int ret; |
0c530ab8 A |
502 | boolean_t disable_NX = FALSE; |
503 | ||
504 | if ( !nx_enabled || (pmap->pmapFlags & pmapNXdisabled) ) | |
505 | disable_NX = TRUE; | |
506 | ||
507 | ret = hw_protect(pmap, va, getProtPPC(prot, disable_NX), nextva); /* Try to change the protect here */ | |
1c79356b | 508 | |
55e303ae A |
509 | switch (ret) { /* Decode return code */ |
510 | ||
511 | case mapRtOK: /* Changed */ | |
512 | case mapRtNotFnd: /* Didn't find it */ | |
55e303ae A |
513 | case mapRtBlock: /* Block map, just ignore request */ |
514 | case mapRtNest: /* Nested pmap, just ignore request */ | |
55e303ae A |
515 | break; |
516 | ||
517 | default: | |
2d21ac55 | 518 | panic("mapping_protect: hw_protect failed - rc = %d, pmap = %p, va = %016llX\n", ret, pmap, va); |
55e303ae | 519 | |
1c79356b A |
520 | } |
521 | ||
1c79356b | 522 | } |
1c79356b A |
523 | |
524 | /* | |
55e303ae | 525 | * void mapping_protect_phys(ppnum_t pa, vm_prot_t prot) - change the protection of a physical page |
1c79356b A |
526 | * |
527 | * This routine takes a physical entry and runs through all mappings attached to it and changes | |
528 | * the protection. If there are PTEs associated with the mappings, they will be invalidated before | |
0c530ab8 A |
529 | * the protection is changed. There is no limitation on changes, e.g., higher to lower, lower to |
530 | * higher; however, changes to execute protection are ignored. | |
1c79356b | 531 | * |
55e303ae A |
532 | * Any mapping that is marked permanent is not changed |
533 | * | |
1c79356b A |
534 | * Phys_entry is unlocked. |
535 | */ | |
536 | ||
55e303ae | 537 | void mapping_protect_phys(ppnum_t pa, vm_prot_t prot) { /* Change protection of all mappings to page */ |
1c79356b | 538 | |
55e303ae | 539 | unsigned int pindex; |
91447636 | 540 | phys_entry_t *physent; |
0c530ab8 | 541 | |
55e303ae A |
542 | physent = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ |
543 | if(!physent) { /* Did we find the physical page? */ | |
544 | panic("mapping_protect_phys: invalid physical page %08X\n", pa); | |
de355530 | 545 | } |
1c79356b | 546 | |
91447636 | 547 | hw_walk_phys(physent, hwpNoop, hwpSPrtMap, hwpNoop, |
0c530ab8 | 548 | getProtPPC(prot, FALSE), hwpPurgePTE); /* Set the new protection for page and mappings */ |
de355530 | 549 | |
0c530ab8 | 550 | return; /* Leave... */ |
1c79356b A |
551 | } |
552 | ||
553 | ||
554 | /* | |
55e303ae | 555 | * void mapping_clr_mod(ppnum_t pa) - clears the change bit of a physical page |
1c79356b A |
556 | * |
557 | * This routine takes a physical entry and runs through all mappings attached to it and turns | |
55e303ae | 558 | * off the change bit. |
1c79356b A |
559 | */ |
560 | ||
55e303ae A |
561 | void mapping_clr_mod(ppnum_t pa) { /* Clears the change bit of a physical page */ |
562 | ||
563 | unsigned int pindex; | |
91447636 | 564 | phys_entry_t *physent; |
55e303ae A |
565 | |
566 | physent = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ | |
567 | if(!physent) { /* Did we find the physical page? */ | |
568 | panic("mapping_clr_mod: invalid physical page %08X\n", pa); | |
569 | } | |
1c79356b | 570 | |
91447636 A |
571 | hw_walk_phys(physent, hwpNoop, hwpCCngMap, hwpCCngPhy, |
572 | 0, hwpPurgePTE); /* Clear change for page and mappings */ | |
1c79356b A |
573 | return; /* Leave... */ |
574 | } | |
575 | ||
576 | ||
577 | /* | |
55e303ae | 578 | * void mapping_set_mod(ppnum_t pa) - set the change bit of a physical page |
1c79356b A |
579 | * |
580 | * This routine takes a physical entry and runs through all mappings attached to it and turns | |
55e303ae | 581 | * on the change bit. |
1c79356b A |
582 | */ |
583 | ||
55e303ae A |
584 | void mapping_set_mod(ppnum_t pa) { /* Sets the change bit of a physical page */ |
585 | ||
586 | unsigned int pindex; | |
91447636 | 587 | phys_entry_t *physent; |
55e303ae A |
588 | |
589 | physent = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ | |
590 | if(!physent) { /* Did we find the physical page? */ | |
591 | panic("mapping_set_mod: invalid physical page %08X\n", pa); | |
592 | } | |
d7e50217 | 593 | |
91447636 A |
594 | hw_walk_phys(physent, hwpNoop, hwpSCngMap, hwpSCngPhy, |
595 | 0, hwpNoopPTE); /* Set change for page and mappings */ | |
1c79356b A |
596 | return; /* Leave... */ |
597 | } | |
598 | ||
599 | ||
600 | /* | |
55e303ae | 601 | * void mapping_clr_ref(ppnum_t pa) - clears the reference bit of a physical page |
1c79356b | 602 | * |
de355530 | 603 | * This routine takes a physical entry and runs through all mappings attached to it and turns |
55e303ae | 604 | * off the reference bit. |
1c79356b A |
605 | */ |
606 | ||
55e303ae | 607 | void mapping_clr_ref(ppnum_t pa) { /* Clears the reference bit of a physical page */ |
de355530 | 608 | |
55e303ae | 609 | unsigned int pindex; |
91447636 | 610 | phys_entry_t *physent; |
55e303ae A |
611 | |
612 | physent = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ | |
613 | if(!physent) { /* Did we find the physical page? */ | |
614 | panic("mapping_clr_ref: invalid physical page %08X\n", pa); | |
d7e50217 | 615 | } |
55e303ae | 616 | |
91447636 A |
617 | hw_walk_phys(physent, hwpNoop, hwpCRefMap, hwpCRefPhy, |
618 | 0, hwpPurgePTE); /* Clear reference for page and mappings */ | |
de355530 A |
619 | return; /* Leave... */ |
620 | } | |
621 | ||
622 | ||
623 | /* | |
55e303ae | 624 | * void mapping_set_ref(ppnum_t pa) - set the reference bit of a physical page |
de355530 A |
625 | * |
626 | * This routine takes a physical entry and runs through all mappings attached to it and turns | |
55e303ae | 627 | * on the reference bit. |
de355530 A |
628 | */ |
629 | ||
55e303ae A |
630 | void mapping_set_ref(ppnum_t pa) { /* Sets the reference bit of a physical page */ |
631 | ||
632 | unsigned int pindex; | |
91447636 | 633 | phys_entry_t *physent; |
55e303ae A |
634 | |
635 | physent = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ | |
636 | if(!physent) { /* Did we find the physical page? */ | |
637 | panic("mapping_set_ref: invalid physical page %08X\n", pa); | |
638 | } | |
d7e50217 | 639 | |
91447636 A |
640 | hw_walk_phys(physent, hwpNoop, hwpSRefMap, hwpSRefPhy, |
641 | 0, hwpNoopPTE); /* Set reference for page and mappings */ | |
de355530 | 642 | return; /* Leave... */ |
1c79356b A |
643 | } |
644 | ||
645 | ||
646 | /* | |
91447636 | 647 | * boolean_t mapping_tst_mod(ppnum_t pa) - test the change bit of a physical page |
1c79356b A |
648 | * |
649 | * This routine takes a physical entry and runs through all mappings attached to it and tests | |
55e303ae | 650 | * the changed bit. |
1c79356b A |
651 | */ |
652 | ||
55e303ae A |
653 | boolean_t mapping_tst_mod(ppnum_t pa) { /* Tests the change bit of a physical page */ |
654 | ||
655 | unsigned int pindex, rc; | |
91447636 | 656 | phys_entry_t *physent; |
55e303ae A |
657 | |
658 | physent = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ | |
659 | if(!physent) { /* Did we find the physical page? */ | |
660 | panic("mapping_tst_mod: invalid physical page %08X\n", pa); | |
661 | } | |
d7e50217 | 662 | |
91447636 A |
663 | rc = hw_walk_phys(physent, hwpTCngPhy, hwpTCngMap, hwpNoop, |
664 | 0, hwpMergePTE); /* Set change for page and mappings */ | |
55e303ae | 665 | return ((rc & (unsigned long)ppC) != 0); /* Leave with change bit */ |
1c79356b A |
666 | } |
667 | ||
668 | ||
669 | /* | |
91447636 | 670 | * boolean_t mapping_tst_ref(ppnum_t pa) - tests the reference bit of a physical page |
de355530 A |
671 | * |
672 | * This routine takes a physical entry and runs through all mappings attached to it and tests | |
55e303ae | 673 | * the reference bit. |
1c79356b A |
674 | */ |
675 | ||
55e303ae A |
676 | boolean_t mapping_tst_ref(ppnum_t pa) { /* Tests the reference bit of a physical page */ |
677 | ||
678 | unsigned int pindex, rc; | |
91447636 | 679 | phys_entry_t *physent; |
55e303ae A |
680 | |
681 | physent = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ | |
682 | if(!physent) { /* Did we find the physical page? */ | |
683 | panic("mapping_tst_ref: invalid physical page %08X\n", pa); | |
684 | } | |
1c79356b | 685 | |
91447636 A |
686 | rc = hw_walk_phys(physent, hwpTRefPhy, hwpTRefMap, hwpNoop, |
687 | 0, hwpMergePTE); /* Test reference for page and mappings */ | |
55e303ae | 688 | return ((rc & (unsigned long)ppR) != 0); /* Leave with reference bit */ |
1c79356b A |
689 | } |
690 | ||
691 | ||
91447636 A |
692 | /* |
693 | * unsigned int mapping_tst_refmod(ppnum_t pa) - tests the reference and change bits of a physical page | |
694 | * | |
695 | * This routine takes a physical entry and runs through all mappings attached to it and tests | |
696 | * their reference and changed bits. | |
697 | */ | |
698 | ||
699 | unsigned int mapping_tst_refmod(ppnum_t pa) { /* Tests the reference and change bits of a physical page */ | |
700 | ||
701 | unsigned int pindex, rc; | |
702 | phys_entry_t *physent; | |
703 | ||
704 | physent = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ | |
705 | if (!physent) { /* Did we find the physical page? */ | |
706 | panic("mapping_tst_refmod: invalid physical page %08X\n", pa); | |
707 | } | |
708 | ||
709 | rc = hw_walk_phys(physent, hwpTRefCngPhy, hwpTRefCngMap, hwpNoop, | |
710 | 0, hwpMergePTE); /* Test reference and change bits in page and mappings */ | |
711 | return (((rc & ppC)? VM_MEM_MODIFIED : 0) | ((rc & ppR)? VM_MEM_REFERENCED : 0)); | |
712 | /* Convert bits to generic format and return */ | |
713 | ||
714 | } | |
715 | ||
716 | ||
717 | /* | |
718 | * void mapping_clr_refmod(ppnum_t pa, unsigned int mask) - clears the reference and change bits specified | |
719 | * by mask of a physical page | |
720 | * | |
721 | * This routine takes a physical entry and runs through all mappings attached to it and turns | |
722 | * off all the reference and change bits. | |
723 | */ | |
724 | ||
725 | void mapping_clr_refmod(ppnum_t pa, unsigned int mask) { /* Clears the reference and change bits of a physical page */ | |
726 | ||
727 | unsigned int pindex; | |
728 | phys_entry_t *physent; | |
729 | unsigned int ppcMask; | |
730 | ||
731 | physent = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ | |
732 | if(!physent) { /* Did we find the physical page? */ | |
733 | panic("mapping_clr_refmod: invalid physical page %08X\n", pa); | |
734 | } | |
735 | ||
736 | ppcMask = (((mask & VM_MEM_MODIFIED)? ppC : 0) | ((mask & VM_MEM_REFERENCED)? ppR : 0)); | |
737 | /* Convert mask bits to PPC-specific format */ | |
738 | hw_walk_phys(physent, hwpNoop, hwpCRefCngMap, hwpCRefCngPhy, | |
739 | ppcMask, hwpPurgePTE); /* Clear reference and change bits for page and mappings */ | |
740 | return; /* Leave... */ | |
741 | } | |
742 | ||
743 | ||
744 | ||
de355530 | 745 | /* |
55e303ae | 746 | * phys_ent *mapping_phys_lookup(ppnum_t pp, unsigned int *pindex) - tests the reference bit of a physical page |
de355530 | 747 | * |
55e303ae A |
748 | * This routine takes a physical page number and returns the phys_entry associated with it. It also |
749 | * calculates the bank address associated with the entry | |
750 | * the reference bit. | |
de355530 A |
751 | */ |
752 | ||
2d21ac55 A |
753 | phys_entry_t * |
754 | mapping_phys_lookup(ppnum_t pp, unsigned int *pindex) | |
755 | { /* Finds the physical entry for the page */ | |
756 | unsigned int i; | |
55e303ae A |
757 | |
758 | for(i = 0; i < pmap_mem_regions_count; i++) { /* Walk through the list */ | |
759 | if(!(unsigned int)pmap_mem_regions[i].mrPhysTab) continue; /* Skip any empty lists */ | |
760 | if((pp < pmap_mem_regions[i].mrStart) || (pp > pmap_mem_regions[i].mrEnd)) continue; /* This isn't ours */ | |
761 | ||
762 | *pindex = (i * sizeof(mem_region_t)) / 4; /* Make the word index to this list */ | |
763 | ||
764 | return &pmap_mem_regions[i].mrPhysTab[pp - pmap_mem_regions[i].mrStart]; /* Return the physent pointer */ | |
765 | } | |
766 | ||
91447636 | 767 | return (phys_entry_t *)0; /* Shucks, can't find it... */ |
55e303ae | 768 | |
de355530 | 769 | } |
d7e50217 A |
770 | |
771 | ||
55e303ae A |
772 | |
773 | ||
1c79356b A |
774 | /* |
775 | * mapping_adjust(void) - Releases free mapping blocks and/or allocates new ones | |
776 | * | |
777 | * This routine frees any mapping blocks queued to mapCtl.mapcrel. It also checks | |
778 | * the number of free mappings remaining, and if below a threshold, replenishes them. | |
779 | * The list will be replenshed from mapCtl.mapcrel if there are enough. Otherwise, | |
780 | * a new one is allocated. | |
781 | * | |
55e303ae A |
782 | * This routine allocates and/or frees memory and must be called from a safe place. |
783 | * Currently, vm_pageout_scan is the safest place. | |
1c79356b A |
784 | */ |
785 | ||
786 | thread_call_t mapping_adjust_call; | |
787 | static thread_call_data_t mapping_adjust_call_data; | |
788 | ||
789 | void mapping_adjust(void) { /* Adjust free mappings */ | |
790 | ||
55e303ae | 791 | kern_return_t retr = KERN_SUCCESS; |
91447636 | 792 | mappingblok_t *mb, *mbn; |
1c79356b | 793 | spl_t s; |
91447636 | 794 | int allocsize; |
1c79356b A |
795 | |
796 | if(mapCtl.mapcmin <= MAPPERBLOK) { | |
55e303ae | 797 | mapCtl.mapcmin = (sane_size / PAGE_SIZE) / 16; |
1c79356b A |
798 | |
799 | #if DEBUG | |
800 | kprintf("mapping_adjust: minimum entries rqrd = %08X\n", mapCtl.mapcmin); | |
801 | kprintf("mapping_adjust: free = %08X; in use = %08X; release = %08X\n", | |
802 | mapCtl.mapcfree, mapCtl.mapcinuse, mapCtl.mapcreln); | |
803 | #endif | |
804 | } | |
805 | ||
806 | s = splhigh(); /* Don't bother from now on */ | |
807 | if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ | |
808 | panic("mapping_adjust - timeout getting control lock (1)\n"); /* Tell all and die */ | |
809 | } | |
810 | ||
811 | if (mapping_adjust_call == NULL) { | |
9bccf70c A |
812 | thread_call_setup(&mapping_adjust_call_data, |
813 | (thread_call_func_t)mapping_adjust, | |
814 | (thread_call_param_t)NULL); | |
1c79356b A |
815 | mapping_adjust_call = &mapping_adjust_call_data; |
816 | } | |
817 | ||
818 | while(1) { /* Keep going until we've got enough */ | |
819 | ||
820 | allocsize = mapCtl.mapcmin - mapCtl.mapcfree; /* Figure out how much we need */ | |
821 | if(allocsize < 1) break; /* Leave if we have all we need */ | |
822 | ||
823 | if((unsigned int)(mbn = mapCtl.mapcrel)) { /* Can we rescue a free one? */ | |
824 | mapCtl.mapcrel = mbn->nextblok; /* Dequeue it */ | |
825 | mapCtl.mapcreln--; /* Back off the count */ | |
826 | allocsize = MAPPERBLOK; /* Show we allocated one block */ | |
827 | } | |
55e303ae | 828 | else { /* No free ones, try to get it */ |
1c79356b A |
829 | |
830 | allocsize = (allocsize + MAPPERBLOK - 1) / MAPPERBLOK; /* Get the number of pages we need */ | |
55e303ae | 831 | |
1c79356b A |
832 | hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ |
833 | splx(s); /* Restore 'rupts */ | |
834 | ||
835 | for(; allocsize > 0; allocsize >>= 1) { /* Try allocating in descending halves */ | |
836 | retr = kmem_alloc_wired(mapping_map, (vm_offset_t *)&mbn, PAGE_SIZE * allocsize); /* Find a virtual address to use */ | |
837 | if((retr != KERN_SUCCESS) && (allocsize == 1)) { /* Did we find any memory at all? */ | |
9bccf70c | 838 | break; |
1c79356b A |
839 | } |
840 | if(retr == KERN_SUCCESS) break; /* We got some memory, bail out... */ | |
841 | } | |
55e303ae | 842 | |
1c79356b A |
843 | allocsize = allocsize * MAPPERBLOK; /* Convert pages to number of maps allocated */ |
844 | s = splhigh(); /* Don't bother from now on */ | |
845 | if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ | |
846 | panic("mapping_adjust - timeout getting control lock (2)\n"); /* Tell all and die */ | |
847 | } | |
848 | } | |
55e303ae | 849 | |
9bccf70c A |
850 | if (retr != KERN_SUCCESS) |
851 | break; /* Fail to alocate, bail out... */ | |
1c79356b A |
852 | for(; allocsize > 0; allocsize -= MAPPERBLOK) { /* Release one block at a time */ |
853 | mapping_free_init((vm_offset_t)mbn, 0, 1); /* Initialize a non-permanent block */ | |
91447636 | 854 | mbn = (mappingblok_t *)((unsigned int)mbn + PAGE_SIZE); /* Point to the next slot */ |
1c79356b | 855 | } |
55e303ae | 856 | |
1c79356b A |
857 | if ((mapCtl.mapcinuse + mapCtl.mapcfree + (mapCtl.mapcreln * (MAPPERBLOK + 1))) > mapCtl.mapcmaxalloc) |
858 | mapCtl.mapcmaxalloc = mapCtl.mapcinuse + mapCtl.mapcfree + (mapCtl.mapcreln * (MAPPERBLOK + 1)); | |
859 | } | |
860 | ||
861 | if(mapCtl.mapcholdoff) { /* Should we hold off this release? */ | |
862 | mapCtl.mapcrecurse = 0; /* We are done now */ | |
863 | hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ | |
864 | splx(s); /* Restore 'rupts */ | |
865 | return; /* Return... */ | |
866 | } | |
867 | ||
868 | mbn = mapCtl.mapcrel; /* Get first pending release block */ | |
2d21ac55 | 869 | mapCtl.mapcrel = NULL; /* Dequeue them */ |
1c79356b A |
870 | mapCtl.mapcreln = 0; /* Set count to 0 */ |
871 | ||
872 | hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ | |
873 | splx(s); /* Restore 'rupts */ | |
874 | ||
875 | while((unsigned int)mbn) { /* Toss 'em all */ | |
876 | mb = mbn->nextblok; /* Get the next */ | |
55e303ae | 877 | |
1c79356b | 878 | kmem_free(mapping_map, (vm_offset_t) mbn, PAGE_SIZE); /* Release this mapping block */ |
55e303ae | 879 | |
1c79356b A |
880 | mbn = mb; /* Chain to the next */ |
881 | } | |
882 | ||
55e303ae | 883 | __asm__ volatile("eieio"); /* Make sure all is well */ |
1c79356b A |
884 | mapCtl.mapcrecurse = 0; /* We are done now */ |
885 | return; | |
886 | } | |
887 | ||
888 | /* | |
889 | * mapping_free(mapping *mp) - release a mapping to the free list | |
890 | * | |
891 | * This routine takes a mapping and adds it to the free list. | |
892 | * If this mapping make the block non-empty, we queue it to the free block list. | |
893 | * NOTE: we might want to queue it to the end to keep quelch the pathalogical | |
894 | * case when we get a mapping and free it repeatedly causing the block to chain and unchain. | |
895 | * If this release fills a block and we are above the threshold, we release the block | |
896 | */ | |
897 | ||
898 | void mapping_free(struct mapping *mp) { /* Release a mapping */ | |
899 | ||
91447636 | 900 | mappingblok_t *mb, *mbn; |
1c79356b | 901 | spl_t s; |
55e303ae | 902 | unsigned int full, mindx, lists; |
1c79356b | 903 | |
55e303ae | 904 | mindx = ((unsigned int)mp & (PAGE_SIZE - 1)) >> 6; /* Get index to mapping */ |
91447636 | 905 | mb = (mappingblok_t *)((unsigned int)mp & -PAGE_SIZE); /* Point to the mapping block */ |
55e303ae A |
906 | lists = (mp->mpFlags & mpLists); /* get #lists */ |
907 | if ((lists == 0) || (lists > kSkipListMaxLists)) /* panic if out of range */ | |
908 | panic("mapping_free: mpLists invalid\n"); | |
909 | ||
910 | #if 0 | |
911 | mp->mpFlags = 0x99999999; /* (BRINGUP) */ | |
912 | mp->mpSpace = 0x9999; /* (BRINGUP) */ | |
91447636 | 913 | mp->u.mpBSize = 0x9999; /* (BRINGUP) */ |
55e303ae A |
914 | mp->mpPte = 0x99999998; /* (BRINGUP) */ |
915 | mp->mpPAddr = 0x99999999; /* (BRINGUP) */ | |
916 | mp->mpVAddr = 0x9999999999999999ULL; /* (BRINGUP) */ | |
917 | mp->mpAlias = 0x9999999999999999ULL; /* (BRINGUP) */ | |
918 | mp->mpList0 = 0x9999999999999999ULL; /* (BRINGUP) */ | |
919 | mp->mpList[0] = 0x9999999999999999ULL; /* (BRINGUP) */ | |
920 | mp->mpList[1] = 0x9999999999999999ULL; /* (BRINGUP) */ | |
921 | mp->mpList[2] = 0x9999999999999999ULL; /* (BRINGUP) */ | |
922 | ||
923 | if(lists > mpBasicLists) { /* (BRINGUP) */ | |
924 | mp->mpList[3] = 0x9999999999999999ULL; /* (BRINGUP) */ | |
925 | mp->mpList[4] = 0x9999999999999999ULL; /* (BRINGUP) */ | |
926 | mp->mpList[5] = 0x9999999999999999ULL; /* (BRINGUP) */ | |
927 | mp->mpList[6] = 0x9999999999999999ULL; /* (BRINGUP) */ | |
928 | mp->mpList[7] = 0x9999999999999999ULL; /* (BRINGUP) */ | |
929 | mp->mpList[8] = 0x9999999999999999ULL; /* (BRINGUP) */ | |
930 | mp->mpList[9] = 0x9999999999999999ULL; /* (BRINGUP) */ | |
931 | mp->mpList[10] = 0x9999999999999999ULL; /* (BRINGUP) */ | |
932 | } | |
933 | #endif | |
934 | ||
1c79356b A |
935 | |
936 | s = splhigh(); /* Don't bother from now on */ | |
937 | if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ | |
938 | panic("mapping_free - timeout getting control lock\n"); /* Tell all and die */ | |
939 | } | |
940 | ||
55e303ae | 941 | full = !(mb->mapblokfree[0] | mb->mapblokfree[1]); /* See if full now */ |
1c79356b | 942 | mb->mapblokfree[mindx >> 5] |= (0x80000000 >> (mindx & 31)); /* Flip on the free bit */ |
55e303ae A |
943 | if ( lists > mpBasicLists ) { /* if big block, lite the 2nd bit too */ |
944 | mindx++; | |
945 | mb->mapblokfree[mindx >> 5] |= (0x80000000 >> (mindx & 31)); | |
946 | mapCtl.mapcfree++; | |
947 | mapCtl.mapcinuse--; | |
948 | } | |
1c79356b A |
949 | |
950 | if(full) { /* If it was full before this: */ | |
951 | mb->nextblok = mapCtl.mapcnext; /* Move head of list to us */ | |
952 | mapCtl.mapcnext = mb; /* Chain us to the head of the list */ | |
9bccf70c A |
953 | if(!((unsigned int)mapCtl.mapclast)) |
954 | mapCtl.mapclast = mb; | |
1c79356b A |
955 | } |
956 | ||
957 | mapCtl.mapcfree++; /* Bump free count */ | |
958 | mapCtl.mapcinuse--; /* Decriment in use count */ | |
959 | ||
960 | mapCtl.mapcfreec++; /* Count total calls */ | |
961 | ||
962 | if(mapCtl.mapcfree > mapCtl.mapcmin) { /* Should we consider releasing this? */ | |
55e303ae | 963 | if(((mb->mapblokfree[0] | 0x80000000) & mb->mapblokfree[1]) == 0xFFFFFFFF) { /* See if empty now */ |
1c79356b A |
964 | |
965 | if(mapCtl.mapcnext == mb) { /* Are we first on the list? */ | |
966 | mapCtl.mapcnext = mb->nextblok; /* Unchain us */ | |
2d21ac55 | 967 | if(!((unsigned int)mapCtl.mapcnext)) mapCtl.mapclast = NULL; /* If last, remove last */ |
1c79356b A |
968 | } |
969 | else { /* We're not first */ | |
970 | for(mbn = mapCtl.mapcnext; mbn != 0; mbn = mbn->nextblok) { /* Search for our block */ | |
971 | if(mbn->nextblok == mb) break; /* Is the next one our's? */ | |
972 | } | |
2d21ac55 | 973 | if(!mbn) panic("mapping_free: attempt to release mapping block (%p) not on list\n", mp); |
1c79356b A |
974 | mbn->nextblok = mb->nextblok; /* Dequeue us */ |
975 | if(mapCtl.mapclast == mb) mapCtl.mapclast = mbn; /* If last, make our predecessor last */ | |
976 | } | |
977 | ||
978 | if(mb->mapblokflags & mbPerm) { /* Is this permanently assigned? */ | |
979 | mb->nextblok = mapCtl.mapcnext; /* Move chain head to us */ | |
980 | mapCtl.mapcnext = mb; /* Chain us to the head */ | |
981 | if(!((unsigned int)mb->nextblok)) mapCtl.mapclast = mb; /* If last, make us so */ | |
982 | } | |
983 | else { | |
984 | mapCtl.mapcfree -= MAPPERBLOK; /* Remove the block from the free count */ | |
985 | mapCtl.mapcreln++; /* Count on release list */ | |
986 | mb->nextblok = mapCtl.mapcrel; /* Move pointer */ | |
987 | mapCtl.mapcrel = mb; /* Chain us in front */ | |
988 | } | |
989 | } | |
990 | } | |
991 | ||
992 | if(mapCtl.mapcreln > MAPFRTHRSH) { /* Do we have way too many releasable mappings? */ | |
993 | if(hw_compare_and_store(0, 1, &mapCtl.mapcrecurse)) { /* Make sure we aren't recursing */ | |
994 | thread_call_enter(mapping_adjust_call); /* Go toss some */ | |
995 | } | |
996 | } | |
997 | hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ | |
998 | splx(s); /* Restore 'rupts */ | |
999 | ||
1000 | return; /* Bye, dude... */ | |
1001 | } | |
1002 | ||
1003 | ||
1004 | /* | |
55e303ae | 1005 | * mapping_alloc(lists) - obtain a mapping from the free list |
1c79356b | 1006 | * |
55e303ae A |
1007 | * This routine takes a mapping off of the free list and returns its address. |
1008 | * The mapping is zeroed, and its mpLists count is set. The caller passes in | |
1009 | * the number of skiplists it would prefer; if this number is greater than | |
1010 | * mpBasicLists (ie, 4) then we need to allocate a 128-byte mapping, which is | |
1011 | * just two consequtive free entries coallesced into one. If we cannot find | |
1012 | * two consequtive free entries, we clamp the list count down to mpBasicLists | |
1013 | * and return a basic 64-byte node. Our caller never knows the difference. | |
1c79356b | 1014 | * |
55e303ae | 1015 | * If this allocation empties a block, we remove it from the free list. |
1c79356b A |
1016 | * If this allocation drops the total number of free entries below a threshold, |
1017 | * we allocate a new block. | |
1018 | * | |
1019 | */ | |
91447636 | 1020 | decl_simple_lock_data(extern,free_pmap_lock) |
1c79356b | 1021 | |
91447636 A |
1022 | mapping_t * |
1023 | mapping_alloc(int lists) { /* Obtain a mapping */ | |
1c79356b | 1024 | |
91447636 A |
1025 | register mapping_t *mp; |
1026 | mappingblok_t *mb, *mbn; | |
1c79356b A |
1027 | spl_t s; |
1028 | int mindx; | |
55e303ae A |
1029 | int big = (lists > mpBasicLists); /* set flag if big block req'd */ |
1030 | pmap_t refpmap, ckpmap; | |
1031 | unsigned int space, i; | |
55e303ae | 1032 | addr64_t va, nextva; |
55e303ae A |
1033 | boolean_t found_mapping; |
1034 | boolean_t do_rescan; | |
1035 | ||
1c79356b A |
1036 | s = splhigh(); /* Don't bother from now on */ |
1037 | if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ | |
1038 | panic("mapping_alloc - timeout getting control lock\n"); /* Tell all and die */ | |
1039 | } | |
1040 | ||
55e303ae A |
1041 | if(!((unsigned int)mapCtl.mapcnext)) { /* Are there any free mappings? */ |
1042 | ||
1043 | /* | |
1044 | * No free mappings. First, there may be some mapping blocks on the "to be released" | |
1045 | * list. If so, rescue one. Otherwise, try to steal a couple blocks worth. | |
1046 | */ | |
1047 | ||
91447636 | 1048 | if((mbn = mapCtl.mapcrel) != 0) { /* Try to rescue a block from impending doom */ |
55e303ae A |
1049 | mapCtl.mapcrel = mbn->nextblok; /* Pop the queue */ |
1050 | mapCtl.mapcreln--; /* Back off the count */ | |
1051 | mapping_free_init((vm_offset_t)mbn, 0, 1); /* Initialize a non-permanent block */ | |
1052 | goto rescued; | |
1053 | } | |
1054 | ||
1055 | hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); | |
1056 | ||
1057 | simple_lock(&free_pmap_lock); | |
1058 | ||
1059 | if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ | |
1060 | panic("mapping_alloc - timeout getting control lock\n"); /* Tell all and die */ | |
1061 | } | |
1062 | ||
1063 | if (!((unsigned int)mapCtl.mapcnext)) { | |
1064 | ||
1065 | refpmap = (pmap_t)cursor_pmap->pmap_link.next; | |
1066 | space = mapCtl.mapcflush.spacenum; | |
1067 | while (refpmap != cursor_pmap) { | |
1068 | if(((pmap_t)(refpmap->pmap_link.next))->spaceNum > space) break; | |
1069 | refpmap = (pmap_t)refpmap->pmap_link.next; | |
de355530 | 1070 | } |
55e303ae A |
1071 | |
1072 | ckpmap = refpmap; | |
1073 | va = mapCtl.mapcflush.addr; | |
1074 | found_mapping = FALSE; | |
1075 | ||
1076 | while (mapCtl.mapcfree <= (MAPPERBLOK*2)) { | |
1077 | ||
1078 | hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); | |
1079 | ||
1080 | ckpmap = (pmap_t)ckpmap->pmap_link.next; | |
1081 | ||
91447636 A |
1082 | /* We don't steal mappings from the kernel pmap, a VMM host pmap, or a VMM guest pmap with guest |
1083 | shadow assist active. | |
1084 | */ | |
1085 | if ((ckpmap->stats.resident_count != 0) && (ckpmap != kernel_pmap) | |
1086 | && !(ckpmap->pmapFlags & (pmapVMgsaa|pmapVMhost))) { | |
55e303ae A |
1087 | do_rescan = TRUE; |
1088 | for (i=0;i<8;i++) { | |
1089 | mp = hw_purge_map(ckpmap, va, &nextva); | |
1090 | ||
91447636 A |
1091 | switch ((unsigned int)mp & mapRetCode) { |
1092 | case mapRtOK: | |
1093 | mapping_free(mp); | |
1094 | found_mapping = TRUE; | |
1095 | break; | |
1096 | case mapRtNotFnd: | |
1097 | break; | |
1098 | default: | |
2d21ac55 | 1099 | panic("mapping_alloc: hw_purge_map failed - pmap = %p, va = %16llX, code = %p\n", ckpmap, va, mp); |
91447636 | 1100 | break; |
55e303ae A |
1101 | } |
1102 | ||
2d21ac55 | 1103 | if (mapRtNotFnd == ((unsigned int)mp & mapRetCode)) { |
55e303ae A |
1104 | if (do_rescan) |
1105 | do_rescan = FALSE; | |
1106 | else | |
1107 | break; | |
2d21ac55 | 1108 | } |
55e303ae A |
1109 | |
1110 | va = nextva; | |
1111 | } | |
1112 | } | |
1113 | ||
1114 | if (ckpmap == refpmap) { | |
1115 | if (found_mapping == FALSE) | |
1116 | panic("no valid pmap to purge mappings\n"); | |
1117 | else | |
1118 | found_mapping = FALSE; | |
1119 | } | |
1120 | ||
1121 | if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ | |
1122 | panic("mapping_alloc - timeout getting control lock\n"); /* Tell all and die */ | |
1123 | } | |
1124 | ||
9bccf70c | 1125 | } |
55e303ae A |
1126 | |
1127 | mapCtl.mapcflush.spacenum = ckpmap->spaceNum; | |
1128 | mapCtl.mapcflush.addr = nextva; | |
9bccf70c | 1129 | } |
55e303ae A |
1130 | |
1131 | simple_unlock(&free_pmap_lock); | |
1132 | } | |
1133 | ||
1134 | rescued: | |
1135 | ||
1136 | mb = mapCtl.mapcnext; | |
1137 | ||
1138 | if ( big ) { /* if we need a big (128-byte) mapping */ | |
1139 | mapCtl.mapcbig++; /* count attempts to allocate a big mapping */ | |
1140 | mbn = NULL; /* this will be prev ptr */ | |
1141 | mindx = 0; | |
1142 | while( mb ) { /* loop over mapping blocks with free entries */ | |
1143 | mindx = mapalc2(mb); /* try for 2 consequtive free bits in this block */ | |
1144 | ||
1145 | if ( mindx ) break; /* exit loop if we found them */ | |
1146 | mbn = mb; /* remember previous block */ | |
1147 | mb = mb->nextblok; /* move on to next block */ | |
1148 | } | |
1149 | if ( mindx == 0 ) { /* if we couldn't find 2 consequtive bits... */ | |
1150 | mapCtl.mapcbigfails++; /* count failures */ | |
1151 | big = 0; /* forget that we needed a big mapping */ | |
1152 | lists = mpBasicLists; /* clamp list count down to the max in a 64-byte mapping */ | |
1153 | mb = mapCtl.mapcnext; /* back to the first block with a free entry */ | |
1154 | } | |
1155 | else { /* if we did find a big mapping */ | |
1156 | mapCtl.mapcfree--; /* Decrement free count twice */ | |
1157 | mapCtl.mapcinuse++; /* Bump in use count twice */ | |
1158 | if ( mindx < 0 ) { /* if we just used the last 2 free bits in this block */ | |
1159 | if (mbn) { /* if this wasn't the first block */ | |
1160 | mindx = -mindx; /* make positive */ | |
1161 | mbn->nextblok = mb->nextblok; /* unlink this one from the middle of block list */ | |
1162 | if (mb == mapCtl.mapclast) { /* if we emptied last block */ | |
1163 | mapCtl.mapclast = mbn; /* then prev block is now last */ | |
1164 | } | |
1165 | } | |
1166 | } | |
1167 | } | |
1168 | } | |
1169 | ||
1170 | if ( !big ) { /* if we need a small (64-byte) mapping */ | |
1171 | if(!(mindx = mapalc1(mb))) /* Allocate a 1-bit slot */ | |
2d21ac55 | 1172 | panic("mapping_alloc - empty mapping block detected at %p\n", mb); |
55e303ae | 1173 | } |
1c79356b A |
1174 | |
1175 | if(mindx < 0) { /* Did we just take the last one */ | |
1176 | mindx = -mindx; /* Make positive */ | |
1177 | mapCtl.mapcnext = mb->nextblok; /* Remove us from the list */ | |
2d21ac55 | 1178 | if(!((unsigned int)mapCtl.mapcnext)) mapCtl.mapclast = NULL; /* Removed the last one */ |
1c79356b A |
1179 | } |
1180 | ||
1181 | mapCtl.mapcfree--; /* Decrement free count */ | |
1182 | mapCtl.mapcinuse++; /* Bump in use count */ | |
1183 | ||
1184 | mapCtl.mapcallocc++; /* Count total calls */ | |
1185 | ||
1186 | /* | |
1187 | * Note: in the following code, we will attempt to rescue blocks only one at a time. | |
1188 | * Eventually, after a few more mapping_alloc calls, we will catch up. If there are none | |
1189 | * rescueable, we will kick the misc scan who will allocate some for us. We only do this | |
1190 | * if we haven't already done it. | |
1191 | * For early boot, we are set up to only rescue one block at a time. This is because we prime | |
1192 | * the release list with as much as we need until threads start. | |
1193 | */ | |
55e303ae | 1194 | |
1c79356b | 1195 | if(mapCtl.mapcfree < mapCtl.mapcmin) { /* See if we need to replenish */ |
91447636 | 1196 | if((mbn = mapCtl.mapcrel) != 0) { /* Try to rescue a block from impending doom */ |
1c79356b A |
1197 | mapCtl.mapcrel = mbn->nextblok; /* Pop the queue */ |
1198 | mapCtl.mapcreln--; /* Back off the count */ | |
1199 | mapping_free_init((vm_offset_t)mbn, 0, 1); /* Initialize a non-permanent block */ | |
1200 | } | |
1201 | else { /* We need to replenish */ | |
1202 | if (mapCtl.mapcfree < (mapCtl.mapcmin / 4)) { | |
1203 | if(hw_compare_and_store(0, 1, &mapCtl.mapcrecurse)) { /* Make sure we aren't recursing */ | |
1204 | thread_call_enter(mapping_adjust_call); /* Go allocate some more */ | |
1205 | } | |
1206 | } | |
1207 | } | |
1208 | } | |
1209 | ||
1210 | hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ | |
1211 | splx(s); /* Restore 'rupts */ | |
1212 | ||
91447636 | 1213 | mp = &((mapping_t *)mb)[mindx]; /* Point to the allocated mapping */ |
55e303ae A |
1214 | mp->mpFlags = lists; /* set the list count */ |
1215 | ||
1216 | ||
1c79356b A |
1217 | return mp; /* Send it back... */ |
1218 | } | |
1219 | ||
1220 | ||
1221 | void | |
91447636 | 1222 | consider_mapping_adjust(void) |
1c79356b A |
1223 | { |
1224 | spl_t s; | |
1225 | ||
1226 | s = splhigh(); /* Don't bother from now on */ | |
1227 | if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ | |
55e303ae | 1228 | panic("consider_mapping_adjust -- lock timeout\n"); |
1c79356b A |
1229 | } |
1230 | ||
1231 | if (mapCtl.mapcfree < (mapCtl.mapcmin / 4)) { | |
1232 | if(hw_compare_and_store(0, 1, &mapCtl.mapcrecurse)) { /* Make sure we aren't recursing */ | |
1233 | thread_call_enter(mapping_adjust_call); /* Go allocate some more */ | |
1234 | } | |
1235 | } | |
1236 | ||
1237 | hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ | |
1238 | splx(s); /* Restore 'rupts */ | |
1239 | ||
1240 | } | |
1241 | ||
1242 | ||
1243 | ||
1244 | /* | |
1245 | * void mapping_free_init(mb, perm) - Adds a block of storage to the free mapping list | |
1246 | * | |
55e303ae A |
1247 | * The mapping block is a page size area on a page boundary. It contains 1 header and 63 |
1248 | * mappings. This call adds and initializes a block for use. Mappings come in two sizes, | |
1249 | * 64 and 128 bytes (the only difference is the number of skip-lists.) When we allocate a | |
1250 | * 128-byte mapping we just look for two consequtive free 64-byte mappings, so most of the | |
1251 | * code only deals with "basic" 64-byte mappings. This works for two reasons: | |
1252 | * - Only one in 256 mappings is big, so they are rare. | |
1253 | * - If we cannot find two consequtive free mappings, we just return a small one. | |
1254 | * There is no problem with doing this, except a minor performance degredation. | |
1255 | * Therefore, all counts etc in the mapping control structure are in units of small blocks. | |
1c79356b A |
1256 | * |
1257 | * The header contains a chain link, bit maps, a virtual to real translation mask, and | |
1258 | * some statistics. Bit maps map each slot on the page (bit 0 is not used because it | |
1259 | * corresponds to the header). The translation mask is the XOR of the virtual and real | |
1260 | * addresses (needless to say, the block must be wired). | |
1261 | * | |
1262 | * We handle these mappings the same way as saveareas: the block is only on the chain so | |
1263 | * long as there are free entries in it. | |
1264 | * | |
1265 | * Empty blocks are garbage collected when there are at least mapCtl.mapcmin pages worth of free | |
1266 | * mappings. Blocks marked PERM won't ever be released. | |
1267 | * | |
1268 | * If perm is negative, the mapping is initialized, but immediately queued to the mapCtl.mapcrel | |
1269 | * list. We do this only at start up time. This is done because we only allocate blocks | |
1270 | * in the pageout scan and it doesn't start up until after we run out of the initial mappings. | |
1271 | * Therefore, we need to preallocate a bunch, but we don't want them to be permanent. If we put | |
1272 | * them on the release queue, the allocate routine will rescue them. Then when the | |
1273 | * pageout scan starts, all extra ones will be released. | |
1274 | * | |
1275 | */ | |
1276 | ||
1277 | ||
1278 | void mapping_free_init(vm_offset_t mbl, int perm, boolean_t locked) { | |
1279 | /* Set's start and end of a block of mappings | |
1280 | perm indicates if the block can be released | |
1281 | or goes straight to the release queue . | |
1282 | locked indicates if the lock is held already */ | |
1283 | ||
91447636 | 1284 | mappingblok_t *mb; |
1c79356b | 1285 | spl_t s; |
55e303ae A |
1286 | addr64_t raddr; |
1287 | ppnum_t pp; | |
1c79356b | 1288 | |
91447636 | 1289 | mb = (mappingblok_t *)mbl; /* Start of area */ |
1c79356b A |
1290 | |
1291 | if(perm >= 0) { /* See if we need to initialize the block */ | |
1292 | if(perm) { | |
55e303ae | 1293 | raddr = (addr64_t)((unsigned int)mbl); /* Perm means V=R */ |
1c79356b | 1294 | mb->mapblokflags = mbPerm; /* Set perm */ |
55e303ae | 1295 | // mb->mapblokflags |= (unsigned int)mb; /* (BRINGUP) */ |
1c79356b A |
1296 | } |
1297 | else { | |
55e303ae A |
1298 | pp = pmap_find_phys(kernel_pmap, (addr64_t)mbl); /* Get the physical page */ |
1299 | if(!pp) { /* What gives? Where's the page? */ | |
1300 | panic("mapping_free_init: could not find translation for vaddr %016llX\n", (addr64_t)mbl); | |
1301 | } | |
1302 | ||
1303 | raddr = (addr64_t)pp << 12; /* Convert physical page to physical address */ | |
1c79356b | 1304 | mb->mapblokflags = 0; /* Set not perm */ |
55e303ae | 1305 | // mb->mapblokflags |= (unsigned int)mb; /* (BRINGUP) */ |
1c79356b A |
1306 | } |
1307 | ||
55e303ae | 1308 | mb->mapblokvrswap = raddr ^ (addr64_t)((unsigned int)mbl); /* Form translation mask */ |
1c79356b A |
1309 | |
1310 | mb->mapblokfree[0] = 0x7FFFFFFF; /* Set first 32 (minus 1) free */ | |
1311 | mb->mapblokfree[1] = 0xFFFFFFFF; /* Set next 32 free */ | |
1c79356b A |
1312 | } |
1313 | ||
1314 | s = splhigh(); /* Don't bother from now on */ | |
1315 | if(!locked) { /* Do we need the lock? */ | |
1316 | if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ | |
55e303ae | 1317 | panic("mapping_free_init: timeout getting control lock\n"); /* Tell all and die */ |
1c79356b A |
1318 | } |
1319 | } | |
1320 | ||
1321 | if(perm < 0) { /* Direct to release queue? */ | |
1322 | mb->nextblok = mapCtl.mapcrel; /* Move forward pointer */ | |
1323 | mapCtl.mapcrel = mb; /* Queue us on in */ | |
1324 | mapCtl.mapcreln++; /* Count the free block */ | |
1325 | } | |
1326 | else { /* Add to the free list */ | |
1327 | ||
2d21ac55 | 1328 | mb->nextblok = NULL; /* We always add to the end */ |
1c79356b A |
1329 | mapCtl.mapcfree += MAPPERBLOK; /* Bump count */ |
1330 | ||
1331 | if(!((unsigned int)mapCtl.mapcnext)) { /* First entry on list? */ | |
1332 | mapCtl.mapcnext = mapCtl.mapclast = mb; /* Chain to us */ | |
1333 | } | |
1334 | else { /* We are not the first */ | |
1335 | mapCtl.mapclast->nextblok = mb; /* Point the last to us */ | |
1336 | mapCtl.mapclast = mb; /* We are now last */ | |
1337 | } | |
1338 | } | |
1339 | ||
1340 | if(!locked) { /* Do we need to unlock? */ | |
1341 | hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ | |
1342 | } | |
55e303ae A |
1343 | |
1344 | splx(s); /* Restore 'rupts */ | |
1c79356b A |
1345 | return; /* All done, leave... */ |
1346 | } | |
1347 | ||
1348 | ||
1349 | /* | |
1350 | * void mapping_prealloc(unsigned int) - Preallocates mapppings for large request | |
1351 | * | |
1352 | * No locks can be held, because we allocate memory here. | |
1353 | * This routine needs a corresponding mapping_relpre call to remove the | |
1354 | * hold off flag so that the adjust routine will free the extra mapping | |
1355 | * blocks on the release list. I don't like this, but I don't know | |
1356 | * how else to do this for now... | |
1357 | * | |
1358 | */ | |
1359 | ||
1360 | void mapping_prealloc(unsigned int size) { /* Preallocates mapppings for large request */ | |
1361 | ||
1362 | int nmapb, i; | |
1363 | kern_return_t retr; | |
91447636 | 1364 | mappingblok_t *mbn; |
1c79356b A |
1365 | spl_t s; |
1366 | ||
1367 | s = splhigh(); /* Don't bother from now on */ | |
1368 | if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ | |
1369 | panic("mapping_prealloc - timeout getting control lock\n"); /* Tell all and die */ | |
1370 | } | |
1371 | ||
1372 | nmapb = (size >> 12) + mapCtl.mapcmin; /* Get number of entries needed for this and the minimum */ | |
1373 | ||
1374 | mapCtl.mapcholdoff++; /* Bump the hold off count */ | |
1375 | ||
1376 | if((nmapb = (nmapb - mapCtl.mapcfree)) <= 0) { /* Do we already have enough? */ | |
1377 | hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ | |
1378 | splx(s); /* Restore 'rupts */ | |
1379 | return; | |
1380 | } | |
55e303ae | 1381 | if (!hw_compare_and_store(0, 1, &mapCtl.mapcrecurse)) { /* Make sure we aren't recursing */ |
1c79356b | 1382 | hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ |
55e303ae | 1383 | splx(s); /* Restore 'rupts */ |
1c79356b A |
1384 | return; |
1385 | } | |
1386 | nmapb = (nmapb + MAPPERBLOK - 1) / MAPPERBLOK; /* Get number of blocks to get */ | |
1387 | ||
1388 | hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ | |
1389 | splx(s); /* Restore 'rupts */ | |
1390 | ||
1391 | for(i = 0; i < nmapb; i++) { /* Allocate 'em all */ | |
1392 | retr = kmem_alloc_wired(mapping_map, (vm_offset_t *)&mbn, PAGE_SIZE); /* Find a virtual address to use */ | |
55e303ae | 1393 | if(retr != KERN_SUCCESS) /* Did we get some memory? */ |
d7e50217 | 1394 | break; |
1c79356b A |
1395 | mapping_free_init((vm_offset_t)mbn, -1, 0); /* Initialize on to the release queue */ |
1396 | } | |
1397 | if ((mapCtl.mapcinuse + mapCtl.mapcfree + (mapCtl.mapcreln * (MAPPERBLOK + 1))) > mapCtl.mapcmaxalloc) | |
1398 | mapCtl.mapcmaxalloc = mapCtl.mapcinuse + mapCtl.mapcfree + (mapCtl.mapcreln * (MAPPERBLOK + 1)); | |
1399 | ||
1400 | mapCtl.mapcrecurse = 0; /* We are done now */ | |
1401 | } | |
1402 | ||
1403 | /* | |
1404 | * void mapping_relpre(void) - Releases preallocation release hold off | |
1405 | * | |
1406 | * This routine removes the | |
1407 | * hold off flag so that the adjust routine will free the extra mapping | |
1408 | * blocks on the release list. I don't like this, but I don't know | |
1409 | * how else to do this for now... | |
1410 | * | |
1411 | */ | |
1412 | ||
1413 | void mapping_relpre(void) { /* Releases release hold off */ | |
1414 | ||
1415 | spl_t s; | |
1416 | ||
1417 | s = splhigh(); /* Don't bother from now on */ | |
1418 | if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */ | |
1419 | panic("mapping_relpre - timeout getting control lock\n"); /* Tell all and die */ | |
1420 | } | |
1421 | if(--mapCtl.mapcholdoff < 0) { /* Back down the hold off count */ | |
1422 | panic("mapping_relpre: hold-off count went negative\n"); | |
1423 | } | |
1424 | ||
1425 | hw_lock_unlock((hw_lock_t)&mapCtl.mapclock); /* Unlock our stuff */ | |
1426 | splx(s); /* Restore 'rupts */ | |
1427 | } | |
1428 | ||
1429 | /* | |
1430 | * void mapping_free_prime(void) - Primes the mapping block release list | |
1431 | * | |
1432 | * See mapping_free_init. | |
1433 | * No locks can be held, because we allocate memory here. | |
1434 | * One processor running only. | |
1435 | * | |
1436 | */ | |
1437 | ||
1438 | void mapping_free_prime(void) { /* Primes the mapping block release list */ | |
1439 | ||
1440 | int nmapb, i; | |
1441 | kern_return_t retr; | |
91447636 | 1442 | mappingblok_t *mbn; |
1c79356b A |
1443 | vm_offset_t mapping_min; |
1444 | ||
55e303ae | 1445 | retr = kmem_suballoc(kernel_map, &mapping_min, sane_size / 16, |
91447636 | 1446 | FALSE, VM_FLAGS_ANYWHERE, &mapping_map); |
1c79356b A |
1447 | |
1448 | if (retr != KERN_SUCCESS) | |
1449 | panic("mapping_free_prime: kmem_suballoc failed"); | |
1450 | ||
1451 | ||
1452 | nmapb = (mapCtl.mapcfree + mapCtl.mapcinuse + MAPPERBLOK - 1) / MAPPERBLOK; /* Get permanent allocation */ | |
1453 | nmapb = nmapb * 4; /* Get 4 times our initial allocation */ | |
1454 | ||
1455 | #if DEBUG | |
1456 | kprintf("mapping_free_prime: free = %08X; in use = %08X; priming = %08X\n", | |
1457 | mapCtl.mapcfree, mapCtl.mapcinuse, nmapb); | |
1458 | #endif | |
1459 | ||
1460 | for(i = 0; i < nmapb; i++) { /* Allocate 'em all */ | |
1461 | retr = kmem_alloc_wired(mapping_map, (vm_offset_t *)&mbn, PAGE_SIZE); /* Find a virtual address to use */ | |
1462 | if(retr != KERN_SUCCESS) { /* Did we get some memory? */ | |
1463 | panic("Whoops... Not a bit of wired memory left for anyone\n"); | |
1464 | } | |
1465 | mapping_free_init((vm_offset_t)mbn, -1, 0); /* Initialize onto release queue */ | |
1466 | } | |
1467 | if ((mapCtl.mapcinuse + mapCtl.mapcfree + (mapCtl.mapcreln * (MAPPERBLOK + 1))) > mapCtl.mapcmaxalloc) | |
1468 | mapCtl.mapcmaxalloc = mapCtl.mapcinuse + mapCtl.mapcfree + (mapCtl.mapcreln * (MAPPERBLOK + 1)); | |
1469 | } | |
1470 | ||
1471 | ||
91447636 | 1472 | void |
1c79356b A |
1473 | mapping_fake_zone_info(int *count, vm_size_t *cur_size, vm_size_t *max_size, vm_size_t *elem_size, |
1474 | vm_size_t *alloc_size, int *collectable, int *exhaustable) | |
1475 | { | |
1476 | *count = mapCtl.mapcinuse; | |
1477 | *cur_size = ((PAGE_SIZE / (MAPPERBLOK + 1)) * (mapCtl.mapcinuse + mapCtl.mapcfree)) + (PAGE_SIZE * mapCtl.mapcreln); | |
1478 | *max_size = (PAGE_SIZE / (MAPPERBLOK + 1)) * mapCtl.mapcmaxalloc; | |
1479 | *elem_size = (PAGE_SIZE / (MAPPERBLOK + 1)); | |
1480 | *alloc_size = PAGE_SIZE; | |
1481 | ||
1482 | *collectable = 1; | |
1483 | *exhaustable = 0; | |
1484 | } | |
1485 | ||
1486 | ||
1487 | /* | |
55e303ae | 1488 | * addr64_t mapping_p2v(pmap_t pmap, ppnum_t pa) - Finds first virtual mapping of a physical page in a space |
1c79356b | 1489 | * |
55e303ae A |
1490 | * First looks up the physical entry associated witht the physical page. Then searches the alias |
1491 | * list for a matching pmap. It grabs the virtual address from the mapping, drops busy, and returns | |
1492 | * that. | |
1c79356b | 1493 | * |
1c79356b A |
1494 | */ |
1495 | ||
55e303ae | 1496 | addr64_t mapping_p2v(pmap_t pmap, ppnum_t pa) { /* Finds first virtual mapping of a physical page in a space */ |
1c79356b | 1497 | |
55e303ae | 1498 | spl_t s; |
91447636 | 1499 | mapping_t *mp; |
55e303ae | 1500 | unsigned int pindex; |
91447636 | 1501 | phys_entry_t *physent; |
55e303ae | 1502 | addr64_t va; |
de355530 | 1503 | |
55e303ae A |
1504 | physent = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ |
1505 | if(!physent) { /* Did we find the physical page? */ | |
1506 | panic("mapping_p2v: invalid physical page %08X\n", pa); | |
1c79356b | 1507 | } |
1c79356b | 1508 | |
55e303ae | 1509 | s = splhigh(); /* Make sure interruptions are disabled */ |
1c79356b | 1510 | |
91447636 | 1511 | mp = hw_find_space(physent, pmap->space); /* Go find the first mapping to the page from the requested pmap */ |
1c79356b | 1512 | |
55e303ae A |
1513 | if(mp) { /* Did we find one? */ |
1514 | va = mp->mpVAddr & -4096; /* If so, get the cleaned up vaddr */ | |
1515 | mapping_drop_busy(mp); /* Go ahead and relase the mapping now */ | |
1c79356b | 1516 | } |
55e303ae | 1517 | else va = 0; /* Return failure */ |
1c79356b | 1518 | |
55e303ae | 1519 | splx(s); /* Restore 'rupts */ |
1c79356b | 1520 | |
55e303ae | 1521 | return va; /* Bye, bye... */ |
1c79356b | 1522 | |
1c79356b A |
1523 | } |
1524 | ||
55e303ae A |
1525 | |
1526 | /* | |
1527 | * kvtophys(addr) | |
1528 | * | |
1529 | * Convert a kernel virtual address to a physical address | |
1530 | */ | |
0c530ab8 | 1531 | addr64_t kvtophys(vm_offset_t va) { |
55e303ae A |
1532 | |
1533 | return pmap_extract(kernel_pmap, va); /* Find mapping and lock the physical entry for this mapping */ | |
1c79356b A |
1534 | |
1535 | } | |
1536 | ||
2d21ac55 A |
1537 | /* |
1538 | * kvtophys64(addr) | |
1539 | * | |
1540 | * Convert a kernel virtual address to a 64-bit physical address | |
1541 | */ | |
1542 | vm_map_offset_t kvtophys64(vm_map_offset_t va) { | |
1543 | ||
1544 | ppnum_t pa = pmap_find_phys(kernel_pmap, (addr64_t)va); | |
1545 | ||
1546 | if (!pa) | |
1547 | return 0; | |
1548 | return (((vm_map_offset_t)pa) << 12) | (va & 0xfff); | |
1549 | ||
1550 | } | |
1551 | ||
1c79356b A |
1552 | /* |
1553 | * void ignore_zero_fault(boolean_t) - Sets up to ignore or honor any fault on | |
1554 | * page 0 access for the current thread. | |
1555 | * | |
1556 | * If parameter is TRUE, faults are ignored | |
1557 | * If parameter is FALSE, faults are honored | |
1558 | * | |
1559 | */ | |
1560 | ||
1561 | void ignore_zero_fault(boolean_t type) { /* Sets up to ignore or honor any fault on page 0 access for the current thread */ | |
1562 | ||
91447636 A |
1563 | if(type) current_thread()->machine.specFlags |= ignoreZeroFault; /* Ignore faults on page 0 */ |
1564 | else current_thread()->machine.specFlags &= ~ignoreZeroFault; /* Honor faults on page 0 */ | |
1c79356b A |
1565 | |
1566 | return; /* Return the result or 0... */ | |
1567 | } | |
1568 | ||
0c530ab8 | 1569 | /* |
2d21ac55 | 1570 | * no-op in current ppc implementation |
0c530ab8 | 1571 | */ |
2d21ac55 | 1572 | void inval_copy_windows(__unused thread_t th) |
0c530ab8 A |
1573 | { |
1574 | } | |
1575 | ||
1c79356b | 1576 | |
55e303ae A |
1577 | /* |
1578 | * Copies data between a physical page and a virtual page, or 2 physical. This is used to | |
1579 | * move data from the kernel to user state. Note that the "which" parm | |
1580 | * says which of the parameters is physical and if we need to flush sink/source. | |
91447636 | 1581 | * Note that both addresses may be physical, but only one may be virtual. |
1c79356b | 1582 | * |
55e303ae | 1583 | * The rules are that the size can be anything. Either address can be on any boundary |
91447636 | 1584 | * and span pages. The physical data must be contiguous as must the virtual. |
1c79356b | 1585 | * |
55e303ae A |
1586 | * We can block when we try to resolve the virtual address at each page boundary. |
1587 | * We don't check protection on the physical page. | |
1c79356b | 1588 | * |
55e303ae A |
1589 | * Note that we will not check the entire range and if a page translation fails, |
1590 | * we will stop with partial contents copied. | |
1c79356b A |
1591 | * |
1592 | */ | |
1593 | ||
2d21ac55 A |
1594 | kern_return_t |
1595 | hw_copypv_32(addr64_t source, addr64_t sink, unsigned int size, int which) | |
1596 | { | |
1c79356b A |
1597 | vm_map_t map; |
1598 | kern_return_t ret; | |
2d21ac55 A |
1599 | addr64_t nextva, vaddr = 0, paddr; |
1600 | mapping_t *mp = NULL; | |
1c79356b | 1601 | spl_t s; |
91447636 | 1602 | unsigned int lop, csize; |
55e303ae A |
1603 | int needtran, bothphys; |
1604 | unsigned int pindex; | |
91447636 | 1605 | phys_entry_t *physent; |
2d21ac55 | 1606 | vm_prot_t prot = 0; |
55e303ae | 1607 | int orig_which; |
1c79356b | 1608 | |
55e303ae | 1609 | orig_which = which; |
1c79356b | 1610 | |
55e303ae | 1611 | map = (which & cppvKmap) ? kernel_map : current_map_fast(); |
1c79356b | 1612 | |
55e303ae A |
1613 | if((which & (cppvPsrc | cppvPsnk)) == 0 ) { /* Make sure that only one is virtual */ |
1614 | panic("copypv: no more than 1 parameter may be virtual\n"); /* Not allowed */ | |
1615 | } | |
1616 | ||
1617 | bothphys = 1; /* Assume both are physical */ | |
1618 | ||
91447636 | 1619 | if(!(which & cppvPsnk)) { /* Is sink page virtual? */ |
55e303ae A |
1620 | vaddr = sink; /* Sink side is virtual */ |
1621 | bothphys = 0; /* Show both aren't physical */ | |
1622 | prot = VM_PROT_READ | VM_PROT_WRITE; /* Sink always must be read/write */ | |
91447636 | 1623 | } else if (!(which & cppvPsrc)) { /* Is source page virtual? */ |
55e303ae A |
1624 | vaddr = source; /* Source side is virtual */ |
1625 | bothphys = 0; /* Show both aren't physical */ | |
1626 | prot = VM_PROT_READ; /* Virtual source is always read only */ | |
1627 | } | |
1c79356b | 1628 | |
55e303ae A |
1629 | needtran = 1; /* Show we need to map the virtual the first time */ |
1630 | s = splhigh(); /* Don't bother me */ | |
1c79356b | 1631 | |
55e303ae | 1632 | while(size) { |
de355530 | 1633 | |
55e303ae A |
1634 | if(!bothphys && (needtran || !(vaddr & 4095LL))) { /* If first time or we stepped onto a new page, we need to translate */ |
1635 | if(!needtran) { /* If this is not the first translation, we need to drop the old busy */ | |
1636 | mapping_drop_busy(mp); /* Release the old mapping now */ | |
1637 | } | |
1638 | needtran = 0; | |
1639 | ||
1640 | while(1) { | |
1641 | mp = mapping_find(map->pmap, vaddr, &nextva, 1); /* Find and busy the mapping */ | |
1642 | if(!mp) { /* Was it there? */ | |
91447636 | 1643 | if(getPerProc()->istackptr == 0) |
2d21ac55 | 1644 | panic("copypv: No vaild mapping on memory %s %16llx", "RD", vaddr); |
55e303ae A |
1645 | |
1646 | splx(s); /* Restore the interrupt level */ | |
91447636 | 1647 | ret = vm_fault(map, vm_map_trunc_page(vaddr), prot, FALSE, THREAD_UNINT, NULL, 0); /* Didn't find it, try to fault it in... */ |
55e303ae A |
1648 | |
1649 | if(ret != KERN_SUCCESS)return KERN_FAILURE; /* Didn't find any, return no good... */ | |
1650 | ||
1651 | s = splhigh(); /* Don't bother me */ | |
1652 | continue; /* Go try for the map again... */ | |
1653 | ||
1654 | } | |
1655 | if (mp->mpVAddr & mpI) { /* cache inhibited, so force the appropriate page to be flushed before */ | |
1656 | if (which & cppvPsrc) /* and after the copy to avoid cache paradoxes */ | |
1657 | which |= cppvFsnk; | |
1658 | else | |
1659 | which |= cppvFsrc; | |
1660 | } else | |
1661 | which = orig_which; | |
1662 | ||
1663 | /* Note that we have to have the destination writable. So, if we already have it, or we are mapping the source, | |
1664 | we can just leave. | |
1665 | */ | |
1666 | if((which & cppvPsnk) || !(mp->mpVAddr & 1)) break; /* We got it mapped R/W or the source is not virtual, leave... */ | |
1667 | ||
1668 | mapping_drop_busy(mp); /* Go ahead and release the mapping for now */ | |
91447636 | 1669 | if(getPerProc()->istackptr == 0) |
2d21ac55 | 1670 | panic("copypv: No vaild mapping on memory %s %16llx", "RDWR", vaddr); |
55e303ae A |
1671 | splx(s); /* Restore the interrupt level */ |
1672 | ||
91447636 | 1673 | ret = vm_fault(map, vm_map_trunc_page(vaddr), VM_PROT_READ | VM_PROT_WRITE, FALSE, THREAD_UNINT, NULL, 0); /* check for a COW area */ |
55e303ae A |
1674 | if (ret != KERN_SUCCESS) return KERN_FAILURE; /* We couldn't get it R/W, leave in disgrace... */ |
1675 | s = splhigh(); /* Don't bother me */ | |
1676 | } | |
1677 | paddr = ((addr64_t)mp->mpPAddr << 12) + (vaddr - (mp->mpVAddr & -4096LL)); /* construct the physical address... this calculation works */ | |
1678 | /* properly on both single page and block mappings */ | |
1679 | if(which & cppvPsrc) sink = paddr; /* If source is physical, then the sink is virtual */ | |
1680 | else source = paddr; /* Otherwise the source is */ | |
1c79356b | 1681 | } |
55e303ae A |
1682 | |
1683 | lop = (unsigned int)(4096LL - (sink & 4095LL)); /* Assume sink smallest */ | |
1684 | if(lop > (unsigned int)(4096LL - (source & 4095LL))) lop = (unsigned int)(4096LL - (source & 4095LL)); /* No, source is smaller */ | |
1685 | ||
1686 | csize = size; /* Assume we can copy it all */ | |
1687 | if(lop < size) csize = lop; /* Nope, we can't do it all */ | |
1688 | ||
1689 | if(which & cppvFsrc) flush_dcache64(source, csize, 1); /* If requested, flush source before move */ | |
1690 | if(which & cppvFsnk) flush_dcache64(sink, csize, 1); /* If requested, flush sink before move */ | |
1c79356b | 1691 | |
91447636 | 1692 | bcopy_physvir_32(source, sink, csize); /* Do a physical copy, virtually */ |
55e303ae A |
1693 | |
1694 | if(which & cppvFsrc) flush_dcache64(source, csize, 1); /* If requested, flush source after move */ | |
1695 | if(which & cppvFsnk) flush_dcache64(sink, csize, 1); /* If requested, flush sink after move */ | |
1c79356b | 1696 | |
b4c24cb9 | 1697 | /* |
55e303ae A |
1698 | * Note that for certain ram disk flavors, we may be copying outside of known memory. |
1699 | * Therefore, before we try to mark it modifed, we check if it exists. | |
b4c24cb9 A |
1700 | */ |
1701 | ||
55e303ae A |
1702 | if( !(which & cppvNoModSnk)) { |
1703 | physent = mapping_phys_lookup(sink >> 12, &pindex); /* Get physical entry for sink */ | |
1704 | if(physent) mapping_set_mod((ppnum_t)(sink >> 12)); /* Make sure we know that it is modified */ | |
1705 | } | |
1706 | if( !(which & cppvNoRefSrc)) { | |
1707 | physent = mapping_phys_lookup(source >> 12, &pindex); /* Get physical entry for source */ | |
1708 | if(physent) mapping_set_ref((ppnum_t)(source >> 12)); /* Make sure we know that it is modified */ | |
1709 | } | |
1710 | size = size - csize; /* Calculate what is left */ | |
1711 | vaddr = vaddr + csize; /* Move to next sink address */ | |
1712 | source = source + csize; /* Bump source to next physical address */ | |
1713 | sink = sink + csize; /* Bump sink to next physical address */ | |
b4c24cb9 | 1714 | } |
55e303ae A |
1715 | |
1716 | if(!bothphys) mapping_drop_busy(mp); /* Go ahead and release the mapping of the virtual page if any */ | |
1717 | splx(s); /* Open up for interrupts */ | |
b4c24cb9 | 1718 | |
55e303ae | 1719 | return KERN_SUCCESS; |
b4c24cb9 A |
1720 | } |
1721 | ||
1722 | ||
1c79356b | 1723 | /* |
55e303ae | 1724 | * Debug code |
1c79356b | 1725 | */ |
1c79356b | 1726 | |
55e303ae | 1727 | void mapping_verify(void) { |
1c79356b | 1728 | |
55e303ae | 1729 | spl_t s; |
91447636 A |
1730 | mappingblok_t *mb, *mbn; |
1731 | unsigned int relncnt; | |
55e303ae | 1732 | unsigned int dumbodude; |
de355530 | 1733 | |
55e303ae A |
1734 | dumbodude = 0; |
1735 | ||
1736 | s = splhigh(); /* Don't bother from now on */ | |
de355530 | 1737 | |
2d21ac55 | 1738 | mbn = NULL; /* Start with none */ |
55e303ae | 1739 | for(mb = mapCtl.mapcnext; mb; mb = mb->nextblok) { /* Walk the free chain */ |
91447636 | 1740 | if((mappingblok_t *)(mb->mapblokflags & 0x7FFFFFFF) != mb) { /* Is tag ok? */ |
2d21ac55 | 1741 | panic("mapping_verify: flags tag bad, free chain; mb = %p, tag = %08X\n", mb, mb->mapblokflags); |
55e303ae A |
1742 | } |
1743 | mbn = mb; /* Remember the last one */ | |
1c79356b | 1744 | } |
55e303ae A |
1745 | |
1746 | if(mapCtl.mapcnext && (mapCtl.mapclast != mbn)) { /* Do we point to the last one? */ | |
2d21ac55 | 1747 | panic("mapping_verify: last pointer bad; mb = %p, mapclast = %p\n", mb, mapCtl.mapclast); |
1c79356b A |
1748 | } |
1749 | ||
55e303ae A |
1750 | relncnt = 0; /* Clear count */ |
1751 | for(mb = mapCtl.mapcrel; mb; mb = mb->nextblok) { /* Walk the release chain */ | |
1752 | dumbodude |= mb->mapblokflags; /* Just touch it to make sure it is mapped */ | |
1753 | relncnt++; /* Count this one */ | |
1754 | } | |
1c79356b | 1755 | |
55e303ae A |
1756 | if(mapCtl.mapcreln != relncnt) { /* Is the count on release queue ok? */ |
1757 | panic("mapping_verify: bad release queue count; mapcreln = %d, cnt = %d, ignore this = %08X\n", mapCtl.mapcreln, relncnt, dumbodude); | |
1758 | } | |
1c79356b | 1759 | |
55e303ae | 1760 | splx(s); /* Restore 'rupts */ |
1c79356b | 1761 | |
1c79356b A |
1762 | return; |
1763 | } | |
1764 | ||
55e303ae | 1765 | void mapping_phys_unused(ppnum_t pa) { |
1c79356b | 1766 | |
55e303ae | 1767 | unsigned int pindex; |
91447636 | 1768 | phys_entry_t *physent; |
1c79356b | 1769 | |
55e303ae A |
1770 | physent = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ |
1771 | if(!physent) return; /* Did we find the physical page? */ | |
1c79356b | 1772 | |
91447636 | 1773 | if(!(physent->ppLink & ~(ppLock | ppFlags))) return; /* No one else is here */ |
1c79356b | 1774 | |
2d21ac55 | 1775 | panic("mapping_phys_unused: physical page (%08X) in use, physent = %p\n", pa, physent); |
1c79356b | 1776 | |
de355530 | 1777 | } |
d7e50217 | 1778 | |
2d21ac55 A |
1779 | void |
1780 | mapping_hibernate_flush(void) | |
3a60a9f5 | 1781 | { |
2d21ac55 | 1782 | unsigned int page, bank; |
3a60a9f5 A |
1783 | struct phys_entry * entry; |
1784 | ||
1785 | for (bank = 0; bank < pmap_mem_regions_count; bank++) | |
1786 | { | |
1787 | entry = (struct phys_entry *) pmap_mem_regions[bank].mrPhysTab; | |
1788 | for (page = pmap_mem_regions[bank].mrStart; page <= pmap_mem_regions[bank].mrEnd; page++) | |
1789 | { | |
1790 | hw_walk_phys(entry, hwpNoop, hwpNoop, hwpNoop, 0, hwpPurgePTE); | |
1791 | entry++; | |
1792 | } | |
1793 | } | |
1794 | } | |
1795 | ||
91447636 A |
1796 | |
1797 | ||
1798 | ||
1799 | ||
1800 |