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(®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