The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/osfmk/ppc/pmap.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: e1bc91c65e61319a3df76eb200f7474b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.