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