]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
2d21ac55 | 2 | * Copyright (c) 2000-2007 Apple 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 | * @OSF_COPYRIGHT@ | |
30 | */ | |
31 | /* | |
32 | * Mach Operating System | |
33 | * Copyright (c) 1990,1991,1992 The University of Utah and | |
34 | * the Center for Software Science (CSS). | |
35 | * Copyright (c) 1991,1987 Carnegie Mellon University. | |
36 | * All rights reserved. | |
37 | * | |
38 | * Permission to use, copy, modify and distribute this software and its | |
39 | * documentation is hereby granted, provided that both the copyright | |
40 | * notice and this permission notice appear in all copies of the | |
41 | * software, derivative works or modified versions, and any portions | |
42 | * thereof, and that both notices appear in supporting documentation, | |
43 | * and that all advertising materials mentioning features or use of | |
44 | * this software display the following acknowledgement: ``This product | |
45 | * includes software developed by the Center for Software Science at | |
46 | * the University of Utah.'' | |
47 | * | |
48 | * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSS ALLOW FREE USE OF | |
49 | * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY | |
50 | * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF | |
51 | * THIS SOFTWARE. | |
52 | * | |
53 | * CSS requests users of this software to return to css-dist@cs.utah.edu any | |
54 | * improvements that they make and grant CSS redistribution rights. | |
55 | * | |
56 | * Carnegie Mellon requests users of this software to return to | |
57 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
58 | * School of Computer Science | |
59 | * Carnegie Mellon University | |
60 | * Pittsburgh PA 15213-3890 | |
61 | * any improvements or extensions that they make and grant Carnegie Mellon | |
62 | * the rights to redistribute these changes. | |
63 | * | |
64 | * Utah $Hdr: pmap.c 1.28 92/06/23$ | |
65 | * Author: Mike Hibler, Bob Wheeler, University of Utah CSS, 10/90 | |
66 | */ | |
67 | ||
68 | /* | |
69 | * Manages physical address maps for powerpc. | |
70 | * | |
71 | * In addition to hardware address maps, this | |
72 | * module is called upon to provide software-use-only | |
73 | * maps which may or may not be stored in the same | |
74 | * form as hardware maps. These pseudo-maps are | |
75 | * used to store intermediate results from copy | |
76 | * operations to and from address spaces. | |
77 | * | |
78 | * Since the information managed by this module is | |
79 | * also stored by the logical address mapping module, | |
80 | * this module may throw away valid virtual-to-physical | |
81 | * mappings at almost any time. However, invalidations | |
82 | * of virtual-to-physical mappings must be done as | |
83 | * requested. | |
84 | * | |
85 | * In order to cope with hardware architectures which | |
86 | * make virtual-to-physical map invalidates expensive, | |
87 | * this module may delay invalidate or reduced protection | |
88 | * operations until such time as they are actually | |
89 | * necessary. This module is given full information to | |
90 | * when physical maps must be made correct. | |
91 | * | |
92 | */ | |
93 | ||
94 | #include <zone_debug.h> | |
1c79356b A |
95 | #include <debug.h> |
96 | #include <mach_kgdb.h> | |
97 | #include <mach_vm_debug.h> | |
98 | #include <db_machine_commands.h> | |
99 | ||
100 | #include <kern/thread.h> | |
9bccf70c | 101 | #include <kern/simple_lock.h> |
1c79356b A |
102 | #include <mach/vm_attributes.h> |
103 | #include <mach/vm_param.h> | |
55e303ae | 104 | #include <vm/vm_kern.h> |
1c79356b A |
105 | #include <kern/spl.h> |
106 | ||
107 | #include <kern/misc_protos.h> | |
108 | #include <ppc/misc_protos.h> | |
109 | #include <ppc/proc_reg.h> | |
110 | ||
111 | #include <vm/pmap.h> | |
112 | #include <vm/vm_map.h> | |
113 | #include <vm/vm_page.h> | |
114 | ||
115 | #include <ppc/pmap.h> | |
1c79356b A |
116 | #include <ppc/mem.h> |
117 | #include <ppc/mappings.h> | |
118 | ||
119 | #include <ppc/new_screen.h> | |
120 | #include <ppc/Firmware.h> | |
121 | #include <ppc/savearea.h> | |
91447636 | 122 | #include <ppc/cpu_internal.h> |
9bccf70c | 123 | #include <ppc/exception.h> |
55e303ae | 124 | #include <ppc/low_trace.h> |
91447636 | 125 | #include <ppc/lowglobals.h> |
2d21ac55 | 126 | #include <ppc/limits.h> |
1c79356b | 127 | #include <ddb/db_output.h> |
91447636 A |
128 | #include <machine/cpu_capabilities.h> |
129 | ||
130 | #include <vm/vm_protos.h> /* must be last */ | |
131 | ||
1c79356b | 132 | |
1c79356b | 133 | extern unsigned int avail_remaining; |
55e303ae | 134 | unsigned int debugbackpocket; /* (TEST/DEBUG) */ |
1c79356b | 135 | |
1c79356b | 136 | vm_offset_t first_free_virt; |
2d21ac55 | 137 | unsigned int current_free_region; /* Used in pmap_next_page */ |
1c79356b | 138 | |
55e303ae A |
139 | pmapTransTab *pmapTrans; /* Point to the hash to pmap translations */ |
140 | struct phys_entry *phys_table; | |
141 | ||
1c79356b | 142 | /* forward */ |
91447636 A |
143 | static void pmap_map_physical(void); |
144 | static void pmap_map_iohole(addr64_t paddr, addr64_t size); | |
1c79356b A |
145 | void pmap_activate(pmap_t pmap, thread_t th, int which_cpu); |
146 | void pmap_deactivate(pmap_t pmap, thread_t th, int which_cpu); | |
1c79356b | 147 | |
91447636 | 148 | extern void hw_hash_init(void); |
1c79356b | 149 | |
1c79356b A |
150 | /* NOTE: kernel_pmap_store must be in V=R storage and aligned!!!!!!!!!!!!!! */ |
151 | ||
152 | extern struct pmap kernel_pmap_store; | |
153 | pmap_t kernel_pmap; /* Pointer to kernel pmap and anchor for in-use pmaps */ | |
55e303ae | 154 | addr64_t kernel_pmap_phys; /* Pointer to kernel pmap and anchor for in-use pmaps, physical address */ |
1c79356b | 155 | pmap_t cursor_pmap; /* Pointer to last pmap allocated or previous if removed from in-use list */ |
55e303ae | 156 | pmap_t sharedPmap; /* Pointer to common pmap for 64-bit address spaces */ |
1c79356b A |
157 | struct zone *pmap_zone; /* zone of pmap structures */ |
158 | boolean_t pmap_initialized = FALSE; | |
159 | ||
55e303ae A |
160 | int ppc_max_pmaps; /* Maximum number of concurrent address spaces allowed. This is machine dependent */ |
161 | addr64_t vm_max_address; /* Maximum effective address supported */ | |
162 | addr64_t vm_max_physical; /* Maximum physical address supported */ | |
163 | ||
1c79356b A |
164 | /* |
165 | * Physical-to-virtual translations are handled by inverted page table | |
166 | * structures, phys_tables. Multiple mappings of a single page are handled | |
167 | * by linking the affected mapping structures. We initialise one region | |
168 | * for phys_tables of the physical memory we know about, but more may be | |
169 | * added as it is discovered (eg. by drivers). | |
170 | */ | |
1c79356b A |
171 | |
172 | /* | |
173 | * free pmap list. caches the first free_pmap_max pmaps that are freed up | |
174 | */ | |
175 | int free_pmap_max = 32; | |
176 | int free_pmap_count; | |
177 | pmap_t free_pmap_list; | |
178 | decl_simple_lock_data(,free_pmap_lock) | |
179 | ||
180 | /* | |
181 | * Function to get index into phys_table for a given physical address | |
182 | */ | |
183 | ||
55e303ae | 184 | struct phys_entry *pmap_find_physentry(ppnum_t pa) |
1c79356b A |
185 | { |
186 | int i; | |
55e303ae | 187 | unsigned int entry; |
1c79356b | 188 | |
55e303ae A |
189 | for (i = pmap_mem_regions_count - 1; i >= 0; i--) { |
190 | if (pa < pmap_mem_regions[i].mrStart) continue; /* See if we fit in this region */ | |
191 | if (pa > pmap_mem_regions[i].mrEnd) continue; /* Check the end too */ | |
1c79356b | 192 | |
91447636 | 193 | entry = (unsigned int)pmap_mem_regions[i].mrPhysTab + ((pa - pmap_mem_regions[i].mrStart) * sizeof(phys_entry_t)); |
55e303ae | 194 | return (struct phys_entry *)entry; |
1c79356b | 195 | } |
55e303ae | 196 | // kprintf("DEBUG - pmap_find_physentry: page 0x%08X not found\n", pa); |
2d21ac55 | 197 | return NULL; |
1c79356b A |
198 | } |
199 | ||
200 | /* | |
201 | * kern_return_t | |
202 | * pmap_add_physical_memory(vm_offset_t spa, vm_offset_t epa, | |
203 | * boolean_t available, unsigned int attr) | |
55e303ae A |
204 | * |
205 | * THIS IS NOT SUPPORTED | |
1c79356b | 206 | */ |
91447636 A |
207 | kern_return_t |
208 | pmap_add_physical_memory( | |
209 | __unused vm_offset_t spa, | |
210 | __unused vm_offset_t epa, | |
211 | __unused boolean_t available, | |
212 | __unused unsigned int attr) | |
1c79356b | 213 | { |
1c79356b A |
214 | |
215 | panic("Forget it! You can't map no more memory, you greedy puke!\n"); | |
1c79356b A |
216 | return KERN_SUCCESS; |
217 | } | |
218 | ||
219 | /* | |
220 | * pmap_map(va, spa, epa, prot) | |
221 | * is called during boot to map memory in the kernel's address map. | |
222 | * A virtual address range starting at "va" is mapped to the physical | |
223 | * address range "spa" to "epa" with machine independent protection | |
224 | * "prot". | |
225 | * | |
226 | * "va", "spa", and "epa" are byte addresses and must be on machine | |
227 | * independent page boundaries. | |
228 | * | |
229 | * Pages with a contiguous virtual address range, the same protection, and attributes. | |
230 | * therefore, we map it with a single block. | |
231 | * | |
55e303ae A |
232 | * Note that this call will only map into 32-bit space |
233 | * | |
1c79356b | 234 | */ |
55e303ae | 235 | |
1c79356b A |
236 | vm_offset_t |
237 | pmap_map( | |
238 | vm_offset_t va, | |
239 | vm_offset_t spa, | |
240 | vm_offset_t epa, | |
0c530ab8 A |
241 | vm_prot_t prot, |
242 | unsigned int flags) | |
1c79356b | 243 | { |
0c530ab8 | 244 | unsigned int mflags; |
2d21ac55 | 245 | addr64_t colladr; |
0c530ab8 A |
246 | mflags = 0; /* Make sure this is initialized to nothing special */ |
247 | if(!(flags & VM_WIMG_USE_DEFAULT)) { /* Are they supplying the attributes? */ | |
248 | mflags = mmFlgUseAttr | (flags & VM_MEM_GUARDED) | ((flags & VM_MEM_NOT_CACHEABLE) >> 1); /* Convert to our mapping_make flags */ | |
249 | } | |
1c79356b | 250 | |
55e303ae | 251 | if (spa == epa) return(va); |
1c79356b A |
252 | |
253 | assert(epa > spa); | |
254 | ||
0c530ab8 A |
255 | colladr = mapping_make(kernel_pmap, (addr64_t)va, (ppnum_t)(spa >> 12), |
256 | (mmFlgBlock | mmFlgPerm), (epa - spa) >> 12, (prot & VM_PROT_ALL) ); | |
1c79356b | 257 | |
55e303ae A |
258 | if(colladr) { /* Was something already mapped in the range? */ |
259 | panic("pmap_map: attempt to map previously mapped range - va = %08X, pa = %08X, epa = %08X, collision = %016llX\n", | |
260 | va, spa, epa, colladr); | |
261 | } | |
1c79356b A |
262 | return(va); |
263 | } | |
264 | ||
91447636 A |
265 | /* |
266 | * pmap_map_physical() | |
267 | * Maps physical memory into the kernel's address map beginning at lgPMWvaddr, the | |
268 | * physical memory window. | |
269 | * | |
270 | */ | |
271 | void | |
2d21ac55 | 272 | pmap_map_physical(void) |
91447636 A |
273 | { |
274 | unsigned region; | |
3a60a9f5 A |
275 | uint64_t msize, size; |
276 | addr64_t paddr, vaddr, colladdr; | |
91447636 A |
277 | |
278 | /* Iterate over physical memory regions, block mapping each into the kernel's address map */ | |
279 | for (region = 0; region < (unsigned)pmap_mem_regions_count; region++) { | |
3a60a9f5 A |
280 | paddr = ((addr64_t)pmap_mem_regions[region].mrStart << 12); /* Get starting physical address */ |
281 | size = (((addr64_t)pmap_mem_regions[region].mrEnd + 1) << 12) - paddr; | |
282 | ||
283 | vaddr = paddr + lowGlo.lgPMWvaddr; /* Get starting virtual address */ | |
284 | ||
91447636 | 285 | while (size > 0) { |
3a60a9f5 A |
286 | |
287 | msize = ((size > 0x0000020000000000ULL) ? 0x0000020000000000ULL : size); /* Get size, but no more than 2TBs */ | |
288 | ||
289 | colladdr = mapping_make(kernel_pmap, vaddr, (paddr >> 12), | |
290 | (mmFlgBlock | mmFlgPerm), (msize >> 12), | |
291 | (VM_PROT_READ | VM_PROT_WRITE)); | |
91447636 | 292 | if (colladdr) { |
2d21ac55 | 293 | panic ("pmap_map_physical: mapping failure - va = %016llX, pa = %016llX, size = %016llX, collision = %016llX\n", |
91447636 A |
294 | vaddr, (paddr >> 12), (msize >> 12), colladdr); |
295 | } | |
3a60a9f5 A |
296 | |
297 | vaddr = vaddr + (uint64_t)msize; /* Point to the next virtual addr */ | |
298 | paddr = paddr + (uint64_t)msize; /* Point to the next physical addr */ | |
91447636 A |
299 | size -= msize; |
300 | } | |
301 | } | |
302 | } | |
303 | ||
304 | /* | |
305 | * pmap_map_iohole(addr64_t paddr, addr64_t size) | |
306 | * Maps an I/O hole into the kernel's address map at its proper offset in | |
307 | * the physical memory window. | |
308 | * | |
309 | */ | |
310 | void | |
311 | pmap_map_iohole(addr64_t paddr, addr64_t size) | |
312 | { | |
3a60a9f5 A |
313 | |
314 | addr64_t vaddr, colladdr, msize; | |
3a60a9f5 A |
315 | |
316 | vaddr = paddr + lowGlo.lgPMWvaddr; /* Get starting virtual address */ | |
317 | ||
91447636 | 318 | while (size > 0) { |
3a60a9f5 A |
319 | |
320 | msize = ((size > 0x0000020000000000ULL) ? 0x0000020000000000ULL : size); /* Get size, but no more than 2TBs */ | |
321 | ||
322 | colladdr = mapping_make(kernel_pmap, vaddr, (paddr >> 12), | |
323 | (mmFlgBlock | mmFlgPerm | mmFlgGuarded | mmFlgCInhib), (msize >> 12), | |
324 | (VM_PROT_READ | VM_PROT_WRITE)); | |
91447636 | 325 | if (colladdr) { |
2d21ac55 | 326 | panic ("pmap_map_iohole: mapping failed - va = %016llX, pa = %016llX, size = %016llX, collision = %016llX\n", |
3a60a9f5 | 327 | vaddr, (paddr >> 12), (msize >> 12), colladdr); |
91447636 | 328 | } |
3a60a9f5 A |
329 | |
330 | vaddr = vaddr + (uint64_t)msize; /* Point to the next virtual addr */ | |
331 | paddr = paddr + (uint64_t)msize; /* Point to the next physical addr */ | |
91447636 | 332 | size -= msize; |
3a60a9f5 | 333 | } |
91447636 A |
334 | } |
335 | ||
1c79356b A |
336 | /* |
337 | * Bootstrap the system enough to run with virtual memory. | |
338 | * Map the kernel's code and data, and allocate the system page table. | |
339 | * Called with mapping done by BATs. Page_size must already be set. | |
340 | * | |
341 | * Parameters: | |
55e303ae | 342 | * msize: Total memory present |
1c79356b | 343 | * first_avail: First virtual address available |
55e303ae | 344 | * kmapsize: Size of kernel text and data |
1c79356b A |
345 | */ |
346 | void | |
55e303ae | 347 | pmap_bootstrap(uint64_t msize, vm_offset_t *first_avail, unsigned int kmapsize) |
1c79356b | 348 | { |
1c79356b A |
349 | vm_offset_t addr; |
350 | vm_size_t size; | |
91447636 A |
351 | unsigned int i, num, mapsize, vmpagesz, vmmapsz, nbits; |
352 | signed bank; | |
55e303ae A |
353 | uint64_t tmemsize; |
354 | uint_t htslop; | |
355 | vm_offset_t first_used_addr, PCAsize; | |
91447636 | 356 | struct phys_entry *phys_entry; |
de355530 | 357 | |
91447636 | 358 | *first_avail = round_page(*first_avail); /* Make sure we start out on a page boundary */ |
55e303ae | 359 | vm_last_addr = VM_MAX_KERNEL_ADDRESS; /* Set the highest address know to VM */ |
1c79356b A |
360 | |
361 | /* | |
362 | * Initialize kernel pmap | |
363 | */ | |
364 | kernel_pmap = &kernel_pmap_store; | |
cf7d32b8 | 365 | kernel_pmap_phys = (addr64_t)(uintptr_t)&kernel_pmap_store; |
1c79356b A |
366 | cursor_pmap = &kernel_pmap_store; |
367 | ||
1c79356b A |
368 | kernel_pmap->pmap_link.next = (queue_t)kernel_pmap; /* Set up anchor forward */ |
369 | kernel_pmap->pmap_link.prev = (queue_t)kernel_pmap; /* Set up anchor reverse */ | |
370 | kernel_pmap->ref_count = 1; | |
55e303ae | 371 | kernel_pmap->pmapFlags = pmapKeyDef; /* Set the default keys */ |
0c530ab8 | 372 | kernel_pmap->pmapFlags |= pmapNXdisabled; |
55e303ae | 373 | kernel_pmap->pmapCCtl = pmapCCtlVal; /* Initialize cache control */ |
1c79356b | 374 | kernel_pmap->space = PPC_SID_KERNEL; |
55e303ae | 375 | kernel_pmap->pmapvr = 0; /* Virtual = Real */ |
1c79356b | 376 | |
55e303ae | 377 | /* |
91447636 A |
378 | * IBM's recommended hash table size is one PTEG for every 2 physical pages. |
379 | * However, we have found that OSX rarely uses more than 4 PTEs in a PTEG | |
380 | * with this size table. Therefore, by default we allocate a hash table | |
381 | * one half IBM's recommended size, ie one PTEG per 4 pages. The "ht_shift" boot-arg | |
382 | * can be used to override the default hash table size. | |
383 | * We will allocate the hash table in physical RAM, outside of kernel virtual memory, | |
55e303ae A |
384 | * at the top of the highest bank that will contain it. |
385 | * Note that "bank" doesn't refer to a physical memory slot here, it is a range of | |
386 | * physically contiguous memory. | |
387 | * | |
388 | * The PCA will go there as well, immediately before the hash table. | |
389 | */ | |
390 | ||
391 | nbits = cntlzw(((msize << 1) - 1) >> 32); /* Get first bit in upper half */ | |
91447636 A |
392 | if (nbits == 32) /* If upper half was empty, find bit in bottom half */ |
393 | nbits = nbits + cntlzw((uint_t)((msize << 1) - 1)); | |
394 | tmemsize = 0x8000000000000000ULL >> nbits; /* Get memory size rounded up to power of 2 */ | |
55e303ae | 395 | |
91447636 A |
396 | /* Calculate hash table size: First, make sure we don't overflow 32-bit arithmetic. */ |
397 | if (tmemsize > 0x0000002000000000ULL) | |
398 | tmemsize = 0x0000002000000000ULL; | |
399 | ||
400 | /* Second, calculate IBM recommended hash table size, ie one PTEG per 2 physical pages */ | |
401 | hash_table_size = (uint_t)(tmemsize >> 13) * PerProcTable[0].ppe_vaddr->pf.pfPTEG; | |
402 | ||
403 | /* Third, cut this in half to produce the OSX default, ie one PTEG per 4 physical pages */ | |
404 | hash_table_size >>= 1; | |
405 | ||
406 | /* Fourth, adjust default size per "ht_shift" boot arg */ | |
407 | if (hash_table_shift >= 0) /* if positive, make size bigger */ | |
408 | hash_table_size <<= hash_table_shift; | |
409 | else /* if "ht_shift" is negative, make smaller */ | |
410 | hash_table_size >>= (-hash_table_shift); | |
411 | ||
412 | /* Fifth, make sure we are at least minimum size */ | |
413 | if (hash_table_size < (256 * 1024)) | |
414 | hash_table_size = (256 * 1024); | |
1c79356b | 415 | |
55e303ae | 416 | while(1) { /* Try to fit hash table in PCA into contiguous memory */ |
1c79356b | 417 | |
55e303ae A |
418 | if(hash_table_size < (256 * 1024)) { /* Have we dropped too short? This should never, ever happen */ |
419 | panic("pmap_bootstrap: Can't find space for hash table\n"); /* This will never print, system isn't up far enough... */ | |
420 | } | |
1c79356b | 421 | |
91447636 A |
422 | PCAsize = (hash_table_size / PerProcTable[0].ppe_vaddr->pf.pfPTEG) * sizeof(PCA_t); /* Get total size of PCA table */ |
423 | PCAsize = round_page(PCAsize); /* Make sure it is at least a page long */ | |
55e303ae A |
424 | |
425 | for(bank = pmap_mem_regions_count - 1; bank >= 0; bank--) { /* Search backwards through banks */ | |
426 | ||
427 | hash_table_base = ((addr64_t)pmap_mem_regions[bank].mrEnd << 12) - hash_table_size + PAGE_SIZE; /* Get tenative address */ | |
428 | ||
429 | htslop = hash_table_base & (hash_table_size - 1); /* Get the extra that we will round down when we align */ | |
430 | hash_table_base = hash_table_base & -(addr64_t)hash_table_size; /* Round down to correct boundary */ | |
431 | ||
91447636 | 432 | if((hash_table_base - round_page(PCAsize)) >= ((addr64_t)pmap_mem_regions[bank].mrStart << 12)) break; /* Leave if we fit */ |
55e303ae A |
433 | } |
434 | ||
435 | if(bank >= 0) break; /* We are done if we found a suitable bank */ | |
436 | ||
437 | hash_table_size = hash_table_size >> 1; /* Try the next size down */ | |
438 | } | |
de355530 | 439 | |
55e303ae | 440 | if(htslop) { /* If there was slop (i.e., wasted pages for alignment) add a new region */ |
91447636 | 441 | for(i = pmap_mem_regions_count - 1; i >= (unsigned)bank; i--) { /* Copy from end to our bank, including our bank */ |
55e303ae A |
442 | pmap_mem_regions[i + 1].mrStart = pmap_mem_regions[i].mrStart; /* Set the start of the bank */ |
443 | pmap_mem_regions[i + 1].mrAStart = pmap_mem_regions[i].mrAStart; /* Set the start of allocatable area */ | |
444 | pmap_mem_regions[i + 1].mrEnd = pmap_mem_regions[i].mrEnd; /* Set the end address of bank */ | |
445 | pmap_mem_regions[i + 1].mrAEnd = pmap_mem_regions[i].mrAEnd; /* Set the end address of allocatable area */ | |
446 | } | |
de355530 | 447 | |
55e303ae A |
448 | pmap_mem_regions[i + 1].mrStart = (hash_table_base + hash_table_size) >> 12; /* Set the start of the next bank to the start of the slop area */ |
449 | pmap_mem_regions[i + 1].mrAStart = (hash_table_base + hash_table_size) >> 12; /* Set the start of allocatable area to the start of the slop area */ | |
450 | pmap_mem_regions[i].mrEnd = (hash_table_base + hash_table_size - 4096) >> 12; /* Set the end of our bank to the end of the hash table */ | |
de355530 | 451 | |
55e303ae A |
452 | } |
453 | ||
454 | pmap_mem_regions[bank].mrAEnd = (hash_table_base - PCAsize - 4096) >> 12; /* Set the maximum allocatable in this bank */ | |
455 | ||
456 | hw_hash_init(); /* Initiaize the hash table and PCA */ | |
457 | hw_setup_trans(); /* Set up hardware registers needed for translation */ | |
458 | ||
459 | /* | |
460 | * The hash table is now all initialized and so is the PCA. Go on to do the rest of it. | |
461 | * This allocation is from the bottom up. | |
462 | */ | |
463 | ||
464 | num = atop_64(msize); /* Get number of pages in all of memory */ | |
1c79356b | 465 | |
55e303ae | 466 | /* Figure out how much we need to allocate */ |
1c79356b | 467 | |
55e303ae A |
468 | size = (vm_size_t) ( |
469 | (InitialSaveBloks * PAGE_SIZE) + /* Allow space for the initial context saveareas */ | |
470 | (BackPocketSaveBloks * PAGE_SIZE) + /* For backpocket saveareas */ | |
471 | trcWork.traceSize + /* Size of trace table */ | |
472 | ((((1 << maxAdrSpb) * sizeof(pmapTransTab)) + 4095) & -4096) + /* Size of pmap translate table */ | |
473 | (((num * sizeof(struct phys_entry)) + 4095) & -4096) /* For the physical entries */ | |
474 | ); | |
1c79356b | 475 | |
91447636 | 476 | mapsize = size = round_page(size); /* Get size of area to map that we just calculated */ |
55e303ae | 477 | mapsize = mapsize + kmapsize; /* Account for the kernel text size */ |
1c79356b | 478 | |
91447636 A |
479 | vmpagesz = round_page(num * sizeof(struct vm_page)); /* Allow for all vm_pages needed to map physical mem */ |
480 | vmmapsz = round_page((num / 8) * sizeof(struct vm_map_entry)); /* Allow for vm_maps */ | |
55e303ae A |
481 | |
482 | mapsize = mapsize + vmpagesz + vmmapsz; /* Add the VM system estimates into the grand total */ | |
1c79356b | 483 | |
55e303ae A |
484 | mapsize = mapsize + (4 * 1024 * 1024); /* Allow for 4 meg of extra mappings */ |
485 | mapsize = ((mapsize / PAGE_SIZE) + MAPPERBLOK - 1) / MAPPERBLOK; /* Get number of blocks of mappings we need */ | |
486 | mapsize = mapsize + ((mapsize + MAPPERBLOK - 1) / MAPPERBLOK); /* Account for the mappings themselves */ | |
1c79356b | 487 | |
55e303ae | 488 | size = size + (mapsize * PAGE_SIZE); /* Get the true size we need */ |
1c79356b | 489 | |
55e303ae | 490 | /* hash table must be aligned to its size */ |
1c79356b | 491 | |
55e303ae A |
492 | addr = *first_avail; /* Set the address to start allocations */ |
493 | first_used_addr = addr; /* Remember where we started */ | |
d7e50217 | 494 | |
55e303ae | 495 | bzero((char *)addr, size); /* Clear everything that we are allocating */ |
d7e50217 | 496 | |
55e303ae A |
497 | savearea_init(addr); /* Initialize the savearea chains and data */ |
498 | ||
499 | addr = (vm_offset_t)((unsigned int)addr + ((InitialSaveBloks + BackPocketSaveBloks) * PAGE_SIZE)); /* Point past saveareas */ | |
1c79356b | 500 | |
55e303ae A |
501 | trcWork.traceCurr = (unsigned int)addr; /* Set first trace slot to use */ |
502 | trcWork.traceStart = (unsigned int)addr; /* Set start of trace table */ | |
503 | trcWork.traceEnd = (unsigned int)addr + trcWork.traceSize; /* Set end of trace table */ | |
504 | ||
505 | addr = (vm_offset_t)trcWork.traceEnd; /* Set next allocatable location */ | |
1c79356b | 506 | |
55e303ae | 507 | pmapTrans = (pmapTransTab *)addr; /* Point to the pmap to hash translation table */ |
1c79356b | 508 | |
55e303ae A |
509 | pmapTrans[PPC_SID_KERNEL].pmapPAddr = (addr64_t)((uintptr_t)kernel_pmap); /* Initialize the kernel pmap in the translate table */ |
510 | pmapTrans[PPC_SID_KERNEL].pmapVAddr = CAST_DOWN(unsigned int, kernel_pmap); /* Initialize the kernel pmap in the translate table */ | |
1c79356b | 511 | |
55e303ae | 512 | addr += ((((1 << maxAdrSpb) * sizeof(pmapTransTab)) + 4095) & -4096); /* Point past pmap translate table */ |
1c79356b | 513 | |
55e303ae | 514 | /* NOTE: the phys_table must be within the first 2GB of physical RAM. This makes sure we only need to do 32-bit arithmetic */ |
1c79356b | 515 | |
91447636 | 516 | phys_entry = (struct phys_entry *) addr; /* Get pointer to physical table */ |
1c79356b | 517 | |
2d21ac55 | 518 | for (bank = 0; (unsigned)bank < pmap_mem_regions_count; bank++) { /* Set pointer and initialize all banks of ram */ |
55e303ae | 519 | |
91447636 | 520 | pmap_mem_regions[bank].mrPhysTab = phys_entry; /* Set pointer to the physical table for this bank */ |
55e303ae | 521 | |
91447636 | 522 | phys_entry = phys_entry + (pmap_mem_regions[bank].mrEnd - pmap_mem_regions[bank].mrStart + 1); /* Point to the next */ |
55e303ae | 523 | } |
1c79356b | 524 | |
55e303ae A |
525 | addr += (((num * sizeof(struct phys_entry)) + 4095) & -4096); /* Step on past the physical entries */ |
526 | ||
1c79356b A |
527 | /* |
528 | * Remaining space is for mapping entries. Tell the initializer routine that | |
529 | * the mapping system can't release this block because it's permanently assigned | |
530 | */ | |
531 | ||
55e303ae | 532 | mapping_init(); /* Initialize the mapping tables */ |
1c79356b A |
533 | |
534 | for(i = addr; i < first_used_addr + size; i += PAGE_SIZE) { /* Add initial mapping blocks */ | |
55e303ae | 535 | mapping_free_init(i, 1, 0); /* Pass block address and say that this one is not releasable */ |
1c79356b | 536 | } |
55e303ae | 537 | mapCtl.mapcmin = MAPPERBLOK; /* Make sure we only adjust one at a time */ |
1c79356b A |
538 | |
539 | /* Map V=R the page tables */ | |
540 | pmap_map(first_used_addr, first_used_addr, | |
0c530ab8 | 541 | round_page(first_used_addr + size), VM_PROT_READ | VM_PROT_WRITE, VM_WIMG_USE_DEFAULT); |
de355530 | 542 | |
91447636 | 543 | *first_avail = round_page(first_used_addr + size); /* Set next available page */ |
55e303ae | 544 | first_free_virt = *first_avail; /* Ditto */ |
91447636 A |
545 | |
546 | /* For 64-bit machines, block map physical memory and the I/O hole into kernel space */ | |
547 | if(BootProcInfo.pf.Available & pf64Bit) { /* Are we on a 64-bit machine? */ | |
548 | lowGlo.lgPMWvaddr = PHYS_MEM_WINDOW_VADDR; /* Initialize the physical memory window's virtual address */ | |
549 | ||
550 | pmap_map_physical(); /* Block map physical memory into the window */ | |
551 | ||
552 | pmap_map_iohole(IO_MEM_WINDOW_VADDR, IO_MEM_WINDOW_SIZE); | |
553 | /* Block map the I/O hole */ | |
554 | } | |
1c79356b A |
555 | |
556 | /* All the rest of memory is free - add it to the free | |
557 | * regions so that it can be allocated by pmap_steal | |
558 | */ | |
1c79356b | 559 | |
55e303ae | 560 | pmap_mem_regions[0].mrAStart = (*first_avail >> 12); /* Set up the free area to start allocations (always in the first bank) */ |
de355530 | 561 | |
55e303ae A |
562 | current_free_region = 0; /* Set that we will start allocating in bank 0 */ |
563 | avail_remaining = 0; /* Clear free page count */ | |
2d21ac55 | 564 | for(bank = 0; (unsigned)bank < pmap_mem_regions_count; bank++) { /* Total up all of the pages in the system that are available */ |
55e303ae | 565 | avail_remaining += (pmap_mem_regions[bank].mrAEnd - pmap_mem_regions[bank].mrAStart) + 1; /* Add in allocatable pages in this bank */ |
de355530 | 566 | } |
55e303ae | 567 | |
1c79356b A |
568 | |
569 | } | |
570 | ||
571 | /* | |
572 | * pmap_init(spa, epa) | |
573 | * finishes the initialization of the pmap module. | |
574 | * This procedure is called from vm_mem_init() in vm/vm_init.c | |
575 | * to initialize any remaining data structures that the pmap module | |
576 | * needs to map virtual memory (VM is already ON). | |
577 | * | |
578 | * Note that the pmap needs to be sized and aligned to | |
579 | * a power of two. This is because it is used both in virtual and | |
580 | * real so it can't span a page boundary. | |
581 | */ | |
582 | ||
583 | void | |
584 | pmap_init(void) | |
585 | { | |
586 | ||
1c79356b A |
587 | pmap_zone = zinit(pmapSize, 400 * pmapSize, 4096, "pmap"); |
588 | #if ZONE_DEBUG | |
589 | zone_debug_disable(pmap_zone); /* Can't debug this one 'cause it messes with size and alignment */ | |
590 | #endif /* ZONE_DEBUG */ | |
591 | ||
592 | pmap_initialized = TRUE; | |
593 | ||
594 | /* | |
595 | * Initialize list of freed up pmaps | |
596 | */ | |
2d21ac55 | 597 | free_pmap_list = NULL; /* Set that there are no free pmaps */ |
1c79356b | 598 | free_pmap_count = 0; |
91447636 | 599 | simple_lock_init(&free_pmap_lock, 0); |
55e303ae | 600 | |
1c79356b A |
601 | } |
602 | ||
603 | unsigned int pmap_free_pages(void) | |
604 | { | |
605 | return avail_remaining; | |
606 | } | |
607 | ||
55e303ae A |
608 | /* |
609 | * This function allocates physical pages. | |
610 | */ | |
611 | ||
0b4c1975 A |
612 | boolean_t |
613 | pmap_next_page_hi(ppnum_t * pnum) | |
614 | { | |
615 | return pmap_next_page(pnum); | |
616 | } | |
617 | ||
618 | ||
55e303ae A |
619 | /* Non-optimal, but only used for virtual memory startup. |
620 | * Allocate memory from a table of free physical addresses | |
621 | * If there are no more free entries, too bad. | |
622 | */ | |
623 | ||
2d21ac55 A |
624 | boolean_t |
625 | pmap_next_page(ppnum_t *addrp) | |
1c79356b | 626 | { |
2d21ac55 | 627 | unsigned int i; |
1c79356b | 628 | |
55e303ae | 629 | if(current_free_region >= pmap_mem_regions_count) return FALSE; /* Return failure if we have used everything... */ |
2d21ac55 | 630 | |
55e303ae A |
631 | for(i = current_free_region; i < pmap_mem_regions_count; i++) { /* Find the next bank with free pages */ |
632 | if(pmap_mem_regions[i].mrAStart <= pmap_mem_regions[i].mrAEnd) break; /* Found one */ | |
de355530 | 633 | } |
2d21ac55 | 634 | |
55e303ae A |
635 | current_free_region = i; /* Set our current bank */ |
636 | if(i >= pmap_mem_regions_count) return FALSE; /* Couldn't find a free page */ | |
637 | ||
638 | *addrp = pmap_mem_regions[i].mrAStart; /* Allocate the page */ | |
639 | pmap_mem_regions[i].mrAStart = pmap_mem_regions[i].mrAStart + 1; /* Set the next one to go */ | |
640 | avail_remaining--; /* Drop free count */ | |
641 | ||
1c79356b A |
642 | return TRUE; |
643 | } | |
644 | ||
645 | void pmap_virtual_space( | |
646 | vm_offset_t *startp, | |
647 | vm_offset_t *endp) | |
648 | { | |
91447636 | 649 | *startp = round_page(first_free_virt); |
55e303ae | 650 | *endp = vm_last_addr; |
1c79356b A |
651 | } |
652 | ||
653 | /* | |
654 | * pmap_create | |
655 | * | |
656 | * Create and return a physical map. | |
657 | * | |
658 | * If the size specified for the map is zero, the map is an actual physical | |
659 | * map, and may be referenced by the hardware. | |
660 | * | |
661 | * A pmap is either in the free list or in the in-use list. The only use | |
662 | * of the in-use list (aside from debugging) is to handle the VSID wrap situation. | |
663 | * Whenever a new pmap is allocated (i.e., not recovered from the free list). The | |
664 | * in-use list is matched until a hole in the VSID sequence is found. (Note | |
665 | * that the in-use pmaps are queued in VSID sequence order.) This is all done | |
666 | * while free_pmap_lock is held. | |
667 | * | |
668 | * If the size specified is non-zero, the map will be used in software | |
669 | * only, and is bounded by that size. | |
670 | */ | |
671 | pmap_t | |
0c530ab8 | 672 | pmap_create(vm_map_size_t size, __unused boolean_t is_64bit) |
1c79356b | 673 | { |
91447636 A |
674 | pmap_t pmap, ckpmap, fore; |
675 | int s; | |
676 | unsigned int currSID; | |
55e303ae | 677 | addr64_t physpmap; |
1c79356b A |
678 | |
679 | /* | |
680 | * A software use-only map doesn't even need a pmap structure. | |
681 | */ | |
682 | if (size) | |
683 | return(PMAP_NULL); | |
684 | ||
685 | /* | |
686 | * If there is a pmap in the pmap free list, reuse it. | |
687 | * Note that we use free_pmap_list for all chaining of pmaps, both to | |
688 | * the free list and the in use chain (anchored from kernel_pmap). | |
689 | */ | |
690 | s = splhigh(); | |
691 | simple_lock(&free_pmap_lock); | |
692 | ||
55e303ae A |
693 | if(free_pmap_list) { /* Any free? */ |
694 | pmap = free_pmap_list; /* Yes, allocate it */ | |
695 | free_pmap_list = (pmap_t)pmap->freepmap; /* Dequeue this one (we chain free ones through freepmap) */ | |
1c79356b A |
696 | free_pmap_count--; |
697 | } | |
698 | else { | |
55e303ae | 699 | simple_unlock(&free_pmap_lock); /* Unlock just in case */ |
1c79356b A |
700 | splx(s); |
701 | ||
55e303ae | 702 | pmap = (pmap_t) zalloc(pmap_zone); /* Get one */ |
1c79356b A |
703 | if (pmap == PMAP_NULL) return(PMAP_NULL); /* Handle out-of-memory condition */ |
704 | ||
55e303ae | 705 | bzero((char *)pmap, pmapSize); /* Clean up the pmap */ |
1c79356b A |
706 | |
707 | s = splhigh(); | |
55e303ae | 708 | simple_lock(&free_pmap_lock); /* Lock it back up */ |
1c79356b | 709 | |
55e303ae A |
710 | ckpmap = cursor_pmap; /* Get starting point for free ID search */ |
711 | currSID = ckpmap->spaceNum; /* Get the actual space ID number */ | |
1c79356b | 712 | |
55e303ae | 713 | while(1) { /* Keep trying until something happens */ |
1c79356b | 714 | |
55e303ae A |
715 | currSID = (currSID + 1) & (maxAdrSp - 1); /* Get the next in the sequence */ |
716 | if(((currSID * incrVSID) & (maxAdrSp - 1)) == invalSpace) continue; /* Skip the space we have reserved */ | |
1c79356b A |
717 | ckpmap = (pmap_t)ckpmap->pmap_link.next; /* On to the next in-use pmap */ |
718 | ||
719 | if(ckpmap->spaceNum != currSID) break; /* If we are out of sequence, this is free */ | |
720 | ||
55e303ae A |
721 | if(ckpmap == cursor_pmap) { /* See if we have 2^20 already allocated */ |
722 | panic("pmap_create: Maximum number (%d) active address spaces reached\n", maxAdrSp); /* Die pig dog */ | |
1c79356b A |
723 | } |
724 | } | |
725 | ||
55e303ae A |
726 | pmap->space = (currSID * incrVSID) & (maxAdrSp - 1); /* Calculate the actual VSID */ |
727 | pmap->spaceNum = currSID; /* Set the space ID number */ | |
1c79356b A |
728 | /* |
729 | * Now we link into the chain just before the out of sequence guy. | |
730 | */ | |
731 | ||
55e303ae A |
732 | fore = (pmap_t)ckpmap->pmap_link.prev; /* Get the current's previous */ |
733 | pmap->pmap_link.next = (queue_t)ckpmap; /* My next points to the current */ | |
734 | fore->pmap_link.next = (queue_t)pmap; /* Current's previous's next points to me */ | |
735 | pmap->pmap_link.prev = (queue_t)fore; /* My prev points to what the current pointed to */ | |
736 | ckpmap->pmap_link.prev = (queue_t)pmap; /* Current's prev points to me */ | |
55e303ae A |
737 | |
738 | physpmap = ((addr64_t)pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)pmap)) << 12) | (addr64_t)((unsigned int)pmap & 0xFFF); /* Get the physical address of the pmap */ | |
739 | ||
740 | pmap->pmapvr = (addr64_t)((uintptr_t)pmap) ^ physpmap; /* Make V to R translation mask */ | |
741 | ||
742 | pmapTrans[pmap->space].pmapPAddr = physpmap; /* Set translate table physical to point to us */ | |
743 | pmapTrans[pmap->space].pmapVAddr = CAST_DOWN(unsigned int, pmap); /* Set translate table virtual to point to us */ | |
1c79356b | 744 | } |
55e303ae | 745 | |
2d21ac55 | 746 | pmap->pmapVmmExt = NULL; /* Clear VMM extension block vaddr */ |
91447636 | 747 | pmap->pmapVmmExtPhys = 0; /* and the paddr, too */ |
55e303ae A |
748 | pmap->pmapFlags = pmapKeyDef; /* Set default key */ |
749 | pmap->pmapCCtl = pmapCCtlVal; /* Initialize cache control */ | |
1c79356b A |
750 | pmap->ref_count = 1; |
751 | pmap->stats.resident_count = 0; | |
752 | pmap->stats.wired_count = 0; | |
55e303ae | 753 | pmap->pmapSCSubTag = 0x0000000000000000ULL; /* Make sure this is clean an tidy */ |
de355530 | 754 | simple_unlock(&free_pmap_lock); |
55e303ae | 755 | |
1c79356b A |
756 | splx(s); |
757 | return(pmap); | |
758 | } | |
759 | ||
760 | /* | |
761 | * pmap_destroy | |
762 | * | |
763 | * Gives up a reference to the specified pmap. When the reference count | |
764 | * reaches zero the pmap structure is added to the pmap free list. | |
765 | * | |
766 | * Should only be called if the map contains no valid mappings. | |
767 | */ | |
768 | void | |
769 | pmap_destroy(pmap_t pmap) | |
770 | { | |
2d21ac55 | 771 | uint32_t ref_count; |
1c79356b A |
772 | spl_t s; |
773 | pmap_t fore, aft; | |
774 | ||
1c79356b A |
775 | if (pmap == PMAP_NULL) |
776 | return; | |
777 | ||
2d21ac55 | 778 | if ((ref_count = hw_atomic_sub(&pmap->ref_count, 1)) == UINT_MAX) /* underflow */ |
1c79356b | 779 | panic("pmap_destroy(): ref_count < 0"); |
2d21ac55 A |
780 | |
781 | if (ref_count > 0) | |
782 | return; /* Still more users, leave now... */ | |
91447636 A |
783 | |
784 | if (!(pmap->pmapFlags & pmapVMgsaa)) { /* Don't try this for a shadow assist guest */ | |
785 | pmap_unmap_sharedpage(pmap); /* Remove any mapping of page -1 */ | |
786 | } | |
1c79356b A |
787 | |
788 | #ifdef notdef | |
789 | if(pmap->stats.resident_count != 0) | |
790 | panic("PMAP_DESTROY: pmap not empty"); | |
791 | #else | |
792 | if(pmap->stats.resident_count != 0) { | |
55e303ae | 793 | pmap_remove(pmap, 0, 0xFFFFFFFFFFFFF000ULL); |
1c79356b A |
794 | } |
795 | #endif | |
796 | ||
797 | /* | |
798 | * Add the pmap to the pmap free list. | |
799 | */ | |
800 | ||
801 | s = splhigh(); | |
802 | /* | |
803 | * Add the pmap to the pmap free list. | |
804 | */ | |
805 | simple_lock(&free_pmap_lock); | |
806 | ||
55e303ae | 807 | if (free_pmap_count <= free_pmap_max) { /* Do we have enough spares? */ |
1c79356b | 808 | |
55e303ae | 809 | pmap->freepmap = free_pmap_list; /* Queue in front */ |
1c79356b A |
810 | free_pmap_list = pmap; |
811 | free_pmap_count++; | |
812 | simple_unlock(&free_pmap_lock); | |
813 | ||
814 | } else { | |
815 | if(cursor_pmap == pmap) cursor_pmap = (pmap_t)pmap->pmap_link.prev; /* If we are releasing the cursor, back up */ | |
816 | fore = (pmap_t)pmap->pmap_link.prev; | |
817 | aft = (pmap_t)pmap->pmap_link.next; | |
818 | fore->pmap_link.next = pmap->pmap_link.next; /* My previous's next is my next */ | |
819 | aft->pmap_link.prev = pmap->pmap_link.prev; /* My next's previous is my previous */ | |
820 | simple_unlock(&free_pmap_lock); | |
55e303ae A |
821 | pmapTrans[pmap->space].pmapPAddr = -1; /* Invalidate the translate table physical */ |
822 | pmapTrans[pmap->space].pmapVAddr = -1; /* Invalidate the translate table virtual */ | |
91447636 | 823 | zfree(pmap_zone, pmap); |
1c79356b A |
824 | } |
825 | splx(s); | |
826 | } | |
827 | ||
828 | /* | |
829 | * pmap_reference(pmap) | |
830 | * gains a reference to the specified pmap. | |
831 | */ | |
832 | void | |
833 | pmap_reference(pmap_t pmap) | |
834 | { | |
2d21ac55 A |
835 | if (pmap != PMAP_NULL) |
836 | (void)hw_atomic_add(&pmap->ref_count, 1); /* Bump the count */ | |
1c79356b A |
837 | } |
838 | ||
0b4e3aa0 A |
839 | /* |
840 | * pmap_remove_some_phys | |
841 | * | |
842 | * Removes mappings of the associated page from the specified pmap | |
843 | * | |
844 | */ | |
845 | void pmap_remove_some_phys( | |
846 | pmap_t pmap, | |
847 | vm_offset_t pa) | |
848 | { | |
849 | register struct phys_entry *pp; | |
55e303ae A |
850 | register struct mapping *mp; |
851 | unsigned int pindex; | |
0b4e3aa0 | 852 | |
55e303ae A |
853 | if (pmap == PMAP_NULL) { /* This should never be called with a null pmap */ |
854 | panic("pmap_remove_some_phys: null pmap\n"); | |
855 | } | |
0b4e3aa0 | 856 | |
55e303ae A |
857 | pp = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ |
858 | if (pp == 0) return; /* Leave if not in physical RAM */ | |
0b4e3aa0 | 859 | |
91447636 | 860 | do { /* Keep going until we toss all pages from this pmap */ |
55e303ae A |
861 | if (pmap->pmapFlags & pmapVMhost) { |
862 | mp = hw_purge_phys(pp); /* Toss a map */ | |
91447636 A |
863 | switch ((unsigned int)mp & mapRetCode) { |
864 | case mapRtOK: | |
865 | mapping_free(mp); /* Return mapping to free inventory */ | |
866 | break; | |
867 | case mapRtGuest: | |
868 | break; /* Don't try to return a guest mapping */ | |
869 | case mapRtEmpty: | |
870 | break; /* Physent chain empty, we're done */ | |
871 | case mapRtNotFnd: | |
872 | break; /* Mapping disappeared on us, retry */ | |
873 | default: | |
2d21ac55 | 874 | panic("pmap_remove_some_phys: hw_purge_phys failed - pp = %p, pmap = %p, code = %p\n", |
91447636 | 875 | pp, pmap, mp); /* Handle failure with our usual lack of tact */ |
55e303ae A |
876 | } |
877 | } else { | |
91447636 A |
878 | mp = hw_purge_space(pp, pmap); /* Toss a map */ |
879 | switch ((unsigned int)mp & mapRetCode) { | |
880 | case mapRtOK: | |
881 | mapping_free(mp); /* Return mapping to free inventory */ | |
882 | break; | |
883 | case mapRtEmpty: | |
884 | break; /* Physent chain empty, we're done */ | |
885 | case mapRtNotFnd: | |
886 | break; /* Mapping disappeared on us, retry */ | |
887 | default: | |
2d21ac55 | 888 | panic("pmap_remove_some_phys: hw_purge_phys failed - pp = %p, pmap = %p, code = %p\n", |
91447636 | 889 | pp, pmap, mp); /* Handle failure with our usual lack of tact */ |
55e303ae A |
890 | } |
891 | } | |
91447636 A |
892 | } while (mapRtEmpty != ((unsigned int)mp & mapRetCode)); |
893 | ||
894 | #if DEBUG | |
895 | if ((pmap->pmapFlags & pmapVMhost) && !pmap_verify_free(pa)) | |
2d21ac55 | 896 | panic("pmap_remove_some_phys: cruft left behind - pa = %08X, pmap = %p\n", pa, pmap); |
91447636 | 897 | #endif |
de355530 | 898 | |
55e303ae | 899 | return; /* Leave... */ |
0b4e3aa0 A |
900 | } |
901 | ||
1c79356b A |
902 | /* |
903 | * pmap_remove(pmap, s, e) | |
904 | * unmaps all virtual addresses v in the virtual address | |
905 | * range determined by [s, e) and pmap. | |
906 | * s and e must be on machine independent page boundaries and | |
907 | * s must be less than or equal to e. | |
908 | * | |
909 | * Note that pmap_remove does not remove any mappings in nested pmaps. We just | |
910 | * skip those segments. | |
911 | */ | |
912 | void | |
913 | pmap_remove( | |
914 | pmap_t pmap, | |
55e303ae A |
915 | addr64_t sva, |
916 | addr64_t eva) | |
1c79356b | 917 | { |
55e303ae | 918 | addr64_t va, endva; |
de355530 | 919 | |
55e303ae | 920 | if (pmap == PMAP_NULL) return; /* Leave if software pmap */ |
1c79356b | 921 | |
1c79356b A |
922 | |
923 | /* It is just possible that eva might have wrapped around to zero, | |
924 | * and sometimes we get asked to liberate something of size zero | |
925 | * even though it's dumb (eg. after zero length read_overwrites) | |
926 | */ | |
927 | assert(eva >= sva); | |
928 | ||
929 | /* If these are not page aligned the loop might not terminate */ | |
55e303ae | 930 | assert((sva == trunc_page_64(sva)) && (eva == trunc_page_64(eva))); |
de355530 | 931 | |
55e303ae A |
932 | va = sva & -4096LL; /* Round start down to a page */ |
933 | endva = eva & -4096LL; /* Round end down to a page */ | |
1c79356b | 934 | |
55e303ae A |
935 | while(1) { /* Go until we finish the range */ |
936 | va = mapping_remove(pmap, va); /* Remove the mapping and see what's next */ | |
937 | va = va & -4096LL; /* Make sure the "not found" indication is clear */ | |
938 | if((va == 0) || (va >= endva)) break; /* End loop if we finish range or run off the end */ | |
1c79356b A |
939 | } |
940 | ||
1c79356b A |
941 | } |
942 | ||
943 | /* | |
944 | * Routine: | |
945 | * pmap_page_protect | |
946 | * | |
947 | * Function: | |
948 | * Lower the permission for all mappings to a given page. | |
949 | */ | |
950 | void | |
951 | pmap_page_protect( | |
55e303ae | 952 | ppnum_t pa, |
1c79356b A |
953 | vm_prot_t prot) |
954 | { | |
955 | register struct phys_entry *pp; | |
956 | boolean_t remove; | |
55e303ae | 957 | unsigned int pindex; |
91447636 | 958 | mapping_t *mp; |
1c79356b A |
959 | |
960 | ||
0c530ab8 | 961 | switch (prot & VM_PROT_ALL) { |
1c79356b A |
962 | case VM_PROT_READ: |
963 | case VM_PROT_READ|VM_PROT_EXECUTE: | |
964 | remove = FALSE; | |
965 | break; | |
966 | case VM_PROT_ALL: | |
967 | return; | |
968 | default: | |
969 | remove = TRUE; | |
970 | break; | |
971 | } | |
972 | ||
55e303ae | 973 | |
91447636 | 974 | pp = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ |
55e303ae | 975 | if (pp == 0) return; /* Leave if not in physical RAM */ |
1c79356b A |
976 | |
977 | if (remove) { /* If the protection was set to none, we'll remove all mappings */ | |
55e303ae | 978 | |
91447636 | 979 | do { /* Keep going until we toss all pages from this physical page */ |
55e303ae | 980 | mp = hw_purge_phys(pp); /* Toss a map */ |
91447636 A |
981 | switch ((unsigned int)mp & mapRetCode) { |
982 | case mapRtOK: | |
983 | mapping_free(mp); /* Return mapping to free inventory */ | |
984 | break; | |
985 | case mapRtGuest: | |
986 | break; /* Don't try to return a guest mapping */ | |
987 | case mapRtNotFnd: | |
988 | break; /* Mapping disappeared on us, retry */ | |
989 | case mapRtEmpty: | |
990 | break; /* Physent chain empty, we're done */ | |
2d21ac55 | 991 | default: panic("pmap_page_protect: hw_purge_phys failed - pp = %p, code = %p\n", |
91447636 | 992 | pp, mp); /* Handle failure with our usual lack of tact */ |
55e303ae | 993 | } |
91447636 A |
994 | } while (mapRtEmpty != ((unsigned int)mp & mapRetCode)); |
995 | ||
996 | #if DEBUG | |
997 | if (!pmap_verify_free(pa)) | |
998 | panic("pmap_page_protect: cruft left behind - pa = %08X\n", pa); | |
999 | #endif | |
1c79356b | 1000 | |
1c79356b A |
1001 | return; /* Leave... */ |
1002 | } | |
1c79356b | 1003 | |
55e303ae A |
1004 | /* When we get here, it means that we are to change the protection for a |
1005 | * physical page. | |
1006 | */ | |
1007 | ||
0c530ab8 | 1008 | mapping_protect_phys(pa, (prot & VM_PROT_ALL) ); /* Change protection of all mappings to page. */ |
55e303ae | 1009 | |
1c79356b A |
1010 | } |
1011 | ||
91447636 A |
1012 | /* |
1013 | * Routine: | |
1014 | * pmap_disconnect | |
1015 | * | |
1016 | * Function: | |
1017 | * Disconnect all mappings for this page and return reference and change status | |
1018 | * in generic format. | |
1019 | * | |
1020 | */ | |
1021 | unsigned int pmap_disconnect( | |
1022 | ppnum_t pa) | |
1023 | { | |
1024 | register struct phys_entry *pp; | |
1025 | unsigned int pindex; | |
1026 | mapping_t *mp; | |
1027 | ||
1028 | pp = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ | |
1029 | if (pp == 0) return (0); /* Return null ref and chg if not in physical RAM */ | |
1030 | do { /* Iterate until all mappings are dead and gone */ | |
1031 | mp = hw_purge_phys(pp); /* Disconnect a mapping */ | |
1032 | if (!mp) break; /* All mappings are gone, leave the loop */ | |
1033 | switch ((unsigned int)mp & mapRetCode) { | |
1034 | case mapRtOK: | |
1035 | mapping_free(mp); /* Return mapping to free inventory */ | |
1036 | break; | |
1037 | case mapRtGuest: | |
1038 | break; /* Don't try to return a guest mapping */ | |
1039 | case mapRtNotFnd: | |
1040 | break; /* Mapping disappeared on us, retry */ | |
1041 | case mapRtEmpty: | |
1042 | break; /* Physent chain empty, we're done */ | |
2d21ac55 | 1043 | default: panic("hw_purge_phys: hw_purge_phys failed - pp = %p, code = %p\n", |
91447636 A |
1044 | pp, mp); /* Handle failure with our usual lack of tact */ |
1045 | } | |
1046 | } while (mapRtEmpty != ((unsigned int)mp & mapRetCode)); | |
1047 | ||
1048 | #if DEBUG | |
1049 | if (!pmap_verify_free(pa)) | |
1050 | panic("pmap_disconnect: cruft left behind - pa = %08X\n", pa); | |
1051 | #endif | |
1052 | ||
1053 | return (mapping_tst_refmod(pa)); /* Return page ref and chg in generic format */ | |
1054 | } | |
1055 | ||
0b4c1975 A |
1056 | |
1057 | boolean_t | |
1058 | pmap_is_noencrypt(__unused ppnum_t pn) | |
1059 | { | |
1060 | return (FALSE); | |
1061 | } | |
1062 | ||
1063 | void | |
1064 | pmap_set_noencrypt(__unused ppnum_t pn) | |
1065 | { | |
1066 | } | |
1067 | ||
1068 | void | |
1069 | pmap_clear_noencrypt(__unused ppnum_t pn) | |
1070 | { | |
1071 | } | |
1072 | ||
1073 | ||
1c79356b A |
1074 | /* |
1075 | * pmap_protect(pmap, s, e, prot) | |
1076 | * changes the protection on all virtual addresses v in the | |
1077 | * virtual address range determined by [s, e] and pmap to prot. | |
1078 | * s and e must be on machine independent page boundaries and | |
1079 | * s must be less than or equal to e. | |
1080 | * | |
1081 | * Note that any requests to change the protection of a nested pmap are | |
1082 | * ignored. Those changes MUST be done by calling this with the correct pmap. | |
1083 | */ | |
1084 | void pmap_protect( | |
1085 | pmap_t pmap, | |
91447636 A |
1086 | vm_map_offset_t sva, |
1087 | vm_map_offset_t eva, | |
1c79356b A |
1088 | vm_prot_t prot) |
1089 | { | |
de355530 | 1090 | |
91447636 | 1091 | addr64_t va, endva; |
1c79356b A |
1092 | |
1093 | if (pmap == PMAP_NULL) return; /* Do nothing if no pmap */ | |
1094 | ||
1c79356b | 1095 | if (prot == VM_PROT_NONE) { /* Should we kill the address range?? */ |
55e303ae | 1096 | pmap_remove(pmap, (addr64_t)sva, (addr64_t)eva); /* Yeah, dump 'em */ |
1c79356b A |
1097 | return; /* Leave... */ |
1098 | } | |
1099 | ||
55e303ae A |
1100 | va = sva & -4096LL; /* Round start down to a page */ |
1101 | endva = eva & -4096LL; /* Round end down to a page */ | |
1c79356b | 1102 | |
55e303ae | 1103 | while(1) { /* Go until we finish the range */ |
0c530ab8 | 1104 | mapping_protect(pmap, va, (prot & VM_PROT_ALL), &va); /* Change the protection and see what's next */ |
55e303ae | 1105 | if((va == 0) || (va >= endva)) break; /* End loop if we finish range or run off the end */ |
1c79356b A |
1106 | } |
1107 | ||
1c79356b A |
1108 | } |
1109 | ||
9bccf70c A |
1110 | |
1111 | ||
1c79356b A |
1112 | /* |
1113 | * pmap_enter | |
1114 | * | |
1115 | * Create a translation for the virtual address (virt) to the physical | |
1116 | * address (phys) in the pmap with the protection requested. If the | |
1117 | * translation is wired then we can not allow a full page fault, i.e., | |
1118 | * the mapping control block is not eligible to be stolen in a low memory | |
1119 | * condition. | |
1120 | * | |
1121 | * NB: This is the only routine which MAY NOT lazy-evaluate | |
1122 | * or lose information. That is, this routine must actually | |
1123 | * insert this page into the given map NOW. | |
1124 | */ | |
1125 | void | |
91447636 A |
1126 | pmap_enter(pmap_t pmap, vm_map_offset_t va, ppnum_t pa, vm_prot_t prot, |
1127 | unsigned int flags, __unused boolean_t wired) | |
1c79356b | 1128 | { |
55e303ae A |
1129 | unsigned int mflags; |
1130 | addr64_t colva; | |
1c79356b | 1131 | |
55e303ae | 1132 | if (pmap == PMAP_NULL) return; /* Leave if software pmap */ |
1c79356b | 1133 | |
55e303ae A |
1134 | mflags = 0; /* Make sure this is initialized to nothing special */ |
1135 | if(!(flags & VM_WIMG_USE_DEFAULT)) { /* Are they supplying the attributes? */ | |
1136 | mflags = mmFlgUseAttr | (flags & VM_MEM_GUARDED) | ((flags & VM_MEM_NOT_CACHEABLE) >> 1); /* Convert to our mapping_make flags */ | |
1137 | } | |
1138 | ||
1139 | /* | |
1140 | * It is possible to hang here if another processor is remapping any pages we collide with and are removing | |
1141 | */ | |
1c79356b | 1142 | |
55e303ae A |
1143 | while(1) { /* Keep trying the enter until it goes in */ |
1144 | ||
0c530ab8 | 1145 | colva = mapping_make(pmap, va, pa, mflags, 1, (prot & VM_PROT_ALL) ); /* Enter the mapping into the pmap */ |
55e303ae A |
1146 | |
1147 | if(!colva) break; /* If there were no collisions, we are done... */ | |
1148 | ||
1149 | mapping_remove(pmap, colva); /* Remove the mapping that collided */ | |
1150 | } | |
55e303ae A |
1151 | } |
1152 | ||
1153 | /* | |
1154 | * Enters translations for odd-sized V=F blocks. | |
1155 | * | |
1156 | * The higher level VM map should be locked to insure that we don't have a | |
1157 | * double diddle here. | |
1158 | * | |
1159 | * We panic if we get a block that overlaps with another. We do not merge adjacent | |
1160 | * blocks because removing any address within a block removes the entire block and if | |
1161 | * would really mess things up if we trashed too much. | |
1162 | * | |
1163 | * Once a block is mapped, it is unmutable, that is, protection, catch mode, etc. can | |
1164 | * not be changed. The block must be unmapped and then remapped with the new stuff. | |
1165 | * We also do not keep track of reference or change flags. | |
1166 | * | |
3a60a9f5 A |
1167 | * Any block that is larger than 256MB must be a multiple of 32MB. We panic if it is not. |
1168 | * | |
55e303ae A |
1169 | * Note that pmap_map_block_rc is the same but doesn't panic if collision. |
1170 | * | |
1171 | */ | |
1172 | ||
3a60a9f5 | 1173 | void pmap_map_block(pmap_t pmap, addr64_t va, ppnum_t pa, uint32_t size, vm_prot_t prot, int attr, unsigned int flags) { /* Map an autogenned block */ |
55e303ae | 1174 | |
55e303ae A |
1175 | unsigned int mflags; |
1176 | addr64_t colva; | |
d7e50217 | 1177 | |
d7e50217 | 1178 | |
55e303ae A |
1179 | if (pmap == PMAP_NULL) { /* Did they give us a pmap? */ |
1180 | panic("pmap_map_block: null pmap\n"); /* No, like that's dumb... */ | |
1181 | } | |
d7e50217 | 1182 | |
55e303ae | 1183 | // kprintf("pmap_map_block: (%08X) va = %016llX, pa = %08X, size = %08X, prot = %08X, attr = %08X, flags = %08X\n", /* (BRINGUP) */ |
91447636 | 1184 | // current_thread(), va, pa, size, prot, attr, flags); /* (BRINGUP) */ |
d7e50217 | 1185 | |
55e303ae A |
1186 | mflags = mmFlgBlock | mmFlgUseAttr | (attr & VM_MEM_GUARDED) | ((attr & VM_MEM_NOT_CACHEABLE) >> 1); /* Convert to our mapping_make flags */ |
1187 | if(flags) mflags |= mmFlgPerm; /* Mark permanent if requested */ | |
1188 | ||
3a60a9f5 | 1189 | colva = mapping_make(pmap, va, pa, mflags, size, prot); /* Enter the mapping into the pmap */ |
55e303ae A |
1190 | |
1191 | if(colva) { /* If there was a collision, panic */ | |
2d21ac55 | 1192 | panic("pmap_map_block: mapping error %d, pmap = %p, va = %016llX\n", (uint32_t)(colva & mapRetCode), pmap, va); |
55e303ae A |
1193 | } |
1194 | ||
1195 | return; /* Return */ | |
1196 | } | |
de355530 | 1197 | |
3a60a9f5 | 1198 | int pmap_map_block_rc(pmap_t pmap, addr64_t va, ppnum_t pa, uint32_t size, vm_prot_t prot, int attr, unsigned int flags) { /* Map an autogenned block */ |
d7e50217 | 1199 | |
55e303ae A |
1200 | unsigned int mflags; |
1201 | addr64_t colva; | |
1202 | ||
1203 | ||
1204 | if (pmap == PMAP_NULL) { /* Did they give us a pmap? */ | |
1205 | panic("pmap_map_block_rc: null pmap\n"); /* No, like that's dumb... */ | |
1206 | } | |
1207 | ||
1208 | mflags = mmFlgBlock | mmFlgUseAttr | (attr & VM_MEM_GUARDED) | ((attr & VM_MEM_NOT_CACHEABLE) >> 1); /* Convert to our mapping_make flags */ | |
1209 | if(flags) mflags |= mmFlgPerm; /* Mark permanent if requested */ | |
3a60a9f5 A |
1210 | |
1211 | colva = mapping_make(pmap, va, pa, mflags, size, prot); /* Enter the mapping into the pmap */ | |
55e303ae A |
1212 | |
1213 | if(colva) return 0; /* If there was a collision, fail */ | |
1214 | ||
1215 | return 1; /* Return true of we worked */ | |
1c79356b A |
1216 | } |
1217 | ||
1218 | /* | |
1219 | * pmap_extract(pmap, va) | |
1220 | * returns the physical address corrsponding to the | |
1221 | * virtual address specified by pmap and va if the | |
1222 | * virtual address is mapped and 0 if it is not. | |
55e303ae A |
1223 | * Note: we assume nothing is ever mapped to phys 0. |
1224 | * | |
1225 | * NOTE: This call always will fail for physical addresses greater than 0xFFFFF000. | |
1c79356b | 1226 | */ |
91447636 | 1227 | vm_offset_t pmap_extract(pmap_t pmap, vm_map_offset_t va) { |
1c79356b A |
1228 | |
1229 | spl_t spl; | |
55e303ae | 1230 | register struct mapping *mp; |
1c79356b | 1231 | register vm_offset_t pa; |
55e303ae A |
1232 | addr64_t nextva; |
1233 | ppnum_t ppoffset; | |
1234 | unsigned int gva; | |
1c79356b | 1235 | |
55e303ae A |
1236 | #ifdef BOGUSCOMPAT |
1237 | panic("pmap_extract: THIS CALL IS BOGUS. NEVER USE IT EVER. So there...\n"); /* Don't use this */ | |
1238 | #else | |
d7e50217 | 1239 | |
55e303ae | 1240 | gva = (unsigned int)va; /* Make sure we don't have a sign */ |
1c79356b | 1241 | |
de355530 | 1242 | spl = splhigh(); /* We can't allow any loss of control here */ |
55e303ae A |
1243 | |
1244 | mp = mapping_find(pmap, (addr64_t)gva, &nextva,1); /* Find the mapping for this address */ | |
1245 | ||
1246 | if(!mp) { /* Is the page mapped? */ | |
1247 | splx(spl); /* Enable interrupts */ | |
1248 | return 0; /* Pass back 0 if not found */ | |
de355530 A |
1249 | } |
1250 | ||
55e303ae A |
1251 | ppoffset = (ppnum_t)(((gva & -4096LL) - (mp->mpVAddr & -4096LL)) >> 12); /* Get offset from va to base va */ |
1252 | ||
1253 | ||
1254 | pa = mp->mpPAddr + ppoffset; /* Remember ppage because mapping may vanish after drop call */ | |
1255 | ||
1256 | mapping_drop_busy(mp); /* We have everything we need from the mapping */ | |
d7e50217 | 1257 | splx(spl); /* Restore 'rupts */ |
55e303ae A |
1258 | |
1259 | if(pa > maxPPage32) return 0; /* Force large addresses to fail */ | |
1260 | ||
1261 | pa = (pa << 12) | (va & 0xFFF); /* Convert physical page number to address */ | |
1262 | ||
1263 | #endif | |
d7e50217 A |
1264 | return pa; /* Return physical address or 0 */ |
1265 | } | |
1266 | ||
de355530 | 1267 | /* |
55e303ae A |
1268 | * ppnum_t pmap_find_phys(pmap, addr64_t va) |
1269 | * returns the physical page corrsponding to the | |
1270 | * virtual address specified by pmap and va if the | |
1271 | * virtual address is mapped and 0 if it is not. | |
1272 | * Note: we assume nothing is ever mapped to phys 0. | |
1273 | * | |
de355530 | 1274 | */ |
55e303ae A |
1275 | ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va) { |
1276 | ||
1277 | spl_t spl; | |
1278 | register struct mapping *mp; | |
1279 | ppnum_t pa, ppoffset; | |
91447636 | 1280 | addr64_t nextva; |
55e303ae A |
1281 | |
1282 | spl = splhigh(); /* We can't allow any loss of control here */ | |
1283 | ||
1284 | mp = mapping_find(pmap, va, &nextva, 1); /* Find the mapping for this address */ | |
1285 | ||
1286 | if(!mp) { /* Is the page mapped? */ | |
1287 | splx(spl); /* Enable interrupts */ | |
1288 | return 0; /* Pass back 0 if not found */ | |
de355530 | 1289 | } |
55e303ae | 1290 | |
de355530 | 1291 | |
55e303ae A |
1292 | ppoffset = (ppnum_t)(((va & -4096LL) - (mp->mpVAddr & -4096LL)) >> 12); /* Get offset from va to base va */ |
1293 | ||
1294 | pa = mp->mpPAddr + ppoffset; /* Get the actual physical address */ | |
1295 | ||
1296 | mapping_drop_busy(mp); /* We have everything we need from the mapping */ | |
1297 | ||
1298 | splx(spl); /* Restore 'rupts */ | |
1299 | return pa; /* Return physical address or 0 */ | |
1300 | } | |
1301 | ||
9bccf70c | 1302 | |
1c79356b A |
1303 | /* |
1304 | * pmap_attributes: | |
1305 | * | |
55e303ae | 1306 | * Set/Get special memory attributes; not implemented. |
1c79356b A |
1307 | * |
1308 | * Note: 'VAL_GET_INFO' is used to return info about a page. | |
1309 | * If less than 1 page is specified, return the physical page | |
1310 | * mapping and a count of the number of mappings to that page. | |
1311 | * If more than one page is specified, return the number | |
1312 | * of resident pages and the number of shared (more than | |
1313 | * one mapping) pages in the range; | |
1314 | * | |
55e303ae | 1315 | * |
1c79356b A |
1316 | */ |
1317 | kern_return_t | |
91447636 A |
1318 | pmap_attribute( |
1319 | __unused pmap_t pmap, | |
1320 | __unused vm_map_offset_t address, | |
1321 | __unused vm_map_size_t size, | |
1322 | __unused vm_machine_attribute_t attribute, | |
1323 | __unused vm_machine_attribute_val_t* value) | |
1c79356b | 1324 | { |
55e303ae A |
1325 | |
1326 | return KERN_INVALID_ARGUMENT; | |
1327 | ||
1328 | } | |
1c79356b | 1329 | |
0c530ab8 A |
1330 | |
1331 | ||
1332 | unsigned int pmap_cache_attributes(ppnum_t pgn) { | |
1333 | ||
1334 | unsigned int flags; | |
1335 | struct phys_entry * pp; | |
1336 | ||
1337 | // Find physical address | |
1338 | if ((pp = pmap_find_physentry(pgn))) { | |
1339 | // Use physical attributes as default | |
1340 | // NOTE: DEVICE_PAGER_FLAGS are made to line up | |
1341 | flags = VM_MEM_COHERENT; /* We only support coherent memory */ | |
1342 | if (pp->ppLink & ppG) flags |= VM_MEM_GUARDED; /* Add in guarded if it is */ | |
1343 | if (pp->ppLink & ppI) flags |= VM_MEM_NOT_CACHEABLE; /* Add in cache inhibited if so */ | |
1344 | } else | |
1345 | // If no physical, just hard code attributes | |
1346 | flags = VM_WIMG_IO; | |
1347 | ||
1348 | return (flags); | |
1349 | } | |
1350 | ||
1351 | ||
1352 | ||
1c79356b | 1353 | /* |
55e303ae A |
1354 | * pmap_attribute_cache_sync(vm_offset_t pa) |
1355 | * | |
1356 | * Invalidates all of the instruction cache on a physical page and | |
1357 | * pushes any dirty data from the data cache for the same physical page | |
1c79356b | 1358 | */ |
55e303ae A |
1359 | |
1360 | kern_return_t pmap_attribute_cache_sync(ppnum_t pp, vm_size_t size, | |
91447636 A |
1361 | __unused vm_machine_attribute_t attribute, |
1362 | __unused vm_machine_attribute_val_t* value) { | |
d7e50217 | 1363 | |
55e303ae A |
1364 | spl_t s; |
1365 | unsigned int i, npages; | |
1366 | ||
91447636 | 1367 | npages = round_page(size) >> 12; /* Get the number of pages to do */ |
55e303ae A |
1368 | |
1369 | for(i = 0; i < npages; i++) { /* Do all requested pages */ | |
1370 | s = splhigh(); /* No interruptions here */ | |
1371 | sync_ppage(pp + i); /* Go flush data cache and invalidate icache */ | |
1372 | splx(s); /* Allow interruptions */ | |
1c79356b | 1373 | } |
55e303ae A |
1374 | |
1375 | return KERN_SUCCESS; | |
1c79356b A |
1376 | } |
1377 | ||
765c9de3 | 1378 | /* |
91447636 | 1379 | * pmap_sync_page_data_phys(ppnum_t pa) |
765c9de3 A |
1380 | * |
1381 | * Invalidates all of the instruction cache on a physical page and | |
1382 | * pushes any dirty data from the data cache for the same physical page | |
1383 | */ | |
1384 | ||
91447636 | 1385 | void pmap_sync_page_data_phys(ppnum_t pa) { |
765c9de3 A |
1386 | |
1387 | spl_t s; | |
55e303ae A |
1388 | |
1389 | s = splhigh(); /* No interruptions here */ | |
1390 | sync_ppage(pa); /* Sync up dem caches */ | |
1391 | splx(s); /* Allow interruptions */ | |
765c9de3 A |
1392 | return; |
1393 | } | |
1394 | ||
91447636 A |
1395 | void |
1396 | pmap_sync_page_attributes_phys(ppnum_t pa) | |
1397 | { | |
1398 | pmap_sync_page_data_phys(pa); | |
1399 | } | |
1400 | ||
2d21ac55 | 1401 | #ifdef CURRENTLY_UNUSED_AND_UNTESTED |
1c79356b A |
1402 | /* |
1403 | * pmap_collect | |
1404 | * | |
1405 | * Garbage collects the physical map system for pages that are no longer used. | |
1406 | * It isn't implemented or needed or wanted. | |
1407 | */ | |
1408 | void | |
91447636 | 1409 | pmap_collect(__unused pmap_t pmap) |
1c79356b A |
1410 | { |
1411 | return; | |
1412 | } | |
2d21ac55 | 1413 | #endif |
1c79356b A |
1414 | |
1415 | /* | |
1416 | * Routine: pmap_activate | |
1417 | * Function: | |
1418 | * Binds the given physical map to the given | |
1419 | * processor, and returns a hardware map description. | |
1420 | * It isn't implemented or needed or wanted. | |
1421 | */ | |
1422 | void | |
1423 | pmap_activate( | |
91447636 A |
1424 | __unused pmap_t pmap, |
1425 | __unused thread_t th, | |
1426 | __unused int which_cpu) | |
1c79356b A |
1427 | { |
1428 | return; | |
1429 | } | |
1430 | /* | |
1431 | * pmap_deactivate: | |
1432 | * It isn't implemented or needed or wanted. | |
1433 | */ | |
1434 | void | |
1435 | pmap_deactivate( | |
91447636 A |
1436 | __unused pmap_t pmap, |
1437 | __unused thread_t th, | |
1438 | __unused int which_cpu) | |
1c79356b A |
1439 | { |
1440 | return; | |
1441 | } | |
1442 | ||
1c79356b A |
1443 | |
1444 | /* | |
1445 | * pmap_pageable(pmap, s, e, pageable) | |
1446 | * Make the specified pages (by pmap, offset) | |
1447 | * pageable (or not) as requested. | |
1448 | * | |
1449 | * A page which is not pageable may not take | |
1450 | * a fault; therefore, its page table entry | |
1451 | * must remain valid for the duration. | |
1452 | * | |
1453 | * This routine is merely advisory; pmap_enter() | |
1454 | * will specify that these pages are to be wired | |
1455 | * down (or not) as appropriate. | |
1456 | * | |
1457 | * (called from vm/vm_fault.c). | |
1458 | */ | |
1459 | void | |
1460 | pmap_pageable( | |
91447636 A |
1461 | __unused pmap_t pmap, |
1462 | __unused vm_map_offset_t start, | |
1463 | __unused vm_map_offset_t end, | |
1464 | __unused boolean_t pageable) | |
1c79356b A |
1465 | { |
1466 | ||
1467 | return; /* This is not used... */ | |
1468 | ||
1469 | } | |
1470 | /* | |
1471 | * Routine: pmap_change_wiring | |
55e303ae | 1472 | * NOT USED ANYMORE. |
1c79356b A |
1473 | */ |
1474 | void | |
1475 | pmap_change_wiring( | |
91447636 A |
1476 | __unused pmap_t pmap, |
1477 | __unused vm_map_offset_t va, | |
1478 | __unused boolean_t wired) | |
1c79356b A |
1479 | { |
1480 | return; /* This is not used... */ | |
1481 | } | |
1482 | ||
1c79356b A |
1483 | /* |
1484 | * pmap_clear_modify(phys) | |
1485 | * clears the hardware modified ("dirty") bit for one | |
1486 | * machine independant page starting at the given | |
1487 | * physical address. phys must be aligned on a machine | |
1488 | * independant page boundary. | |
1489 | */ | |
1490 | void | |
91447636 | 1491 | pmap_clear_modify(ppnum_t pa) |
1c79356b | 1492 | { |
1c79356b | 1493 | |
91447636 | 1494 | mapping_clr_mod(pa); /* Clear all change bits for physical page */ |
de355530 | 1495 | |
1c79356b A |
1496 | } |
1497 | ||
1498 | /* | |
1499 | * pmap_is_modified(phys) | |
1500 | * returns TRUE if the given physical page has been modified | |
1501 | * since the last call to pmap_clear_modify(). | |
1502 | */ | |
1503 | boolean_t | |
91447636 | 1504 | pmap_is_modified(register ppnum_t pa) |
1c79356b | 1505 | { |
91447636 | 1506 | return mapping_tst_mod(pa); /* Check for modified */ |
de355530 | 1507 | |
1c79356b A |
1508 | } |
1509 | ||
1510 | /* | |
1511 | * pmap_clear_reference(phys) | |
1512 | * clears the hardware referenced bit in the given machine | |
1513 | * independant physical page. | |
1514 | * | |
1515 | */ | |
1516 | void | |
91447636 | 1517 | pmap_clear_reference(ppnum_t pa) |
1c79356b | 1518 | { |
91447636 | 1519 | mapping_clr_ref(pa); /* Check for modified */ |
1c79356b A |
1520 | } |
1521 | ||
1522 | /* | |
1523 | * pmap_is_referenced(phys) | |
1524 | * returns TRUE if the given physical page has been referenced | |
1525 | * since the last call to pmap_clear_reference(). | |
1526 | */ | |
1527 | boolean_t | |
91447636 | 1528 | pmap_is_referenced(ppnum_t pa) |
1c79356b | 1529 | { |
91447636 | 1530 | return mapping_tst_ref(pa); /* Check for referenced */ |
55e303ae | 1531 | } |
de355530 | 1532 | |
55e303ae | 1533 | /* |
91447636 A |
1534 | * pmap_get_refmod(phys) |
1535 | * returns the referenced and modified bits of the specified | |
1536 | * physical page. | |
55e303ae | 1537 | */ |
91447636 A |
1538 | unsigned int |
1539 | pmap_get_refmod(ppnum_t pa) | |
1540 | { | |
1541 | return (mapping_tst_refmod(pa)); | |
1542 | } | |
1543 | ||
1544 | /* | |
1545 | * pmap_clear_refmod(phys, mask) | |
1546 | * clears the referenced and modified bits as specified by the mask | |
1547 | * of the specified physical page. | |
1548 | */ | |
1549 | void | |
1550 | pmap_clear_refmod(ppnum_t pa, unsigned int mask) | |
1551 | { | |
1552 | mapping_clr_refmod(pa, mask); | |
1553 | } | |
1554 | ||
1555 | /* | |
1556 | * pmap_eligible_for_execute(ppnum_t pa) | |
1557 | * return true if physical address is eligible to contain executable code; | |
1558 | * otherwise, return false | |
1559 | */ | |
1560 | boolean_t | |
1561 | pmap_eligible_for_execute(ppnum_t pa) | |
1562 | { | |
1563 | phys_entry_t *physent; | |
1564 | unsigned int pindex; | |
de355530 | 1565 | |
55e303ae | 1566 | physent = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ |
1c79356b | 1567 | |
91447636 A |
1568 | if((!physent) || (physent->ppLink & ppG)) |
1569 | return 0; /* If there is no physical entry or marked guarded, | |
1570 | the entry is not eligible for execute */ | |
1c79356b | 1571 | |
91447636 | 1572 | return 1; /* Otherwise, entry is eligible for execute */ |
1c79356b A |
1573 | } |
1574 | ||
1575 | #if MACH_VM_DEBUG | |
1576 | int | |
1577 | pmap_list_resident_pages( | |
91447636 A |
1578 | __unused pmap_t pmap, |
1579 | __unused vm_offset_t *listp, | |
1580 | __unused int space) | |
1c79356b A |
1581 | { |
1582 | return 0; | |
1583 | } | |
1584 | #endif /* MACH_VM_DEBUG */ | |
1585 | ||
1586 | /* | |
1587 | * Locking: | |
1588 | * spl: VM | |
1589 | */ | |
1590 | void | |
1591 | pmap_copy_part_page( | |
1592 | vm_offset_t src, | |
1593 | vm_offset_t src_offset, | |
1594 | vm_offset_t dst, | |
1595 | vm_offset_t dst_offset, | |
1596 | vm_size_t len) | |
1597 | { | |
55e303ae | 1598 | addr64_t fsrc, fdst; |
1c79356b | 1599 | |
2d21ac55 A |
1600 | assert((((dst << 12) & PAGE_MASK) + dst_offset + len) <= PAGE_SIZE); |
1601 | assert((((src << 12) & PAGE_MASK) + src_offset + len) <= PAGE_SIZE); | |
1c79356b | 1602 | |
55e303ae A |
1603 | fsrc = ((addr64_t)src << 12) + src_offset; |
1604 | fdst = ((addr64_t)dst << 12) + dst_offset; | |
de355530 | 1605 | |
55e303ae | 1606 | phys_copy(fsrc, fdst, len); /* Copy the stuff physically */ |
1c79356b A |
1607 | } |
1608 | ||
1609 | void | |
1610 | pmap_zero_part_page( | |
91447636 A |
1611 | __unused vm_offset_t p, |
1612 | __unused vm_offset_t offset, | |
1613 | __unused vm_size_t len) | |
1c79356b A |
1614 | { |
1615 | panic("pmap_zero_part_page"); | |
1616 | } | |
1617 | ||
55e303ae | 1618 | boolean_t pmap_verify_free(ppnum_t pa) { |
1c79356b A |
1619 | |
1620 | struct phys_entry *pp; | |
55e303ae | 1621 | unsigned int pindex; |
1c79356b | 1622 | |
55e303ae A |
1623 | pp = mapping_phys_lookup(pa, &pindex); /* Get physical entry */ |
1624 | if (pp == 0) return FALSE; /* If there isn't one, show no mapping... */ | |
1c79356b | 1625 | |
91447636 A |
1626 | if(pp->ppLink & ~(ppLock | ppFlags)) return FALSE; /* We have at least one mapping */ |
1627 | return TRUE; /* No mappings */ | |
1c79356b A |
1628 | } |
1629 | ||
1630 | ||
1631 | /* Determine if we need to switch space and set up for it if so */ | |
1632 | ||
1633 | void pmap_switch(pmap_t map) | |
1634 | { | |
91447636 A |
1635 | hw_blow_seg(lowGlo.lgUMWvaddr); /* Blow off the first segment */ |
1636 | hw_blow_seg(lowGlo.lgUMWvaddr + 0x10000000ULL); /* Blow off the second segment */ | |
1c79356b A |
1637 | |
1638 | /* when changing to kernel space, don't bother | |
1639 | * doing anything, the kernel is mapped from here already. | |
1640 | */ | |
1641 | if (map->space == PPC_SID_KERNEL) { /* Are we switching into kernel space? */ | |
1642 | return; /* If so, we don't do anything... */ | |
1643 | } | |
1644 | ||
1645 | hw_set_user_space(map); /* Indicate if we need to load the SRs or not */ | |
1646 | return; /* Bye, bye, butterfly... */ | |
1647 | } | |
1648 | ||
2d21ac55 A |
1649 | |
1650 | /* | |
1651 | * The PPC pmap can only nest segments of 256MB, aligned on a 256MB boundary. | |
1652 | */ | |
1653 | uint64_t pmap_nesting_size_min = 0x10000000ULL; | |
1654 | uint64_t pmap_nesting_size_max = 0x10000000ULL; | |
1655 | ||
1c79356b | 1656 | /* |
55e303ae | 1657 | * kern_return_t pmap_nest(grand, subord, vstart, size) |
1c79356b A |
1658 | * |
1659 | * grand = the pmap that we will nest subord into | |
1660 | * subord = the pmap that goes into the grand | |
55e303ae A |
1661 | * vstart = start of range in pmap to be inserted |
1662 | * nstart = start of range in pmap nested pmap | |
3a60a9f5 | 1663 | * size = Size of nest area (up to 2TB) |
1c79356b A |
1664 | * |
1665 | * Inserts a pmap into another. This is used to implement shared segments. | |
1666 | * On the current PPC processors, this is limited to segment (256MB) aligned | |
1667 | * segment sized ranges. | |
55e303ae A |
1668 | * |
1669 | * We actually kinda allow recursive nests. The gating factor is that we do not allow | |
1670 | * nesting on top of something that is already mapped, i.e., the range must be empty. | |
1671 | * | |
55e303ae A |
1672 | * Note that we depend upon higher level VM locks to insure that things don't change while |
1673 | * we are doing this. For example, VM should not be doing any pmap enters while it is nesting | |
1674 | * or do 2 nests at once. | |
1c79356b A |
1675 | */ |
1676 | ||
55e303ae A |
1677 | kern_return_t pmap_nest(pmap_t grand, pmap_t subord, addr64_t vstart, addr64_t nstart, uint64_t size) { |
1678 | ||
91447636 | 1679 | addr64_t vend, colladdr; |
55e303ae | 1680 | unsigned int msize; |
91447636 A |
1681 | int nlists; |
1682 | mapping_t *mp; | |
d7e50217 | 1683 | |
55e303ae | 1684 | if(size & 0x0FFFFFFFULL) return KERN_INVALID_VALUE; /* We can only do this for multiples of 256MB */ |
3a60a9f5 | 1685 | if((size >> 25) > 65536) return KERN_INVALID_VALUE; /* Max size we can nest is 2TB */ |
55e303ae A |
1686 | if(vstart & 0x0FFFFFFFULL) return KERN_INVALID_VALUE; /* We can only do this aligned to 256MB */ |
1687 | if(nstart & 0x0FFFFFFFULL) return KERN_INVALID_VALUE; /* We can only do this aligned to 256MB */ | |
1688 | ||
1689 | if(size == 0) { /* Is the size valid? */ | |
1690 | panic("pmap_nest: size is invalid - %016llX\n", size); | |
de355530 | 1691 | } |
1c79356b | 1692 | |
3a60a9f5 | 1693 | msize = (size >> 25) - 1; /* Change size to blocks of 32MB */ |
55e303ae A |
1694 | |
1695 | nlists = mapSetLists(grand); /* Set number of lists this will be on */ | |
de355530 | 1696 | |
55e303ae | 1697 | mp = mapping_alloc(nlists); /* Get a spare mapping block */ |
1c79356b | 1698 | |
3a60a9f5 | 1699 | mp->mpFlags = 0x01000000 | mpNest | mpPerm | mpBSu | nlists; /* Make this a permanent nested pmap with a 32MB basic size unit */ |
91447636 | 1700 | /* Set the flags. Make sure busy count is 1 */ |
55e303ae | 1701 | mp->mpSpace = subord->space; /* Set the address space/pmap lookup ID */ |
91447636 | 1702 | mp->u.mpBSize = msize; /* Set the size */ |
55e303ae A |
1703 | mp->mpPte = 0; /* Set the PTE invalid */ |
1704 | mp->mpPAddr = 0; /* Set the physical page number */ | |
1705 | mp->mpVAddr = vstart; /* Set the address */ | |
1706 | mp->mpNestReloc = nstart - vstart; /* Set grand to nested vaddr relocation value */ | |
d7e50217 | 1707 | |
55e303ae A |
1708 | colladdr = hw_add_map(grand, mp); /* Go add the mapping to the pmap */ |
1709 | ||
1710 | if(colladdr) { /* Did it collide? */ | |
1711 | vend = vstart + size - 4096; /* Point to the last page we would cover in nest */ | |
2d21ac55 | 1712 | panic("pmap_nest: attempt to nest into a non-empty range - pmap = %p, start = %016llX, end = %016llX\n", |
55e303ae | 1713 | grand, vstart, vend); |
1c79356b | 1714 | } |
55e303ae A |
1715 | |
1716 | return KERN_SUCCESS; | |
1c79356b A |
1717 | } |
1718 | ||
1c79356b | 1719 | /* |
2d21ac55 | 1720 | * kern_return_t pmap_unnest(grand, vaddr, size) |
1c79356b A |
1721 | * |
1722 | * grand = the pmap that we will nest subord into | |
55e303ae | 1723 | * vaddr = start of range in pmap to be unnested |
2d21ac55 | 1724 | * size = size of range in pmap to be unnested |
1c79356b A |
1725 | * |
1726 | * Removes a pmap from another. This is used to implement shared segments. | |
1727 | * On the current PPC processors, this is limited to segment (256MB) aligned | |
1728 | * segment sized ranges. | |
1729 | */ | |
1730 | ||
2d21ac55 | 1731 | kern_return_t pmap_unnest(pmap_t grand, addr64_t vaddr, uint64_t size) { |
1c79356b | 1732 | |
91447636 | 1733 | unsigned int tstamp, i, mycpu; |
55e303ae A |
1734 | addr64_t nextva; |
1735 | spl_t s; | |
91447636 | 1736 | mapping_t *mp; |
1c79356b | 1737 | |
2d21ac55 A |
1738 | if (size != pmap_nesting_size_min || |
1739 | (vaddr & (pmap_nesting_size_min-1))) { | |
1740 | panic("pmap_unnest(vaddr=0x%016llx, size=0x016%llx): " | |
1741 | "must be 256MB and aligned\n", | |
1742 | vaddr, size); | |
1743 | } | |
1744 | ||
55e303ae A |
1745 | s = splhigh(); /* Make sure interruptions are disabled */ |
1746 | ||
1747 | mp = mapping_find(grand, vaddr, &nextva, 0); /* Find the nested map */ | |
1748 | ||
1749 | if(((unsigned int)mp & mapRetCode) != mapRtOK) { /* See if it was even nested */ | |
1750 | panic("pmap_unnest: Attempt to unnest an unnested segment - va = %016llX\n", vaddr); | |
1751 | } | |
1752 | ||
91447636 | 1753 | if((mp->mpFlags & mpType) != mpNest) { /* Did we find something other than a nest? */ |
55e303ae | 1754 | panic("pmap_unnest: Attempt to unnest something that is not a nest - va = %016llX\n", vaddr); |
1c79356b A |
1755 | } |
1756 | ||
55e303ae A |
1757 | if(mp->mpVAddr != vaddr) { /* Make sure the address is the same */ |
1758 | panic("pmap_unnest: Attempt to unnest something that is not at start of nest - va = %016llX\n", vaddr); | |
1759 | } | |
1c79356b | 1760 | |
b0d623f7 | 1761 | hw_atomic_and_noret(&mp->mpFlags, ~mpPerm); /* Show that this mapping is now removable */ |
1c79356b | 1762 | |
91447636 | 1763 | mapping_drop_busy(mp); /* Go ahead and release the mapping now */ |
1c79356b | 1764 | |
55e303ae A |
1765 | splx(s); /* Restore 'rupts */ |
1766 | ||
1767 | (void)mapping_remove(grand, vaddr); /* Toss the nested pmap mapping */ | |
1768 | ||
1769 | invalidateSegs(grand); /* Invalidate the pmap segment cache */ | |
1770 | ||
1c79356b A |
1771 | /* |
1772 | * Note that the following will force the segment registers to be reloaded | |
1773 | * on all processors (if they are using the pmap we just changed) before returning. | |
1774 | * | |
1775 | * This is needed. The reason is that until the segment register is | |
1776 | * reloaded, another thread in the same task on a different processor will | |
1777 | * be able to access memory that it isn't allowed to anymore. That can happen | |
1778 | * because access to the subordinate pmap is being removed, but the pmap is still | |
1779 | * valid. | |
1780 | * | |
1781 | * Note that we only kick the other processor if we see that it was using the pmap while we | |
1782 | * were changing it. | |
1783 | */ | |
1784 | ||
1785 | ||
55e303ae | 1786 | for(i=0; i < real_ncpus; i++) { /* Cycle through processors */ |
91447636 A |
1787 | disable_preemption(); |
1788 | mycpu = cpu_number(); /* Who am I? Am I just a dream? */ | |
1789 | if((unsigned int)grand == PerProcTable[i].ppe_vaddr->ppUserPmapVirt) { /* Is this guy using the changed pmap? */ | |
55e303ae | 1790 | |
91447636 | 1791 | PerProcTable[i].ppe_vaddr->ppInvSeg = 1; /* Show that we need to invalidate the segments */ |
55e303ae | 1792 | |
91447636 | 1793 | if(i != mycpu) { |
55e303ae | 1794 | |
91447636 A |
1795 | tstamp = PerProcTable[i].ppe_vaddr->ruptStamp[1]; /* Save the processor's last interrupt time stamp */ |
1796 | if(cpu_signal(i, SIGPcpureq, CPRQsegload, 0) == KERN_SUCCESS) { /* Make sure we see the pmap change */ | |
1797 | if(!hw_cpu_wcng(&PerProcTable[i].ppe_vaddr->ruptStamp[1], tstamp, LockTimeOut)) { /* Wait for the other processors to enter debug */ | |
1798 | panic("pmap_unnest: Other processor (%d) did not see interruption request\n", i); | |
1799 | } | |
1800 | } | |
1c79356b A |
1801 | } |
1802 | } | |
91447636 | 1803 | enable_preemption(); |
1c79356b A |
1804 | } |
1805 | ||
55e303ae | 1806 | return KERN_SUCCESS; /* Bye, bye, butterfly... */ |
1c79356b A |
1807 | } |
1808 | ||
b0d623f7 A |
1809 | boolean_t pmap_adjust_unnest_parameters(__unused pmap_t p, __unused vm_map_offset_t *s, __unused vm_map_offset_t *e) { |
1810 | return FALSE; /* Not implemented on PowerPC */ | |
1811 | } | |
1c79356b | 1812 | |
55e303ae | 1813 | /* |
91447636 | 1814 | * void MapUserMemoryWindowInit(void) |
55e303ae | 1815 | * |
91447636 | 1816 | * Initialize anything we need to in order to map user address space slices into |
55e303ae A |
1817 | * the kernel. Primarily used for copy in/out. |
1818 | * | |
1819 | * Currently we only support one 512MB slot for this purpose. There are two special | |
1820 | * mappings defined for the purpose: the special pmap nest, and linkage mapping. | |
1821 | * | |
1822 | * The special pmap nest (which is allocated in this function) is used as a place holder | |
1823 | * in the kernel's pmap search list. It is 512MB long and covers the address range | |
91447636 | 1824 | * starting at lgUMWvaddr. It points to no actual memory and when the fault handler |
55e303ae A |
1825 | * hits in it, it knows to look in the per_proc and start using the linkage |
1826 | * mapping contained therin. | |
1827 | * | |
1828 | * The linkage mapping is used to glue the user address space slice into the | |
1829 | * kernel. It contains the relocation information used to transform the faulting | |
1830 | * kernel address into the user address space. It also provides the link to the | |
1831 | * user's pmap. This is pointed to by the per_proc and is switched in and out | |
1832 | * whenever there is a context switch. | |
1833 | * | |
1834 | */ | |
1835 | ||
91447636 | 1836 | void MapUserMemoryWindowInit(void) { |
55e303ae A |
1837 | |
1838 | addr64_t colladdr; | |
91447636 A |
1839 | int nlists; |
1840 | mapping_t *mp; | |
55e303ae A |
1841 | |
1842 | nlists = mapSetLists(kernel_pmap); /* Set number of lists this will be on */ | |
1843 | ||
1844 | mp = mapping_alloc(nlists); /* Get a spare mapping block */ | |
91447636 | 1845 | |
3a60a9f5 | 1846 | mp->mpFlags = 0x01000000 | mpLinkage | mpPerm | mpBSu | nlists; /* Make this a permanent nested pmap with a 32MB basic size unit */ |
91447636 | 1847 | /* Set the flags. Make sure busy count is 1 */ |
55e303ae | 1848 | mp->mpSpace = kernel_pmap->space; /* Set the address space/pmap lookup ID */ |
3a60a9f5 | 1849 | mp->u.mpBSize = 15; /* Set the size to 2 segments in 32MB chunks - 1 */ |
55e303ae A |
1850 | mp->mpPte = 0; /* Means nothing */ |
1851 | mp->mpPAddr = 0; /* Means nothing */ | |
91447636 | 1852 | mp->mpVAddr = lowGlo.lgUMWvaddr; /* Set the address range we cover */ |
55e303ae A |
1853 | mp->mpNestReloc = 0; /* Means nothing */ |
1854 | ||
1855 | colladdr = hw_add_map(kernel_pmap, mp); /* Go add the mapping to the pmap */ | |
1856 | ||
1857 | if(colladdr) { /* Did it collide? */ | |
91447636 | 1858 | panic("MapUserMemoryWindowInit: MapUserMemoryWindow range already mapped\n"); |
55e303ae A |
1859 | } |
1860 | ||
1861 | return; | |
1862 | } | |
1863 | ||
1864 | /* | |
91447636 | 1865 | * addr64_t MapUserMemoryWindow(vm_map_t map, vm_offset_t va, size) |
55e303ae A |
1866 | * |
1867 | * map = the vm_map that we are mapping into the kernel | |
1868 | * va = start of the address range we are mapping | |
55e303ae A |
1869 | * Note that we do not test validty, we chose to trust our fellows... |
1870 | * | |
91447636 A |
1871 | * Maps a 512M slice of a user address space into a predefined kernel range |
1872 | * on a per-thread basis. We map only the first 256M segment, allowing the | |
1873 | * second 256M segment to fault in as needed. This allows our clients to access | |
1874 | * an arbitrarily aligned operand up to 256M in size. | |
1875 | * | |
1876 | * In the future, the restriction of a predefined range may be loosened. | |
55e303ae A |
1877 | * |
1878 | * Builds the proper linkage map to map the user range | |
1879 | * We will round this down to the previous segment boundary and calculate | |
1880 | * the relocation to the kernel slot | |
1881 | * | |
1882 | * We always make a segment table entry here if we need to. This is mainly because of | |
1883 | * copyin/out and if we don't, there will be multiple segment faults for | |
1884 | * each system call. I have seen upwards of 30000 per second. | |
1885 | * | |
1886 | * We do check, however, to see if the slice is already mapped and if so, | |
1887 | * we just exit. This is done for performance reasons. It was found that | |
1888 | * there was a considerable boost in copyin/out performance if we did not | |
1889 | * invalidate the segment at ReleaseUserAddressSpace time, so we dumped the | |
91447636 | 1890 | * restriction that you had to bracket MapUserMemoryWindow. Further, there |
55e303ae A |
1891 | * is a yet further boost if you didn't need to map it each time. The theory |
1892 | * behind this is that many times copies are to or from the same segment and | |
1893 | * done multiple times within the same system call. To take advantage of that, | |
91447636 | 1894 | * we check umwSpace and umwRelo to see if we've already got it. |
55e303ae A |
1895 | * |
1896 | * We also need to half-invalidate the slice when we context switch or go | |
1897 | * back to user state. A half-invalidate does not clear the actual mapping, | |
91447636 | 1898 | * but it does force the MapUserMemoryWindow function to reload the segment |
55e303ae A |
1899 | * register/SLBE. If this is not done, we can end up some pretty severe |
1900 | * performance penalties. If we map a slice, and the cached space/relocation is | |
1901 | * the same, we won't reload the segment registers. Howver, since we ran someone else, | |
1902 | * our SR is cleared and we will take a fault. This is reasonable if we block | |
1903 | * while copying (e.g., we took a page fault), but it is not reasonable when we | |
1904 | * just start. For this reason, we half-invalidate to make sure that the SR is | |
1905 | * explicitly reloaded. | |
1906 | * | |
1907 | * Note that we do not go to the trouble of making a pmap segment cache | |
1908 | * entry for these guys because they are very short term -- 99.99% of the time | |
1909 | * they will be unmapped before the next context switch. | |
1910 | * | |
1911 | */ | |
1c79356b | 1912 | |
91447636 A |
1913 | addr64_t MapUserMemoryWindow( |
1914 | vm_map_t map, | |
1915 | addr64_t va) { | |
55e303ae A |
1916 | |
1917 | addr64_t baddrs, reladd; | |
91447636 A |
1918 | thread_t thread; |
1919 | mapping_t *mp; | |
1c79356b | 1920 | |
55e303ae | 1921 | baddrs = va & 0xFFFFFFFFF0000000ULL; /* Isolate the segment */ |
91447636 | 1922 | thread = current_thread(); /* Remember our activation */ |
d7e50217 | 1923 | |
91447636 | 1924 | reladd = baddrs - lowGlo.lgUMWvaddr; /* Get the relocation from user to kernel */ |
d7e50217 | 1925 | |
91447636 A |
1926 | if((thread->machine.umwSpace == map->pmap->space) && (thread->machine.umwRelo == reladd)) { /* Already mapped? */ |
1927 | return ((va & 0x0FFFFFFFULL) | lowGlo.lgUMWvaddr); /* Pass back the kernel address we are to use */ | |
1c79356b | 1928 | } |
55e303ae A |
1929 | |
1930 | disable_preemption(); /* Don't move... */ | |
55e303ae | 1931 | |
91447636 A |
1932 | mp = (mapping_t *)&(getPerProc()->ppUMWmp); /* Make up for C */ |
1933 | thread->machine.umwRelo = reladd; /* Relocation from user to kernel */ | |
55e303ae A |
1934 | mp->mpNestReloc = reladd; /* Relocation from user to kernel */ |
1935 | ||
91447636 | 1936 | thread->machine.umwSpace = map->pmap->space; /* Set the address space/pmap lookup ID */ |
55e303ae A |
1937 | mp->mpSpace = map->pmap->space; /* Set the address space/pmap lookup ID */ |
1938 | ||
1939 | /* | |
1940 | * Here we make an assumption that we are going to be using the base pmap's address space. | |
1941 | * If we are wrong, and that would be very, very, very rare, the fault handler will fix us up. | |
1942 | */ | |
1943 | ||
91447636 | 1944 | hw_map_seg(map->pmap, lowGlo.lgUMWvaddr, baddrs); /* Make the entry for the first segment */ |
55e303ae | 1945 | |
55e303ae | 1946 | enable_preemption(); /* Let's move */ |
91447636 | 1947 | return ((va & 0x0FFFFFFFULL) | lowGlo.lgUMWvaddr); /* Pass back the kernel address we are to use */ |
55e303ae A |
1948 | } |
1949 | ||
2d21ac55 A |
1950 | #if CONFIG_DTRACE |
1951 | /* | |
1952 | * Constrain DTrace copyin/copyout actions | |
1953 | */ | |
1954 | extern kern_return_t dtrace_copyio_preflight(addr64_t); | |
1955 | extern kern_return_t dtrace_copyio_postflight(addr64_t); | |
1956 | ||
1957 | kern_return_t dtrace_copyio_preflight(__unused addr64_t va) | |
1958 | { | |
1959 | if (current_map() == kernel_map) | |
1960 | return KERN_FAILURE; | |
1961 | else | |
1962 | return KERN_SUCCESS; | |
1963 | } | |
1964 | ||
1965 | kern_return_t dtrace_copyio_postflight(__unused addr64_t va) | |
1966 | { | |
1967 | thread_t thread = current_thread(); | |
1968 | ||
1969 | thread->machine.umwSpace |= umwSwitchAway; | |
1970 | return KERN_SUCCESS; | |
1971 | } | |
1972 | #endif /* CONFIG_DTRACE */ | |
55e303ae | 1973 | |
55e303ae A |
1974 | /* |
1975 | * kern_return_t pmap_boot_map(size) | |
1976 | * | |
1977 | * size = size of virtual address range to be mapped | |
1978 | * | |
1979 | * This function is used to assign a range of virtual addresses before VM in | |
1980 | * initialized. It starts at VM_MAX_KERNEL_ADDRESS and works downward. | |
1981 | * The variable vm_last_addr contains the current highest possible VM | |
1982 | * assignable address. It is a panic to attempt to call this after VM has | |
1983 | * started up. The only problem is, is that we may not have the serial or | |
1984 | * framebuffer mapped, so we'll never know we died......... | |
1985 | */ | |
1986 | ||
1987 | vm_offset_t pmap_boot_map(vm_size_t size) { | |
1988 | ||
1989 | if(kernel_map != VM_MAP_NULL) { /* Has VM already started? */ | |
1990 | panic("pmap_boot_map: VM started\n"); | |
1c79356b | 1991 | } |
55e303ae | 1992 | |
91447636 | 1993 | size = round_page(size); /* Make sure this is in pages */ |
55e303ae A |
1994 | vm_last_addr = vm_last_addr - size; /* Allocate the memory */ |
1995 | return (vm_last_addr + 1); /* Return the vaddr we just allocated */ | |
1996 | ||
1c79356b A |
1997 | } |
1998 | ||
1999 | ||
91447636 A |
2000 | /* |
2001 | * void pmap_init_sharedpage(void); | |
2002 | * | |
2003 | * Hack map for the 64-bit commpage | |
2004 | */ | |
2005 | ||
2006 | void pmap_init_sharedpage(vm_offset_t cpg){ | |
2007 | ||
2008 | addr64_t cva, cpoff; | |
2009 | ppnum_t cpphys; | |
2010 | ||
0c530ab8 | 2011 | sharedPmap = pmap_create(0, FALSE); /* Get a pmap to hold the common segment */ |
91447636 A |
2012 | if(!sharedPmap) { /* Check for errors */ |
2013 | panic("pmap_init_sharedpage: couldn't make sharedPmap\n"); | |
2014 | } | |
2015 | ||
2016 | for(cpoff = 0; cpoff < _COMM_PAGE_AREA_USED; cpoff += 4096) { /* Step along now */ | |
2017 | ||
2018 | cpphys = pmap_find_phys(kernel_pmap, (addr64_t)cpg + cpoff); | |
2019 | if(!cpphys) { | |
2d21ac55 | 2020 | panic("pmap_init_sharedpage: compage %016llX not mapped in kernel\n", cpg + cpoff); |
91447636 A |
2021 | } |
2022 | ||
2023 | cva = mapping_make(sharedPmap, (addr64_t)((uint32_t)_COMM_PAGE_BASE_ADDRESS) + cpoff, | |
0c530ab8 | 2024 | cpphys, mmFlgPerm, 1, VM_PROT_READ | VM_PROT_EXECUTE); /* Map the page read/execute only */ |
91447636 A |
2025 | if(cva) { /* Check for errors */ |
2026 | panic("pmap_init_sharedpage: couldn't map commpage page - cva = %016llX\n", cva); | |
2027 | } | |
2028 | ||
2029 | } | |
2030 | ||
2031 | return; | |
2032 | } | |
2033 | ||
2034 | ||
2035 | /* | |
2036 | * void pmap_map_sharedpage(pmap_t pmap); | |
2037 | * | |
2038 | * Maps the last segment in a 64-bit address space | |
2039 | * | |
2040 | * | |
2041 | */ | |
2042 | ||
2043 | void pmap_map_sharedpage(task_t task, pmap_t pmap){ | |
2044 | ||
2045 | kern_return_t ret; | |
2046 | ||
2047 | if(task_has_64BitAddr(task) || _cpu_capabilities & k64Bit) { /* Should we map the 64-bit page -1? */ | |
2048 | ret = pmap_nest(pmap, sharedPmap, 0xFFFFFFFFF0000000ULL, 0x00000000F0000000ULL, | |
2049 | 0x0000000010000000ULL); /* Nest the highest possible segment to map comm page */ | |
2050 | if(ret != KERN_SUCCESS) { /* Did it work? */ | |
2051 | panic("pmap_map_sharedpage: couldn't nest shared page - ret = %08X\n", ret); | |
2052 | } | |
2053 | } | |
2054 | ||
2055 | return; | |
2056 | } | |
2057 | ||
2058 | ||
2059 | /* | |
2060 | * void pmap_unmap_sharedpage(pmap_t pmap); | |
2061 | * | |
2062 | * Unmaps the last segment in a 64-bit address space | |
2063 | * | |
2064 | */ | |
2065 | ||
2066 | void pmap_unmap_sharedpage(pmap_t pmap){ | |
2067 | ||
2068 | kern_return_t ret; | |
2069 | mapping_t *mp; | |
2070 | boolean_t inter; | |
2071 | int gotnest; | |
2072 | addr64_t nextva; | |
2073 | ||
2074 | if(BootProcInfo.pf.Available & pf64Bit) { /* Are we on a 64-bit machine? */ | |
2075 | ||
2076 | inter = ml_set_interrupts_enabled(FALSE); /* Disable interruptions for now */ | |
2077 | mp = hw_find_map(pmap, 0xFFFFFFFFF0000000ULL, &nextva); /* Find the mapping for this address */ | |
2078 | if((unsigned int)mp == mapRtBadLk) { /* Did we lock up ok? */ | |
2d21ac55 | 2079 | panic("pmap_unmap_sharedpage: mapping lock failure - rc = %p, pmap = %p\n", mp, pmap); /* Die... */ |
91447636 A |
2080 | } |
2081 | ||
2082 | gotnest = 0; /* Assume nothing here */ | |
2083 | if(mp) { | |
2084 | gotnest = ((mp->mpFlags & mpType) == mpNest); | |
2085 | /* Remember if we have a nest here */ | |
2086 | mapping_drop_busy(mp); /* We have everything we need from the mapping */ | |
2087 | } | |
2088 | ml_set_interrupts_enabled(inter); /* Put interrupts back to what they were */ | |
2089 | ||
2090 | if(!gotnest) return; /* Leave if there isn't any nesting here */ | |
2091 | ||
2d21ac55 | 2092 | ret = pmap_unnest(pmap, 0xFFFFFFFFF0000000ULL, 0x0000000010000000ULL); /* Unnest the max 64-bit page */ |
91447636 A |
2093 | |
2094 | if(ret != KERN_SUCCESS) { /* Did it work? */ | |
2095 | panic("pmap_unmap_sharedpage: couldn't unnest shared page - ret = %08X\n", ret); | |
2096 | } | |
2097 | } | |
2098 | ||
2099 | return; | |
2100 | } | |
2101 | ||
55e303ae | 2102 | |
9bccf70c A |
2103 | /* temporary workaround */ |
2104 | boolean_t | |
91447636 A |
2105 | coredumpok( |
2106 | __unused vm_map_t map, | |
2107 | __unused vm_offset_t va) | |
9bccf70c | 2108 | { |
91447636 | 2109 | return TRUE; |
9bccf70c | 2110 | } |
0c530ab8 A |
2111 | |
2112 | ||
2113 | /* | |
2114 | * disable no-execute capability on | |
2115 | * the specified pmap | |
2116 | */ | |
2117 | void pmap_disable_NX(pmap_t pmap) { | |
2118 | ||
2119 | pmap->pmapFlags |= pmapNXdisabled; | |
2120 | } | |
2d21ac55 | 2121 |