|
|
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 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: /*
55: * User LDT management.
56: * Each thread in a task may have its own LDT.
57: */
58:
59: #include <kern/kalloc.h>
60: #include <kern/thread.h>
61: #include <kern/misc_protos.h>
62:
63: #include <vm/vm_kern.h>
64:
65: #include <i386/seg.h>
66: #include <i386/thread.h>
67: #include <i386/user_ldt.h>
68:
69: char acc_type[8][3] = {
70: /* code stack data */
71: { 0, 0, 1 }, /* data */
72: { 0, 1, 1 }, /* data, writable */
73: { 0, 0, 1 }, /* data, expand-down */
74: { 0, 1, 1 }, /* data, writable, expand-down */
75: { 1, 0, 0 }, /* code */
76: { 1, 0, 1 }, /* code, readable */
77: { 1, 0, 0 }, /* code, conforming */
78: { 1, 0, 1 }, /* code, readable, conforming */
79: };
80:
81: extern struct fake_descriptor ldt[]; /* for system call gate */
82:
83: #if 0
84: /* Forward */
85:
86: extern boolean_t selector_check(
87: thread_t thread,
88: int sel,
89: int type);
90:
91: boolean_t
92: selector_check(
93: thread_t thread,
94: int sel,
95: int type)
96: {
97: struct user_ldt *ldt;
98: int access;
99:
100: ldt = thread->top_act->mact.pcb->ims.ldt;
101: if (ldt == 0) {
102: switch (type) {
103: case S_CODE:
104: return sel == USER_CS;
105: case S_STACK:
106: return sel == USER_DS;
107: case S_DATA:
108: return sel == 0 ||
109: sel == USER_CS ||
110: sel == USER_DS;
111: }
112: }
113:
114: if (type != S_DATA && sel == 0)
115: return FALSE;
116: if ((sel & (SEL_LDTS|SEL_PL)) != (SEL_LDTS|SEL_PL_U)
117: || sel > ldt->desc.limit_low)
118: return FALSE;
119:
120: access = ldt->ldt[sel_idx(sel)].access;
121:
122: if ((access & (ACC_P|ACC_PL|ACC_TYPE_USER))
123: != (ACC_P|ACC_PL_U|ACC_TYPE_USER))
124: return FALSE;
125: /* present, pl == pl.user, not system */
126:
127: return acc_type[(access & 0xe)>>1][type];
128: }
129:
130: /*
131: * Add the descriptors to the LDT, starting with
132: * the descriptor for 'first_selector'.
133: */
134:
135: kern_return_t
136: i386_set_ldt(
137: thread_act_t thr_act,
138: int first_selector,
139: descriptor_list_t desc_list,
140: mach_msg_type_number_t count)
141: {
142: user_ldt_t new_ldt, old_ldt, temp;
143: struct real_descriptor *dp;
144: int i;
145: int min_selector = 0;
146: pcb_t pcb;
147: vm_size_t ldt_size_needed;
148: int first_desc = sel_idx(first_selector);
149: vm_map_copy_t old_copy_object;
150: thread_t thread;
151:
152: if (first_desc < min_selector || first_desc > 8191)
153: return KERN_INVALID_ARGUMENT;
154: if (first_desc + count >= 8192)
155: return KERN_INVALID_ARGUMENT;
156: if (thr_act == THR_ACT_NULL)
157: return KERN_INVALID_ARGUMENT;
158: if ((thread = act_lock_thread(thr_act)) == THREAD_NULL) {
159: act_unlock_thread(thr_act);
160: return KERN_INVALID_ARGUMENT;
161: }
162: if (thread == current_thread())
163: min_selector = LDTSZ;
164: act_unlock_thread(thr_act);
165:
166: /*
167: * We must copy out desc_list to the kernel map, and wire
168: * it down (we touch it while the PCB is locked).
169: *
170: * We make a copy of the copyin object, and clear
171: * out the old one, so that the MIG stub will have a
172: * a empty (but valid) copyin object to discard.
173: */
174: {
175: kern_return_t kr;
176: vm_offset_t dst_addr;
177:
178: old_copy_object = (vm_map_copy_t) desc_list;
179:
180: kr = vm_map_copyout(ipc_kernel_map, &dst_addr,
181: vm_map_copy_copy(old_copy_object));
182: if (kr != KERN_SUCCESS)
183: return kr;
184:
185: (void) vm_map_wire(ipc_kernel_map,
186: trunc_page(dst_addr),
187: round_page(dst_addr +
188: count * sizeof(struct real_descriptor)),
189: VM_PROT_READ|VM_PROT_WRITE, FALSE);
190: desc_list = (descriptor_list_t) dst_addr;
191: }
192:
193: for (i = 0, dp = (struct real_descriptor *) desc_list;
194: i < count;
195: i++, dp++)
196: {
197: switch (dp->access & ~ACC_A) {
198: case 0:
199: case ACC_P:
200: /* valid empty descriptor */
201: break;
202: case ACC_P | ACC_CALL_GATE:
203: /* Mach kernel call */
204: *dp = *(struct real_descriptor *)
205: &ldt[sel_idx(USER_SCALL)];
206: break;
207: case ACC_P | ACC_PL_U | ACC_DATA:
208: case ACC_P | ACC_PL_U | ACC_DATA_W:
209: case ACC_P | ACC_PL_U | ACC_DATA_E:
210: case ACC_P | ACC_PL_U | ACC_DATA_EW:
211: case ACC_P | ACC_PL_U | ACC_CODE:
212: case ACC_P | ACC_PL_U | ACC_CODE_R:
213: case ACC_P | ACC_PL_U | ACC_CODE_C:
214: case ACC_P | ACC_PL_U | ACC_CODE_CR:
215: case ACC_P | ACC_PL_U | ACC_CALL_GATE_16:
216: case ACC_P | ACC_PL_U | ACC_CALL_GATE:
217: break;
218: default:
219: (void) vm_map_remove(ipc_kernel_map,
220: (vm_offset_t) desc_list,
221: count * sizeof(struct real_descriptor),
222: VM_MAP_REMOVE_KUNWIRE);
223: return KERN_INVALID_ARGUMENT;
224: }
225: }
226: ldt_size_needed = sizeof(struct real_descriptor)
227: * (first_desc + count);
228:
229: pcb = thr_act->mact.pcb;
230: new_ldt = 0;
231: Retry:
232: simple_lock(&pcb->lock);
233: old_ldt = pcb->ims.ldt;
234: if (old_ldt == 0 ||
235: old_ldt->desc.limit_low + 1 < ldt_size_needed)
236: {
237: /*
238: * No old LDT, or not big enough
239: */
240: if (new_ldt == 0) {
241: simple_unlock(&pcb->lock);
242:
243: new_ldt = (user_ldt_t) kalloc(ldt_size_needed
244: + sizeof(struct real_descriptor));
245: new_ldt->desc.limit_low = ldt_size_needed - 1;
246: new_ldt->desc.limit_high = 0;
247: new_ldt->desc.base_low =
248: ((vm_offset_t)&new_ldt->ldt[0]) & 0xffff;
249: new_ldt->desc.base_med =
250: (((vm_offset_t)&new_ldt->ldt[0]) >> 16)
251: & 0xff;
252: new_ldt->desc.base_high =
253: ((vm_offset_t)&new_ldt->ldt[0]) >> 24;
254: new_ldt->desc.access = ACC_P | ACC_LDT;
255: new_ldt->desc.granularity = 0;
256:
257: goto Retry;
258: }
259:
260: /*
261: * Have new LDT. If there was a an old ldt, copy descriptors
262: * from old to new. Otherwise copy the default ldt.
263: */
264: if (old_ldt) {
265: bcopy((char *)&old_ldt->ldt[0],
266: (char *)&new_ldt->ldt[0],
267: old_ldt->desc.limit_low + 1);
268: }
269: else if (thr_act == current_act()) {
270: struct real_descriptor template = {0, 0, 0, ACC_P, 0, 0 ,0};
271:
272: for (dp = &new_ldt->ldt[0], i = 0; i < first_desc; i++, dp++) {
273: if (i < LDTSZ)
274: *dp = *(struct real_descriptor *) &ldt[i];
275: else
276: *dp = template;
277: }
278: }
279:
280: temp = old_ldt;
281: old_ldt = new_ldt; /* use new LDT from now on */
282: new_ldt = temp; /* discard old LDT */
283:
284: pcb->ims.ldt = old_ldt; /* new LDT for thread */
285: }
286:
287: /*
288: * Install new descriptors.
289: */
290: bcopy((char *)desc_list,
291: (char *)&old_ldt->ldt[first_desc],
292: count * sizeof(struct real_descriptor));
293:
294: simple_unlock(&pcb->lock);
295:
296: if (new_ldt)
297: kfree((vm_offset_t)new_ldt,
298: new_ldt->desc.limit_low+1+sizeof(struct real_descriptor));
299:
300: /*
301: * Free the descriptor list.
302: */
303: (void) vm_map_remove(ipc_kernel_map, (vm_offset_t) desc_list,
304: count * sizeof(struct real_descriptor),
305: VM_MAP_REMOVE_KUNWIRE);
306: return KERN_SUCCESS;
307: }
308:
309: kern_return_t
310: i386_get_ldt(
311: thread_act_t thr_act,
312: int first_selector,
313: int selector_count, /* number wanted */
314: descriptor_list_t *desc_list, /* in/out */
315: mach_msg_type_number_t *count) /* in/out */
316: {
317: struct user_ldt *user_ldt;
318: pcb_t pcb = thr_act->mact.pcb;
319: int first_desc = sel_idx(first_selector);
320: unsigned int ldt_count;
321: vm_size_t ldt_size;
322: vm_size_t size, size_needed;
323: vm_offset_t addr;
324: thread_t thread;
325:
326: if (thr_act == THR_ACT_NULL || (thread = thr_act->thread)==THREAD_NULL)
327: return KERN_INVALID_ARGUMENT;
328:
329: if (first_desc < 0 || first_desc > 8191)
330: return KERN_INVALID_ARGUMENT;
331: if (first_desc + selector_count >= 8192)
332: return KERN_INVALID_ARGUMENT;
333:
334: addr = 0;
335: size = 0;
336:
337: for (;;) {
338: simple_lock(&pcb->lock);
339: user_ldt = pcb->ims.ldt;
340: if (user_ldt == 0) {
341: simple_unlock(&pcb->lock);
342: if (addr)
343: kmem_free(ipc_kernel_map, addr, size);
344: *count = 0;
345: return KERN_SUCCESS;
346: }
347:
348: /*
349: * Find how many descriptors we should return.
350: */
351: ldt_count = (user_ldt->desc.limit_low + 1) /
352: sizeof (struct real_descriptor);
353: ldt_count -= first_desc;
354: if (ldt_count > selector_count)
355: ldt_count = selector_count;
356:
357: ldt_size = ldt_count * sizeof(struct real_descriptor);
358:
359: /*
360: * Do we have the memory we need?
361: */
362: if (ldt_count <= *count)
363: break; /* fits in-line */
364:
365: size_needed = round_page(ldt_size);
366: if (size_needed <= size)
367: break;
368:
369: /*
370: * Unlock the pcb and allocate more memory
371: */
372: simple_unlock(&pcb->lock);
373:
374: if (size != 0)
375: kmem_free(ipc_kernel_map, addr, size);
376:
377: size = size_needed;
378:
379: if (kmem_alloc(ipc_kernel_map, &addr, size)
380: != KERN_SUCCESS)
381: return KERN_RESOURCE_SHORTAGE;
382: }
383:
384: /*
385: * copy out the descriptors
386: */
387: bcopy((char *)&user_ldt->ldt[first_desc],
388: (char *)addr,
389: ldt_size);
390: *count = ldt_count;
391: simple_unlock(&pcb->lock);
392:
393: if (addr) {
394: vm_size_t size_used, size_left;
395: vm_map_copy_t memory;
396:
397: /*
398: * Free any unused memory beyond the end of the last page used
399: */
400: size_used = round_page(ldt_size);
401: if (size_used != size)
402: kmem_free(ipc_kernel_map,
403: addr + size_used, size - size_used);
404:
405: /*
406: * Zero the remainder of the page being returned.
407: */
408: size_left = size_used - ldt_size;
409: if (size_left > 0)
410: bzero((char *)addr + ldt_size, size_left);
411:
412: /*
413: * Unwire the memory and make it into copyin form.
414: */
415: (void) vm_map_unwire(ipc_kernel_map, trunc_page(addr),
416: round_page(addr + size_used), FALSE);
417: (void) vm_map_copyin(ipc_kernel_map, addr, size_used,
418: TRUE, &memory);
419: *desc_list = (descriptor_list_t) memory;
420: }
421:
422: return KERN_SUCCESS;
423: }
424:
425: #endif
426: void
427: user_ldt_free(
428: user_ldt_t user_ldt)
429: {
430: kfree((vm_offset_t)user_ldt,
431: user_ldt->desc.limit_low+1+sizeof(struct real_descriptor));
432: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.