]>
Commit | Line | Data |
---|---|---|
6d2010ae | 1 | /* |
39236c6e | 2 | * Copyright (c) 2010-2012 Apple Inc. All rights reserved. |
6d2010ae A |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
0a7de745 | 5 | * |
6d2010ae A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
0a7de745 | 14 | * |
6d2010ae A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
6d2010ae A |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
0a7de745 | 25 | * |
6d2010ae A |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ | |
6d2010ae A |
28 | #include <mach_debug.h> |
29 | #include <mach_ldebug.h> | |
30 | ||
31 | #include <mach/kern_return.h> | |
32 | #include <mach/mach_traps.h> | |
33 | #include <mach/thread_status.h> | |
34 | #include <mach/vm_param.h> | |
35 | ||
6d2010ae A |
36 | #include <kern/cpu_data.h> |
37 | #include <kern/mach_param.h> | |
38 | #include <kern/task.h> | |
39 | #include <kern/thread.h> | |
40 | #include <kern/sched_prim.h> | |
41 | #include <kern/misc_protos.h> | |
42 | #include <kern/assert.h> | |
43 | #include <kern/debug.h> | |
44 | #include <kern/spl.h> | |
45 | #include <kern/syscall_sw.h> | |
46 | #include <ipc/ipc_port.h> | |
47 | #include <vm/vm_kern.h> | |
48 | #include <vm/pmap.h> | |
49 | ||
50 | #include <i386/cpu_number.h> | |
51 | #include <i386/eflags.h> | |
52 | #include <i386/proc_reg.h> | |
53 | #include <i386/tss.h> | |
54 | #include <i386/user_ldt.h> | |
55 | #include <i386/fpu.h> | |
56 | #include <i386/machdep_call.h> | |
57 | #include <i386/vmparam.h> | |
58 | #include <i386/mp_desc.h> | |
59 | #include <i386/misc_protos.h> | |
60 | #include <i386/thread.h> | |
61 | #include <i386/trap.h> | |
62 | #include <i386/seg.h> | |
63 | #include <mach/i386/syscall_sw.h> | |
64 | #include <sys/syscall.h> | |
65 | #include <sys/kdebug.h> | |
66 | #include <sys/errno.h> | |
67 | #include <../bsd/sys/sysent.h> | |
68 | ||
69 | ||
70 | /* | |
71 | * Duplicate parent state in child | |
72 | * for U**X fork. | |
73 | */ | |
74 | kern_return_t | |
75 | machine_thread_dup( | |
0a7de745 A |
76 | thread_t parent, |
77 | thread_t child, | |
78 | __unused boolean_t is_corpse | |
79 | ) | |
6d2010ae | 80 | { |
0a7de745 A |
81 | pcb_t parent_pcb = THREAD_TO_PCB(parent); |
82 | pcb_t child_pcb = THREAD_TO_PCB(child); | |
6d2010ae A |
83 | |
84 | /* | |
85 | * Copy over the x86_saved_state registers | |
86 | */ | |
0a7de745 | 87 | if (thread_is_64bit_addr(parent)) { |
39236c6e | 88 | bcopy(USER_REGS64(parent), USER_REGS64(child), sizeof(x86_saved_state64_t)); |
0a7de745 | 89 | } else { |
6d2010ae | 90 | bcopy(USER_REGS32(parent), USER_REGS32(child), sizeof(x86_saved_state32_t)); |
0a7de745 | 91 | } |
6d2010ae A |
92 | |
93 | /* | |
94 | * Check to see if parent is using floating point | |
95 | * and if so, copy the registers to the child | |
96 | */ | |
97 | fpu_dup_fxstate(parent, child); | |
98 | ||
0a7de745 | 99 | #ifdef MACH_BSD |
6d2010ae A |
100 | /* |
101 | * Copy the parent's cthread id and USER_CTHREAD descriptor, if 32-bit. | |
102 | */ | |
103 | child_pcb->cthread_self = parent_pcb->cthread_self; | |
0a7de745 | 104 | if (!thread_is_64bit_addr(parent)) { |
6d2010ae | 105 | child_pcb->cthread_desc = parent_pcb->cthread_desc; |
0a7de745 | 106 | } |
6d2010ae A |
107 | |
108 | /* | |
109 | * FIXME - should a user specified LDT, TSS and V86 info | |
110 | * be duplicated as well?? - probably not. | |
111 | */ | |
112 | // duplicate any use LDT entry that was set I think this is appropriate. | |
0a7de745 A |
113 | if (parent_pcb->uldt_selector != 0) { |
114 | child_pcb->uldt_selector = parent_pcb->uldt_selector; | |
6d2010ae A |
115 | child_pcb->uldt_desc = parent_pcb->uldt_desc; |
116 | } | |
117 | #endif | |
118 | ||
0a7de745 | 119 | return KERN_SUCCESS; |
6d2010ae A |
120 | } |
121 | ||
122 | void thread_set_parent(thread_t parent, int pid); | |
123 | ||
124 | void | |
125 | thread_set_parent(thread_t parent, int pid) | |
126 | { | |
127 | pal_register_cache_state(parent, DIRTY); | |
128 | ||
d9a64523 | 129 | if (thread_is_64bit_addr(parent)) { |
0a7de745 | 130 | x86_saved_state64_t *iss64; |
6d2010ae A |
131 | |
132 | iss64 = USER_REGS64(parent); | |
133 | ||
134 | iss64->rax = pid; | |
135 | iss64->rdx = 0; | |
136 | iss64->isf.rflags &= ~EFL_CF; | |
137 | } else { | |
0a7de745 | 138 | x86_saved_state32_t *iss32; |
6d2010ae A |
139 | |
140 | iss32 = USER_REGS32(parent); | |
141 | ||
142 | iss32->eax = pid; | |
143 | iss32->edx = 0; | |
144 | iss32->efl &= ~EFL_CF; | |
145 | } | |
146 | } | |
147 | ||
148 | /* | |
149 | * thread_fast_set_cthread_self: Sets the machine kernel thread ID of the | |
150 | * current thread to the given thread ID; fast version for 32-bit processes | |
151 | * | |
152 | * Parameters: self Thread ID to set | |
0a7de745 | 153 | * |
6d2010ae A |
154 | * Returns: 0 Success |
155 | * !0 Not success | |
156 | */ | |
157 | kern_return_t | |
158 | thread_fast_set_cthread_self(uint32_t self) | |
159 | { | |
fe8ab488 | 160 | machine_thread_set_tsd_base(current_thread(), self); |
0a7de745 | 161 | return USER_CTHREAD; /* N.B.: not a kern_return_t! */ |
6d2010ae A |
162 | } |
163 | ||
164 | /* | |
165 | * thread_fast_set_cthread_self64: Sets the machine kernel thread ID of the | |
0a7de745 | 166 | * current thread to the given thread ID; fast version for 64-bit processes |
6d2010ae A |
167 | * |
168 | * Parameters: self Thread ID | |
0a7de745 | 169 | * |
6d2010ae A |
170 | * Returns: 0 Success |
171 | * !0 Not success | |
172 | */ | |
173 | kern_return_t | |
174 | thread_fast_set_cthread_self64(uint64_t self) | |
175 | { | |
fe8ab488 | 176 | machine_thread_set_tsd_base(current_thread(), self); |
0a7de745 | 177 | return USER_CTHREAD; /* N.B.: not a kern_return_t! */ |
6d2010ae A |
178 | } |
179 | ||
180 | /* | |
181 | * thread_set_user_ldt routine is the interface for the user level | |
182 | * settable ldt entry feature. allowing a user to create arbitrary | |
183 | * ldt entries seems to be too large of a security hole, so instead | |
184 | * this mechanism is in place to allow user level processes to have | |
185 | * an ldt entry that can be used in conjunction with the FS register. | |
186 | * | |
187 | * Swapping occurs inside the pcb.c file along with initialization | |
188 | * when a thread is created. The basic functioning theory is that the | |
189 | * pcb->uldt_selector variable will contain either 0 meaning the | |
190 | * process has not set up any entry, or the selector to be used in | |
191 | * the FS register. pcb->uldt_desc contains the actual descriptor the | |
192 | * user has set up stored in machine usable ldt format. | |
193 | * | |
194 | * Currently one entry is shared by all threads (USER_SETTABLE), but | |
195 | * this could be changed in the future by changing how this routine | |
196 | * allocates the selector. There seems to be no real reason at this | |
197 | * time to have this added feature, but in the future it might be | |
198 | * needed. | |
199 | * | |
200 | * address is the linear address of the start of the data area size | |
201 | * is the size in bytes of the area flags should always be set to 0 | |
202 | * for now. in the future it could be used to set R/W permisions or | |
203 | * other functions. Currently the segment is created as a data segment | |
204 | * up to 1 megabyte in size with full read/write permisions only. | |
205 | * | |
206 | * this call returns the segment selector or -1 if any error occurs | |
207 | */ | |
208 | kern_return_t | |
209 | thread_set_user_ldt(uint32_t address, uint32_t size, uint32_t flags) | |
210 | { | |
211 | pcb_t pcb; | |
212 | struct fake_descriptor temp; | |
213 | ||
0a7de745 A |
214 | if (flags != 0) { |
215 | return -1; // flags not supported | |
216 | } | |
217 | if (size > 0xFFFFF) { | |
218 | return -1; // size too big, 1 meg is the limit | |
219 | } | |
6d2010ae A |
220 | mp_disable_preemption(); |
221 | ||
222 | // create a "fake" descriptor so we can use fix_desc() | |
223 | // to build a real one... | |
224 | // 32 bit default operation size | |
225 | // standard read/write perms for a data segment | |
226 | pcb = THREAD_TO_PCB(current_thread()); | |
227 | temp.offset = address; | |
228 | temp.lim_or_seg = size; | |
229 | temp.size_or_wdct = SZ_32; | |
0a7de745 | 230 | temp.access = ACC_P | ACC_PL_U | ACC_DATA_W; |
6d2010ae A |
231 | |
232 | // turn this into a real descriptor | |
0a7de745 | 233 | fix_desc(&temp, 1); |
6d2010ae A |
234 | |
235 | // set up our data in the pcb | |
236 | pcb->uldt_desc = *(struct real_descriptor*)&temp; | |
0a7de745 | 237 | pcb->uldt_selector = USER_SETTABLE; // set the selector value |
6d2010ae A |
238 | |
239 | // now set it up in the current table... | |
240 | *ldt_desc_p(USER_SETTABLE) = *(struct real_descriptor*)&temp; | |
241 | ||
242 | mp_enable_preemption(); | |
243 | ||
244 | return USER_SETTABLE; | |
245 | } |