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(®ion, ci->ci_gdt, (u_int16_t)(MAXGDTSIZ - 1));
! 194: lgdt(®ion);
! 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(®ion, ci->ci_gdt, MAXGDTSIZ - 1);
! 205: lgdt(®ion);
! 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