[BACK]Return to gdt.c CVS log [TXT][DIR] Up to [local] / sys / arch / amd64 / amd64

Annotation of sys/arch/amd64/amd64/gdt.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: gdt.c,v 1.10 2007/05/29 00:17:33 thib Exp $   */
                      2: /*     $NetBSD: gdt.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $     */
                      3:
                      4: /*-
                      5:  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
                      9:  * by John T. Kohl and Charles M. Hannum.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *        This product includes software developed by the NetBSD
                     22:  *        Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: /*
                     41:  * Modified to deal with variable-length entries for amd64 by
                     42:  * fvdl@wasabisystems.com, may 2001
                     43:  * XXX this file should be shared with the i386 code, the difference
                     44:  * can be hidden in macros.
                     45:  */
                     46:
                     47: #include <sys/param.h>
                     48: #include <sys/systm.h>
                     49: #include <sys/proc.h>
                     50: #include <sys/rwlock.h>
                     51: #include <sys/user.h>
                     52:
                     53: #include <uvm/uvm.h>
                     54:
                     55: #include <machine/gdt.h>
                     56:
                     57: int gdt_size;          /* size of GDT in bytes */
                     58: int gdt_dyncount;      /* number of dyn. allocated GDT entries in use */
                     59: int gdt_dynavail;
                     60: int gdt_next;          /* next available slot for sweeping */
                     61: int gdt_free;          /* next free slot; terminated with GNULL_SEL */
                     62:
                     63: struct rwlock gdt_lock_store = RWLOCK_INITIALIZER("gdtlk");
                     64:
                     65: static __inline void gdt_lock(void);
                     66: static __inline void gdt_unlock(void);
                     67: void gdt_init(void);
                     68: void gdt_grow(void);
                     69: int gdt_get_slot(void);
                     70: void gdt_put_slot(int);
                     71:
                     72: /*
                     73:  * Lock and unlock the GDT, to avoid races in case gdt_{ge,pu}t_slot() sleep
                     74:  * waiting for memory.
                     75:  *
                     76:  * Note that the locking done here is not sufficient for multiprocessor
                     77:  * systems.  A freshly allocated slot will still be of type SDT_SYSNULL for
                     78:  * some time after the GDT is unlocked, so gdt_compact() could attempt to
                     79:  * reclaim it.
                     80:  */
                     81: static __inline void
                     82: gdt_lock(void)
                     83: {
                     84:        if (curproc != NULL)            /* XXX - ugh. needed for startup */
                     85:                rw_enter_write(&gdt_lock_store);
                     86: }
                     87:
                     88: static __inline void
                     89: gdt_unlock(void)
                     90: {
                     91:        if (curproc != NULL)
                     92:                rw_exit_write(&gdt_lock_store);
                     93: }
                     94:
                     95: void
                     96: set_mem_gdt(struct mem_segment_descriptor *sd, void *base, size_t limit,
                     97:     int type, int dpl, int gran, int def32, int is64)
                     98: {
                     99:        CPU_INFO_ITERATOR cii;
                    100:        struct cpu_info *ci;
                    101:        int off;
                    102:
                    103:         set_mem_segment(sd, base, limit, type, dpl, gran, def32, is64);
                    104:        off = (char *)sd - gdtstore;
                    105:         CPU_INFO_FOREACH(cii, ci) {
                    106:                 if (ci->ci_gdt != NULL)
                    107:                        *(struct mem_segment_descriptor *)(ci->ci_gdt + off) =
                    108:                            *sd;
                    109:         }
                    110: }
                    111:
                    112: void
                    113: set_sys_gdt(struct sys_segment_descriptor *sd, void *base, size_t limit,
                    114:     int type, int dpl, int gran)
                    115: {
                    116:        CPU_INFO_ITERATOR cii;
                    117:        struct cpu_info *ci;
                    118:        int off;
                    119:
                    120:         set_sys_segment(sd, base, limit, type, dpl, gran);
                    121:        off = (char *)sd - gdtstore;
                    122:         CPU_INFO_FOREACH(cii, ci) {
                    123:                 if (ci->ci_gdt != NULL)
                    124:                        *(struct sys_segment_descriptor *)(ci->ci_gdt + off) =
                    125:                            *sd;
                    126:         }
                    127: }
                    128:
                    129:
                    130: /*
                    131:  * Initialize the GDT.
                    132:  */
                    133: void
                    134: gdt_init(void)
                    135: {
                    136:        char *old_gdt;
                    137:        struct vm_page *pg;
                    138:        vaddr_t va;
                    139:        struct cpu_info *ci = &cpu_info_primary;
                    140:
                    141:        gdt_size = MINGDTSIZ;
                    142:        gdt_dyncount = 0;
                    143:        gdt_next = 0;
                    144:        gdt_free = GNULL_SEL;
                    145:        gdt_dynavail =
                    146:            (gdt_size - DYNSEL_START) / sizeof (struct sys_segment_descriptor);
                    147:
                    148:        old_gdt = gdtstore;
                    149:        gdtstore = (char *)uvm_km_valloc(kernel_map, MAXGDTSIZ);
                    150:        for (va = (vaddr_t)gdtstore; va < (vaddr_t)gdtstore + gdt_size;
                    151:            va += PAGE_SIZE) {
                    152:                pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO);
                    153:                if (pg == NULL) {
                    154:                        panic("gdt_init: no pages");
                    155:                }
                    156:                pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg),
                    157:                    VM_PROT_READ | VM_PROT_WRITE);
                    158:        }
                    159:        memcpy(gdtstore, old_gdt, DYNSEL_START);
                    160:        ci->ci_gdt = gdtstore;
                    161:        set_sys_segment(GDT_ADDR_SYS(gdtstore, GLDT_SEL), ldtstore,
                    162:            LDT_SIZE - 1, SDT_SYSLDT, SEL_KPL, 0);
                    163:
                    164:        gdt_init_cpu(ci);
                    165: }
                    166:
                    167: #ifdef MULTIPROCESSOR
                    168: /*
                    169:  * Allocate shadow GDT for a slave cpu.
                    170:  */
                    171: void
                    172: gdt_alloc_cpu(struct cpu_info *ci)
                    173: {
                    174:         ci->ci_gdt = (char *)uvm_km_valloc(kernel_map, MAXGDTSIZ);
                    175:         uvm_map_pageable(kernel_map, (vaddr_t)ci->ci_gdt,
                    176:             (vaddr_t)ci->ci_gdt + MINGDTSIZ, FALSE, FALSE);
                    177:         memset(ci->ci_gdt, 0, MINGDTSIZ);
                    178:         memcpy(ci->ci_gdt, gdtstore,
                    179:           DYNSEL_START + gdt_dyncount * sizeof(struct sys_segment_descriptor));
                    180: }
                    181: #endif /* MULTIPROCESSOR */
                    182:
                    183:
                    184: /*
                    185:  * Load appropriate gdt descriptor; we better be running on *ci
                    186:  * (for the most part, this is how a cpu knows who it is).
                    187:  */
                    188: void
                    189: gdt_init_cpu(struct cpu_info *ci)
                    190: {
                    191:        struct region_descriptor region;
                    192:
                    193:        setregion(&region, ci->ci_gdt, (u_int16_t)(MAXGDTSIZ - 1));
                    194:        lgdt(&region);
                    195: }
                    196:
                    197: #ifdef MULTIPROCESSOR
                    198:
                    199: void
                    200: gdt_reload_cpu(struct cpu_info *ci)
                    201: {
                    202:        struct region_descriptor region;
                    203:
                    204:        setregion(&region, ci->ci_gdt, MAXGDTSIZ - 1);
                    205:        lgdt(&region);
                    206: }
                    207: #endif
                    208:
                    209:
                    210: /*
                    211:  * Grow or shrink the GDT.
                    212:  */
                    213: void
                    214: gdt_grow(void)
                    215: {
                    216:        size_t old_len;
                    217:        struct vm_page *pg;
                    218:        vaddr_t va;
                    219:
                    220:        old_len = gdt_size;
                    221:        gdt_size = 2 * gdt_size;
                    222:        gdt_dynavail =
                    223:            (gdt_size - DYNSEL_START) / sizeof (struct sys_segment_descriptor);
                    224:
                    225:        for (va = (vaddr_t)gdtstore + old_len;
                    226:            va < (vaddr_t)gdtstore + gdt_size;
                    227:            va += PAGE_SIZE) {
                    228:                while ((pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO)) ==
                    229:                       NULL) {
                    230:                        uvm_wait("gdt_grow");
                    231:                }
                    232:                pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg),
                    233:                    VM_PROT_READ | VM_PROT_WRITE);
                    234:        }
                    235: }
                    236:
                    237: /*
                    238:  * Allocate a GDT slot as follows:
                    239:  * 1) If there are entries on the free list, use those.
                    240:  * 2) If there are fewer than gdt_dynavail entries in use, there are free slots
                    241:  *    near the end that we can sweep through.
                    242:  * 3) As a last resort, we increase the size of the GDT, and sweep through
                    243:  *    the new slots.
                    244:  */
                    245: int
                    246: gdt_get_slot(void)
                    247: {
                    248:        int slot;
                    249:        struct sys_segment_descriptor *gdt;
                    250:
                    251:        gdt = (struct sys_segment_descriptor *)&gdtstore[DYNSEL_START];
                    252:
                    253:        gdt_lock();
                    254:
                    255:        if (gdt_free != GNULL_SEL) {
                    256:                slot = gdt_free;
                    257:                gdt_free = gdt[slot].sd_xx3;    /* XXXfvdl res. field abuse */
                    258:        } else {
                    259: #ifdef DIAGNOSTIC
                    260:                if (gdt_next != gdt_dyncount)
                    261:                        panic("gdt_get_slot botch 1");
                    262: #endif
                    263:                if (gdt_next >= gdt_dynavail) {
                    264: #ifdef DIAGNOSTIC
                    265:                        if (gdt_size >= MAXGDTSIZ)
                    266:                                panic("gdt_get_slot botch 2");
                    267: #endif
                    268:                        gdt_grow();
                    269:                }
                    270:                slot = gdt_next++;
                    271:        }
                    272:
                    273:        gdt_dyncount++;
                    274:        gdt_unlock();
                    275:        return (slot);
                    276: }
                    277:
                    278: /*
                    279:  * Deallocate a GDT slot, putting it on the free list.
                    280:  */
                    281: void
                    282: gdt_put_slot(int slot)
                    283: {
                    284:        struct sys_segment_descriptor *gdt;
                    285:
                    286:        gdt = (struct sys_segment_descriptor *)&gdtstore[DYNSEL_START];
                    287:
                    288:        gdt_lock();
                    289:        gdt_dyncount--;
                    290:
                    291:        gdt[slot].sd_type = SDT_SYSNULL;
                    292:        gdt[slot].sd_xx3 = gdt_free;
                    293:        gdt_free = slot;
                    294:
                    295:        gdt_unlock();
                    296: }
                    297:
                    298: int
                    299: tss_alloc(struct pcb *pcb)
                    300: {
                    301:        int slot;
                    302:        struct sys_segment_descriptor *gdt;
                    303:
                    304:        gdt = (struct sys_segment_descriptor *)&gdtstore[DYNSEL_START];
                    305:
                    306:        slot = gdt_get_slot();
                    307: #if 0
                    308:        printf("tss_alloc: slot %d addr %p\n", slot, &gdt[slot]);
                    309: #endif
                    310:        set_sys_gdt(&gdt[slot], &pcb->pcb_tss, sizeof (struct x86_64_tss)-1,
                    311:            SDT_SYS386TSS, SEL_KPL, 0);
                    312: #if 0
                    313:        printf("lolimit %lx lobase %lx type %lx dpl %lx p %lx hilimit %lx\n"
                    314:               "xx1 %lx gran %lx hibase %lx xx2 %lx zero %lx xx3 %lx pad %lx\n",
                    315:                (unsigned long)gdt[slot].sd_lolimit,
                    316:                (unsigned long)gdt[slot].sd_lobase,
                    317:                (unsigned long)gdt[slot].sd_type,
                    318:                (unsigned long)gdt[slot].sd_dpl,
                    319:                (unsigned long)gdt[slot].sd_p,
                    320:                (unsigned long)gdt[slot].sd_hilimit,
                    321:                (unsigned long)gdt[slot].sd_xx1,
                    322:                (unsigned long)gdt[slot].sd_gran,
                    323:                (unsigned long)gdt[slot].sd_hibase,
                    324:                (unsigned long)gdt[slot].sd_xx2,
                    325:                (unsigned long)gdt[slot].sd_zero,
                    326:                (unsigned long)gdt[slot].sd_xx3);
                    327: #endif
                    328:        return GDYNSEL(slot, SEL_KPL);
                    329: }
                    330:
                    331: void
                    332: tss_free(int sel)
                    333: {
                    334:
                    335:        gdt_put_slot(IDXDYNSEL(sel));
                    336: }
                    337:
                    338: void
                    339: ldt_alloc(struct pmap *pmap, char *ldt, size_t len)
                    340: {
                    341:        int slot;
                    342:        struct sys_segment_descriptor *gdt;
                    343:
                    344:        gdt = (struct sys_segment_descriptor *)&gdtstore[DYNSEL_START];
                    345:
                    346:        slot = gdt_get_slot();
                    347:        set_sys_gdt(&gdt[slot], ldt, len - 1, SDT_SYSLDT, SEL_KPL, 0);
                    348:        pmap->pm_ldt_sel = GSEL(slot, SEL_KPL);
                    349: }
                    350:
                    351: void
                    352: ldt_free(struct pmap *pmap)
                    353: {
                    354:        int slot;
                    355:
                    356:        slot = IDXDYNSEL(pmap->pm_ldt_sel);
                    357:
                    358:        gdt_put_slot(slot);
                    359: }

CVSweb