Annotation of XNU/osfmk/i386/pmap.h, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 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) 1991,1990,1989,1988 Carnegie Mellon University
                     28:  * All Rights Reserved.
                     29:  * 
                     30:  * Permission to use, copy, modify and distribute this software and its
                     31:  * documentation is hereby granted, provided that both the copyright
                     32:  * notice and this permission notice appear in all copies of the
                     33:  * software, derivative works or modified versions, and any portions
                     34:  * thereof, and that both notices appear in supporting documentation.
                     35:  * 
                     36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     39:  * 
                     40:  * Carnegie Mellon requests users of this software to return to
                     41:  * 
                     42:  *  Software Distribution Coordinator  or  [email protected]
                     43:  *  School of Computer Science
                     44:  *  Carnegie Mellon University
                     45:  *  Pittsburgh PA 15213-3890
                     46:  * 
                     47:  * any improvements or extensions that they make and grant Carnegie Mellon
                     48:  * the rights to redistribute these changes.
                     49:  */
                     50: /*
                     51:  */
                     52: 
                     53: /*
                     54:  *     File:   pmap.h
                     55:  *
                     56:  *     Authors:  Avadis Tevanian, Jr., Michael Wayne Young
                     57:  *     Date:   1985
                     58:  *
                     59:  *     Machine-dependent structures for the physical map module.
                     60:  */
                     61: 
                     62: #ifndef        _PMAP_MACHINE_
                     63: #define _PMAP_MACHINE_ 1
                     64: 
                     65: #ifndef        ASSEMBLER
                     66: 
                     67: #include <platforms.h>
                     68: #include <mp_v1_1.h>
                     69: 
                     70: #include <mach/kern_return.h>
                     71: #include <mach/machine/vm_types.h>
                     72: #include <mach/vm_prot.h>
                     73: #include <mach/vm_statistics.h>
                     74: #include <mach/machine/vm_param.h>
                     75: #include <kern/kern_types.h>
                     76: #include <kern/thread_act.h>
                     77: #include <kern/lock.h>
                     78: 
                     79: /*
                     80:  *     Define the generic in terms of the specific
                     81:  */
                     82: 
                     83: #define        INTEL_PGBYTES           I386_PGBYTES
                     84: #define INTEL_PGSHIFT          I386_PGSHIFT
                     85: #define        intel_btop(x)           i386_btop(x)
                     86: #define        intel_ptob(x)           i386_ptob(x)
                     87: #define        intel_round_page(x)     i386_round_page(x)
                     88: #define        intel_trunc_page(x)     i386_trunc_page(x)
                     89: #define trunc_intel_to_vm(x)   trunc_i386_to_vm(x)
                     90: #define round_intel_to_vm(x)   round_i386_to_vm(x)
                     91: #define vm_to_intel(x)         vm_to_i386(x)
                     92: 
                     93: /*
                     94:  *     i386/i486/i860 Page Table Entry
                     95:  */
                     96: 
                     97: typedef unsigned int   pt_entry_t;
                     98: #define PT_ENTRY_NULL  ((pt_entry_t *) 0)
                     99: 
                    100: #endif /* ASSEMBLER */
                    101: 
                    102: #define INTEL_OFFMASK  0xfff   /* offset within page */
                    103: #define PDESHIFT       22      /* page descriptor shift */
                    104: #define PDEMASK                0x3ff   /* mask for page descriptor index */
                    105: #define PTESHIFT       12      /* page table shift */
                    106: #define PTEMASK                0x3ff   /* mask for page table index */
                    107: 
                    108: /*
                    109:  *     Convert kernel virtual address to linear address
                    110:  */
                    111: 
                    112: #define kvtolinear(a)  ((a)+LINEAR_KERNEL_ADDRESS)
                    113: 
                    114: /*
                    115:  *     Convert address offset to page descriptor index
                    116:  */
                    117: #define pdenum(pmap, a)        (((((pmap) == kernel_pmap) ?    \
                    118:                           kvtolinear(a) : (a))         \
                    119:                          >> PDESHIFT) & PDEMASK)
                    120: 
                    121: /*
                    122:  *     Convert page descriptor index to user virtual address
                    123:  */
                    124: #define pdetova(a)     ((vm_offset_t)(a) << PDESHIFT)
                    125: 
                    126: /*
                    127:  *     Convert address offset to page table index
                    128:  */
                    129: #define ptenum(a)      (((a) >> PTESHIFT) & PTEMASK)
                    130: 
                    131: #define NPTES  (intel_ptob(1)/sizeof(pt_entry_t))
                    132: #define NPDES  (intel_ptob(1)/sizeof(pt_entry_t))
                    133: 
                    134: /*
                    135:  *     Hardware pte bit definitions (to be used directly on the ptes
                    136:  *     without using the bit fields).
                    137:  */
                    138: 
                    139: #define INTEL_PTE_VALID                0x00000001
                    140: #define INTEL_PTE_WRITE                0x00000002
                    141: #define INTEL_PTE_USER         0x00000004
                    142: #define INTEL_PTE_WTHRU                0x00000008
                    143: #define INTEL_PTE_NCACHE       0x00000010
                    144: #define INTEL_PTE_REF          0x00000020
                    145: #define INTEL_PTE_MOD          0x00000040
                    146: #define INTEL_PTE_WIRED                0x00000200
                    147: #define INTEL_PTE_PFN          0xfffff000
                    148: 
                    149: #define        pa_to_pte(a)            ((a) & INTEL_PTE_PFN)
                    150: #define        pte_to_pa(p)            ((p) & INTEL_PTE_PFN)
                    151: #define        pte_increment_pa(p)     ((p) += INTEL_OFFMASK+1)
                    152: 
                    153: /*
                    154:  *     Convert page table entry to kernel virtual address
                    155:  */
                    156: #define ptetokv(a)     (phystokv(pte_to_pa(a)))
                    157: 
                    158: #ifndef        ASSEMBLER
                    159: typedef        volatile long   cpu_set;        /* set of CPUs - must be <= 32 */
                    160:                                        /* changed by other processors */
                    161: 
                    162: struct pmap {
                    163:        pt_entry_t      *dirbase;       /* page directory pointer register */
                    164:        vm_offset_t     pdirbase;       /* phys. address of dirbase */
                    165:        int             ref_count;      /* reference count */
                    166:        decl_simple_lock_data(,lock)    /* lock on map */
                    167:        struct pmap_statistics  stats;  /* map statistics */
                    168:        cpu_set         cpus_using;     /* bitmap of cpus using pmap */
                    169: };
                    170: 
                    171: /* 
                    172:  * Optimization avoiding some TLB flushes when switching to
                    173:  * kernel-loaded threads.  This is effective only for i386:
                    174:  * Since user task, kernel task and kernel loaded tasks share the
                    175:  * same virtual space (with appropriate protections), any pmap
                    176:  * allows mapping kernel and kernel loaded tasks. 
                    177:  *
                    178:  * The idea is to avoid switching to another pmap unnecessarily when
                    179:  * switching to a kernel-loaded task, or when switching to the kernel
                    180:  * itself.
                    181:  *
                    182:  * We store the pmap we are really using (from which we fetched the
                    183:  * dirbase value) in real_pmap[cpu_number()].
                    184:  *
                    185:  * Invariant:
                    186:  * current_pmap() == real_pmap[cpu_number()] || current_pmap() == kernel_pmap.
                    187:  */
                    188: 
                    189: extern struct pmap     *real_pmap[NCPUS];
                    190: 
                    191: #include <i386/proc_reg.h>
                    192: /*
                    193:  * If switching to the kernel pmap, don't incur the TLB cost of switching
                    194:  * to its page tables, since all maps include the kernel map as a subset.
                    195:  * Simply record that this CPU is logically on the kernel pmap (see
                    196:  * pmap_destroy).
                    197:  * 
                    198:  * Similarly, if switching to a pmap (other than kernel_pmap that is already
                    199:  * in use, don't do anything to the hardware, to avoid a TLB flush.
                    200:  */
                    201: 
                    202: #if    NCPUS > 1
                    203: #define        PMAP_CPU_SET(pmap, my_cpu) i_bit_set(my_cpu, &((pmap)->cpus_using))
                    204: #define        PMAP_CPU_CLR(pmap, my_cpu) i_bit_clear(my_cpu, &((pmap)->cpus_using))
                    205: #else  /* NCPUS > 1 */
                    206: #define        PMAP_CPU_SET(pmap,my_cpu)    (pmap)->cpus_using = TRUE  
                    207: #define        PMAP_CPU_CLR(pmap,my_cpu)    (pmap)->cpus_using = FALSE
                    208: #endif /* NCPUS > 1 */
                    209: 
                    210: 
                    211: #define        set_dirbase(mypmap, my_cpu) {                                   \
                    212:        struct pmap     **ppmap = &real_pmap[my_cpu];                   \
                    213:        vm_offset_t     pdirbase = (mypmap)->pdirbase;                  \
                    214:                                                                        \
                    215:        if (*ppmap == (vm_offset_t)NULL) {                              \
                    216:                *ppmap = (mypmap);                                      \
                    217:                PMAP_CPU_SET((mypmap), my_cpu);                         \
                    218:                set_cr3(pdirbase);                                      \
                    219:        } else if ((mypmap) != kernel_pmap && (mypmap) != *ppmap ) {    \
                    220:                if (*ppmap != kernel_pmap)                              \
                    221:                        PMAP_CPU_CLR(*ppmap, my_cpu);                   \
                    222:                *ppmap = (mypmap);                                      \
                    223:                PMAP_CPU_SET((mypmap), my_cpu);                         \
                    224:                set_cr3(pdirbase);                                      \
                    225:        }                                                               \
                    226:        assert((mypmap) == *ppmap || (mypmap) == kernel_pmap);          \
                    227: }
                    228: 
                    229: #if    NCPUS > 1
                    230: /*
                    231:  *     List of cpus that are actively using mapped memory.  Any
                    232:  *     pmap update operation must wait for all cpus in this list.
                    233:  *     Update operations must still be queued to cpus not in this
                    234:  *     list.
                    235:  */
                    236: extern cpu_set         cpus_active;
                    237: 
                    238: /*
                    239:  *     List of cpus that are idle, but still operating, and will want
                    240:  *     to see any kernel pmap updates when they become active.
                    241:  */
                    242: extern cpu_set         cpus_idle;
                    243: 
                    244: 
                    245: /*
                    246:  *     External declarations for PMAP_ACTIVATE.
                    247:  */
                    248: 
                    249: extern void            process_pmap_updates(struct pmap *pmap);
                    250: extern void            pmap_update_interrupt(void);
                    251: 
                    252: #endif /* NCPUS > 1 */
                    253: 
                    254: /*
                    255:  *     Machine dependent routines that are used only for i386/i486/i860.
                    256:  */
                    257: extern vm_offset_t     (phystokv)(
                    258:                                vm_offset_t     pa);
                    259: 
                    260: extern vm_offset_t     (kvtophys)(
                    261:                                vm_offset_t     addr);
                    262: 
                    263: extern pt_entry_t      *pmap_pte(
                    264:                                struct pmap     *pmap,
                    265:                                vm_offset_t     addr);
                    266: 
                    267: extern vm_offset_t     pmap_map(
                    268:                                vm_offset_t     virt,
                    269:                                vm_offset_t     start,
                    270:                                vm_offset_t     end,
                    271:                                vm_prot_t       prot);
                    272: 
                    273: extern vm_offset_t     pmap_map_bd(
                    274:                                vm_offset_t     virt,
                    275:                                vm_offset_t     start,
                    276:                                vm_offset_t     end,
                    277:                                vm_prot_t       prot);
                    278: 
                    279: extern void            pmap_bootstrap(
                    280:                                vm_offset_t     load_start);
                    281: 
                    282: extern boolean_t       pmap_valid_page(
                    283:                                vm_offset_t     pa);
                    284: 
                    285: extern int             pmap_list_resident_pages(
                    286:                                struct pmap     *pmap,
                    287:                                vm_offset_t     *listp,
                    288:                                int             space);
                    289: 
                    290: extern void            flush_tlb(void);
                    291: 
                    292: /*
                    293:  *     Macros for speed.
                    294:  */
                    295: 
                    296: #if    NCPUS > 1
                    297: 
                    298: #include <kern/spl.h>
                    299: 
                    300: /*
                    301:  *     For multiple CPUS, PMAP_ACTIVATE and PMAP_DEACTIVATE must manage
                    302:  *     fields to control TLB invalidation on other CPUS.
                    303:  */
                    304: 
                    305: #define        PMAP_ACTIVATE_KERNEL(my_cpu)    {                               \
                    306:                                                                        \
                    307:        /*                                                              \
                    308:         *      Let pmap updates proceed while we wait for this pmap.   \
                    309:         */                                                             \
                    310:        i_bit_clear((my_cpu), &cpus_active);                            \
                    311:                                                                        \
                    312:        /*                                                              \
                    313:         *      Lock the pmap to put this cpu in its active set.        \
                    314:         *      Wait for updates here.                                  \
                    315:         */                                                             \
                    316:        simple_lock(&kernel_pmap->lock);                                \
                    317:                                                                        \
                    318:        /*                                                              \
                    319:         *      Mark that this cpu is using the pmap.                   \
                    320:         */                                                             \
                    321:        i_bit_set((my_cpu), &kernel_pmap->cpus_using);                  \
                    322:                                                                        \
                    323:        /*                                                              \
                    324:         *      Mark this cpu active - IPL will be lowered by           \
                    325:         *      load_context().                                         \
                    326:         */                                                             \
                    327:        i_bit_set((my_cpu), &cpus_active);                              \
                    328:                                                                        \
                    329:        simple_unlock(&kernel_pmap->lock);                              \
                    330: }
                    331: 
                    332: #define        PMAP_DEACTIVATE_KERNEL(my_cpu)  {                               \
                    333:        /*                                                              \
                    334:         *      Mark pmap no longer in use by this cpu even if          \
                    335:         *      pmap is locked against updates.                         \
                    336:         */                                                             \
                    337:        i_bit_clear((my_cpu), &kernel_pmap->cpus_using);                \
                    338: }
                    339: 
                    340: #define PMAP_ACTIVATE_MAP(map, my_cpu) {                               \
                    341:        register struct pmap    *tpmap;                                 \
                    342:                                                                        \
                    343:        tpmap = vm_map_pmap(map);                                       \
                    344:        if (tpmap == kernel_pmap) {                                     \
                    345:            /*                                                          \
                    346:             *  If this is the kernel pmap, switch to its page tables.  \
                    347:             */                                                         \
                    348:            set_dirbase(kernel_pmap, my_cpu);                           \
                    349:        }                                                               \
                    350:        else {                                                          \
                    351:            /*                                                          \
                    352:             *  Let pmap updates proceed while we wait for this pmap.   \
                    353:             */                                                         \
                    354:            i_bit_clear((my_cpu), &cpus_active);                        \
                    355:                                                                        \
                    356:            /*                                                          \
                    357:             *  Lock the pmap to put this cpu in its active set.        \
                    358:             *  Wait for updates here.                                  \
                    359:             */                                                         \
                    360:            simple_lock(&tpmap->lock);                                  \
                    361:                                                                        \
                    362:            /*                                                          \
                    363:             *  No need to invalidate the TLB - the entire user pmap    \
                    364:             *  will be invalidated by reloading dirbase.               \
                    365:             */                                                         \
                    366:            set_dirbase(tpmap, my_cpu);                                 \
                    367:                                                                        \
                    368:            /*                                                          \
                    369:             *  Mark this cpu active - IPL will be lowered by           \
                    370:             *  load_context().                                         \
                    371:             */                                                         \
                    372:            i_bit_set((my_cpu), &cpus_active);                          \
                    373:                                                                        \
                    374:            simple_unlock(&tpmap->lock);                                \
                    375:        }                                                               \
                    376: }
                    377: 
                    378: #define PMAP_DEACTIVATE_MAP(map, my_cpu)
                    379: 
                    380: #define PMAP_ACTIVATE_USER(th, my_cpu) {                               \
                    381:        spl_t           spl;                                            \
                    382:                                                                        \
                    383:        spl = splhigh();                                                        \
                    384:        PMAP_ACTIVATE_MAP(th->map, my_cpu)                              \
                    385:        splx(spl);                                                      \
                    386: }
                    387: 
                    388: #define PMAP_DEACTIVATE_USER(th, my_cpu)       {                       \
                    389:        spl_t           spl;                                            \
                    390:                                                                        \
                    391:        spl = splhigh();                                                        \
                    392:        PMAP_DEACTIVATE_MAP(th->map, my_cpu)                            \
                    393:        splx(spl);                                                      \
                    394: }
                    395: 
                    396: #define        PMAP_SWITCH_CONTEXT(old_th, new_th, my_cpu) {                   \
                    397:        spl_t           spl;                                            \
                    398:                                                                        \
                    399:        if (old_th->map != new_th->map) {                               \
                    400:                spl = splhigh();                                                \
                    401:                PMAP_DEACTIVATE_MAP(old_th->map, my_cpu);               \
                    402:                PMAP_ACTIVATE_MAP(new_th->map, my_cpu);                 \
                    403:                splx(spl);                                              \
                    404:        }                                                               \
                    405: }
                    406: 
                    407: #define        PMAP_SWITCH_USER(th, new_map, my_cpu) {                         \
                    408:        spl_t           spl;                                            \
                    409:                                                                        \
                    410:        spl = splhigh();                                                        \
                    411:        PMAP_DEACTIVATE_MAP(th->map, my_cpu);                           \
                    412:        th->map = new_map;                                              \
                    413:        PMAP_ACTIVATE_MAP(th->map, my_cpu);                             \
                    414:        splx(spl);                                                      \
                    415: }
                    416: 
                    417: #if    MP_V1_1
                    418: #define        set_led(cpu)
                    419: #define clear_led(cpu)
                    420: #endif /* MP_V1_1  */
                    421: 
                    422: #define MARK_CPU_IDLE(my_cpu)  {                                       \
                    423:        /*                                                              \
                    424:         *      Mark this cpu idle, and remove it from the active set,  \
                    425:         *      since it is not actively using any pmap.  Signal_cpus   \
                    426:         *      will notice that it is idle, and avoid signaling it,    \
                    427:         *      but will queue the update request for when the cpu      \
                    428:         *      becomes active.                                         \
                    429:         */                                                             \
                    430:        int     s = splhigh();                                          \
                    431:        i_bit_set((my_cpu), &cpus_idle);                                \
                    432:        i_bit_clear((my_cpu), &cpus_active);                            \
                    433:        splx(s);                                                        \
                    434:        set_led(my_cpu);                                                \
                    435: }
                    436: 
                    437: #define MARK_CPU_ACTIVE(my_cpu)        {                                       \
                    438:                                                                        \
                    439:        int     s = splhigh();                                          \
                    440:        /*                                                              \
                    441:         *      If a kernel_pmap update was requested while this cpu    \
                    442:         *      was idle, process it as if we got the interrupt.        \
                    443:         *      Before doing so, remove this cpu from the idle set.     \
                    444:         *      Since we do not grab any pmap locks while we flush      \
                    445:         *      our TLB, another cpu may start an update operation      \
                    446:         *      before we finish.  Removing this cpu from the idle      \
                    447:         *      set assures that we will receive another update         \
                    448:         *      interrupt if this happens.                              \
                    449:         */                                                             \
                    450:        i_bit_clear((my_cpu), &cpus_idle);                              \
                    451:                                                                        \
                    452:        /*                                                              \
                    453:         *      Mark that this cpu is now active.                       \
                    454:         */                                                             \
                    455:        i_bit_set((my_cpu), &cpus_active);                              \
                    456:        splx(s);                                                        \
                    457:        clear_led(my_cpu);                                              \
                    458: }
                    459: 
                    460: #else  /* NCPUS > 1 */
                    461: 
                    462: /*
                    463:  *     With only one CPU, we just have to indicate whether the pmap is
                    464:  *     in use.
                    465:  */
                    466: 
                    467: #define        PMAP_ACTIVATE_KERNEL(my_cpu)    {                               \
                    468:        kernel_pmap->cpus_using = TRUE;                                 \
                    469: }
                    470: 
                    471: #define        PMAP_DEACTIVATE_KERNEL(my_cpu)  {                               \
                    472:        kernel_pmap->cpus_using = FALSE;                                \
                    473: }
                    474: 
                    475: #define        PMAP_ACTIVATE_MAP(map, my_cpu)                                  \
                    476:        set_dirbase(vm_map_pmap(map), my_cpu)
                    477: 
                    478: #define PMAP_DEACTIVATE_MAP(map, my_cpu)
                    479: 
                    480: #define PMAP_ACTIVATE_USER(th, my_cpu)                                 \
                    481:        PMAP_ACTIVATE_MAP(th->map, my_cpu)
                    482: 
                    483: #define PMAP_DEACTIVATE_USER(th, my_cpu)                               \
                    484:        PMAP_DEACTIVATE_MAP(th->map, my_cpu)
                    485: 
                    486: #define        PMAP_SWITCH_CONTEXT(old_th, new_th, my_cpu) {                   \
                    487:        if (old_th->map != new_th->map) {                               \
                    488:                PMAP_DEACTIVATE_MAP(old_th->map, my_cpu);               \
                    489:                PMAP_ACTIVATE_MAP(new_th->map, my_cpu);                 \
                    490:        }                                                               \
                    491: }
                    492: 
                    493: #define        PMAP_SWITCH_USER(th, new_map, my_cpu) {                         \
                    494:        PMAP_DEACTIVATE_MAP(th->map, my_cpu);                           \
                    495:        th->map = new_map;                                              \
                    496:        PMAP_ACTIVATE_MAP(th->map, my_cpu);                             \
                    497: }
                    498: 
                    499: #endif /* NCPUS > 1 */
                    500: 
                    501: #define PMAP_CONTEXT(pmap, thread)
                    502: 
                    503: #define pmap_kernel_va(VA)     \
                    504:        (((VA) >= VM_MIN_KERNEL_ADDRESS) && ((VA) <= VM_MAX_KERNEL_ADDRESS))
                    505: 
                    506: #define pmap_resident_count(pmap)      ((pmap)->stats.resident_count)
                    507: #define pmap_phys_address(frame)       ((vm_offset_t) (intel_ptob(frame)))
                    508: #define pmap_phys_to_frame(phys)       ((int) (intel_btop(phys)))
                    509: #define        pmap_copy(dst_pmap,src_pmap,dst_addr,len,src_addr)
                    510: #define        pmap_attribute(pmap,addr,size,attr,value) \
                    511:                                        (KERN_INVALID_ADDRESS)
                    512: #endif /* ASSEMBLER */
                    513: 
                    514: #endif /* _PMAP_MACHINE_ */

unix.superglobalmegacorp.com

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