Annotation of kernel/machdep/i386/pmap_private.h, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /*
                     26:  * Copyright (c) 1992 NeXT Computer, Inc.
                     27:  *
                     28:  * Intel386 Family:    Private definitions for pmap.
                     29:  *
                     30:  * HISTORY
                     31:  *
                     32:  * 10 April 1992 ? at NeXT
                     33:  *     Created.
                     34:  */
                     35:  
                     36: /*
                     37:  * For each managed physical page, there is a list of all currently
                     38:  * valid virtual mappings of that page.
                     39:  */
                     40: typedef struct pv_entry {
                     41:     struct pv_entry *  next;           /* next pv_entry */
                     42:     pmap_t             pmap;           /* pmap where mapping lies */
                     43:     vm_offset_t                va;             /* virtual address for mapping */
                     44: } pv_head_t, *pv_entry_t;
                     45: 
                     46: #define        PV_ENTRY_NULL   ((pv_entry_t) 0)
                     47: 
                     48: zone_t         pv_entry_zone;          /* zone of pv_entry structures */
                     49: 
                     50: /*
                     51:  * First and last physical addresses that we maintain any information
                     52:  * for.  Initialized to zero so that pmap operations done before
                     53:  * pmap_init won't touch any non-existent structures.
                     54:  */
                     55: vm_offset_t    vm_first_phys = (vm_offset_t) 0;
                     56: vm_offset_t    vm_last_phys  = (vm_offset_t) 0;
                     57: #define managed_page(pa)       \
                     58:     ((pa) >= vm_first_phys && (pa) < vm_last_phys)
                     59: boolean_t      pmap_initialized = FALSE;/* Has pmap_init completed? */
                     60: 
                     61: /*
                     62:  * Page descriptor -
                     63:  * Maintained for each managed page.
                     64:  */
                     65: typedef struct pg_desc {
                     66:     pv_head_t          pv_list;                /* head of pv list for page  */
                     67:     struct pg_exten *  pg_exten;               /* page extension  for page  */
                     68:     unsigned int       page_attrib     :8,     /* page attributes:          */
                     69: #define        PG_DIRTY    0x01                        /* page has been modified    */
                     70: #define        PG_REFER    0x02                        /* page has been referenced  */
                     71:                                        :0;
                     72: } pg_desc_t;
                     73: 
                     74: #define PG_DESC_NULL   ((pg_desc_t *) 0)
                     75: 
                     76: pg_desc_t      *pg_desc_tbl;
                     77: unsigned int   pg_first_phys;
                     78: 
                     79: #define pg_desc(pa) \
                     80:      (&pg_desc_tbl[phys_to_pfn((unsigned int)(pa) -    \
                     81:                                   pg_first_phys) >> (ptes_per_vm_page - 1)])
                     82: 
                     83: #define pg_desc_pvh(pd)                (&(pd)->pv_list)
                     84: 
                     85: /*
                     86:  * Page extension -
                     87:  * Contains information for pages used
                     88:  * as page tables or page directories.
                     89:  * NB: the 'links' field *must* be first.
                     90:  */
                     91: typedef struct pg_exten {
                     92:     queue_chain_t      links;                  /* active/free queue links   */
                     93:     struct pg_desc *   pg_desc;                /* page descriptor for page  */
                     94:     unsigned int       phys;                   /* physical address of page  */
                     95:     struct pmap *      pmap;                   /* PT: which address map     */
                     96:     vm_offset_t                offset;                 /* PT: what offset in map    */
                     97:     unsigned int       alloc_count     :16,    /* PT: mappings, PD: pg dirs */
                     98:                        wired_count     :16;    /* PT: wired mappings        */
                     99:     unsigned int       alloc_bmap      :8,     /* PD: alloc map             */
                    100:                        unrefd_age      :8,     /* PT: # aging ticks         */
                    101:                                        :0;
                    102: } pg_exten_t;
                    103: 
                    104: #define PG_EXTEN_NULL  ((pg_exten_t *) 0)
                    105: 
                    106: zone_t         pg_exten_zone;
                    107: 
                    108: /*
                    109:  * A queue of free page tables is
                    110:  * maintained which is emptied by
                    111:  * pmap_update().  This strategy is
                    112:  * used for two reasons.  First, it is
                    113:  * inconvenient to actually free the pages
                    114:  * at the point in the code where it would
                    115:  * be necessary.  Secondly, keeping easily
                    116:  * available spare page tables around makes
                    117:  * pmap expansions quicker.
                    118:  */
                    119: queue_head_t   pt_active_queue, pt_free_queue;
                    120: int            pt_active_count, pt_free_count;
                    121: int            pt_alloc_count;
                    122: 
                    123: static __inline__
                    124: void
                    125: pt_active_add(
                    126:     pg_exten_t *pe
                    127: )
                    128: {
                    129:     enqueue_tail(&pt_active_queue, (queue_entry_t)pe);
                    130:     pt_active_count++;
                    131: }
                    132: 
                    133: static __inline__
                    134: void
                    135: pt_active_remove(
                    136:     pg_exten_t *pe
                    137: )
                    138: {
                    139:     remqueue(&pt_active_queue, (queue_entry_t)pe);
                    140:     pt_active_count--;
                    141: }
                    142: 
                    143: static __inline__
                    144: pg_exten_t *
                    145: pt_free_obtain(
                    146:     void
                    147: )
                    148: {
                    149:     pg_exten_t *pe;
                    150: 
                    151:     if (((queue_entry_t)pe = dequeue_head(&pt_free_queue)))
                    152:        pt_free_count--;
                    153:     
                    154:     return (pe);
                    155: }
                    156: 
                    157: static __inline__
                    158: void
                    159: pt_free_add(
                    160:     pg_exten_t *pe
                    161: )
                    162: {
                    163:     enqueue_tail(&pt_free_queue, (queue_entry_t)pe);
                    164:     pt_free_count++;
                    165: }
                    166: 
                    167: /*
                    168:  * A queue of pages that contain free
                    169:  * page directories is maintained.  This
                    170:  * is also emptied by pmap_update() (if
                    171:  * possible).  This added complexity is
                    172:  * needed to avoid wasting memory when
                    173:  * running with a large MI page size.
                    174:  */
                    175: queue_head_t   pd_free_queue;
                    176: int            pd_free_count;
                    177: int            pd_alloc_count;
                    178: 
                    179: static __inline__
                    180: pg_exten_t *
                    181: pd_free_obtain(
                    182:     void
                    183: )
                    184: {
                    185:     if (queue_empty(&pd_free_queue))
                    186:        return (0);
                    187:     
                    188:     return ((pg_exten_t *) queue_first(&pd_free_queue));
                    189: }
                    190: 
                    191: static __inline__
                    192: void
                    193: pd_free_add(
                    194:     pg_exten_t *pe
                    195: )
                    196: {
                    197:     enqueue_head(&pd_free_queue, (queue_entry_t)pe);
                    198:     pd_free_count++;
                    199: }
                    200: 
                    201: static __inline__
                    202: void
                    203: pd_free_remove(
                    204:     pg_exten_t *pe
                    205: )
                    206: {
                    207:     remqueue(&pd_free_queue, (queue_entry_t)pe);
                    208:     pd_free_count--;
                    209: }
                    210: 
                    211: /*
                    212:  * A section is defined to be the amount
                    213:  * of address space mapped by a single
                    214:  * page table.
                    215:  */
                    216: 
                    217: /*
                    218:  * Machine dependent sections.
                    219:  */
                    220: #define I386_SECTBYTES         ((I386_PGBYTES / sizeof (pt_entry_t)) * \
                    221:                                    I386_PGBYTES)
                    222: #define i386_round_section(x)  ((((unsigned int)(x)) + I386_SECTBYTES - 1) & \
                    223:                                    ~(I386_SECTBYTES - 1)) 
                    224: #define i386_trunc_section(x)  (((unsigned int)(x)) & ~(I386_SECTBYTES - 1))
                    225: 
                    226: /*
                    227:  * Machine independent sections.
                    228:  */
                    229: #define SECTION_SIZE           ((PAGE_SIZE / sizeof (pt_entry_t)) * \
                    230:                                    I386_PGBYTES)
                    231: vm_offset_t                    section_size;
                    232: #define round_section(x)       ((((unsigned int)(x)) + section_size - 1) & \
                    233:                                    ~(section_size - 1)) 
                    234: #define trunc_section(x)       (((unsigned int)(x)) & ~(section_size - 1))
                    235: 
                    236: /*
                    237:  *     Locking and TLB invalidation
                    238:  */
                    239: 
                    240: /*
                    241:  *     Locking Protocols:
                    242:  *
                    243:  *     There are two structures in the pmap module that need locking:
                    244:  *     the pmaps themselves, and the per-page pv_lists (which are locked
                    245:  *     by locking the pv_lock_table entry that corresponds to the pv_head
                    246:  *     for the list in question.)  Most routines want to lock a pmap and
                    247:  *     then do operations in it that require pv_list locking -- however
                    248:  *     pmap_remove_all and pmap_copy_on_write operate on a physical page
                    249:  *     basis and want to do the locking in the reverse order, i.e. lock
                    250:  *     a pv_list and then go through all the pmaps referenced by that list.
                    251:  *     To protect against deadlock between these two cases, the pmap_lock
                    252:  *     is used.  There are three different locking protocols as a result:
                    253:  *
                    254:  *  1.  pmap operations only (pmap_extract, pmap_access, ...)  Lock only
                    255:  *             the pmap.
                    256:  *
                    257:  *  2.  pmap-based operations (pmap_enter, pmap_remove, ...)  Get a read
                    258:  *             lock on the pmap_lock (shared read), then lock the pmap
                    259:  *             and finally the pv_lists as needed [i.e. pmap lock before
                    260:  *             pv_list lock.]
                    261:  *
                    262:  *  3.  pv_list-based operations (pmap_remove_all, pmap_copy_on_write, ...)
                    263:  *             Get a write lock on the pmap_lock (exclusive write); this
                    264:  *             also guaranteees exclusive access to the pv_lists.  Lock the
                    265:  *             pmaps as needed.
                    266:  *
                    267:  *     At no time may any routine hold more than one pmap lock or more than
                    268:  *     one pv_list lock.  Because interrupt level routines can allocate
                    269:  *     mbufs and cause pmap_enter's, the pmap_lock and the lock on the
                    270:  *     kernel_pmap can only be held at splvm.
                    271:  *     
                    272:  *     The dev_addr list is protected by using a write lock on the 
                    273:  *     pmap_lock.  Lookups are expected to be cheap.
                    274:  */
                    275: 
                    276: #define SPLVM(spl)     { spl = splvm(); }
                    277: #define SPLX(spl)      { splx(spl); }
                    278: 
                    279: #define PMAP_READ_LOCK(pmap, spl)      SPLVM(spl)
                    280: #define PMAP_WRITE_LOCK(spl)           SPLVM(spl)
                    281: #define PMAP_READ_UNLOCK(pmap, spl)    SPLX(spl)
                    282: #define PMAP_WRITE_UNLOCK(spl)         SPLX(spl)
                    283: #define PMAP_WRITE_TO_READ_LOCK(pmap)
                    284: 
                    285: #define LOCK_PVH(index)
                    286: #define UNLOCK_PVH(index)
                    287: 
                    288: #define PMAP_UPDATE_TLBS(pmap, s, e)                   \
                    289:     pmap_update_tlbs((pmap), (s), (e))
                    290: 
                    291: struct {
                    292:     int                total;
                    293:     int                single;
                    294: } tlb_stat;
                    295: 
                    296: /*
                    297:  * Kernel pmap is statically
                    298:  * allocated.
                    299:  */
                    300: struct pmap    kernel_pmap_store;
                    301: pmap_t         kernel_pmap;
                    302: 
                    303: /*
                    304:  * Zone to allocate new
                    305:  * pmaps from.
                    306:  */
                    307: zone_t         pmap_zone;
                    308: 
                    309: int            ptes_per_vm_page;
                    310: 
                    311: static void            pmap_expand(
                    312:                                        pmap_t          pmap,
                    313:                                        vm_offset_t     va);
                    314: static void            pmap_allocate_mapping(
                    315:                                        pmap_t          pmap,
                    316:                                        vm_offset_t     va,
                    317:                                        boolean_t       wired);
                    318: static void            pmap_deallocate_mappings(
                    319:                                        pmap_t          pmap,
                    320:                                        vm_offset_t     va,
                    321:                                        int             count,
                    322:                                        int             unwire_count,
                    323:                                        boolean_t       free_table);
                    324: static void            pmap_wire_mapping(
                    325:                                        pmap_t          pmap,
                    326:                                        vm_offset_t     va);
                    327: static void            pmap_unwire_mapping(
                    328:                                        pmap_t          pmap,
                    329:                                        vm_offset_t     va);
                    330: static void            pmap_remove_range(
                    331:                                        pmap_t          pmap,
                    332:                                        vm_offset_t     start,
                    333:                                        vm_offset_t     end,
                    334:                                        boolean_t       free_table);
                    335: static void            pmap_clear_page_attrib(
                    336:                                        vm_offset_t     pa,
                    337:                                        int             attrib);
                    338: static boolean_t       pmap_check_page_attrib(
                    339:                                        vm_offset_t     pa,
                    340:                                        int             attrib);

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.