[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     ! 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