Annotation of kernel/machdep/i386/pmap_private.h, revision 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.