]>
Commit | Line | Data |
---|---|---|
6d2010ae A |
1 | /* |
2 | * Copyright (c) 2010 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
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. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
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. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | #include <mach_rt.h> | |
29 | #include <mach_debug.h> | |
30 | #include <mach_ldebug.h> | |
31 | ||
32 | #include <mach/kern_return.h> | |
33 | #include <mach/mach_traps.h> | |
34 | #include <mach/thread_status.h> | |
35 | #include <mach/vm_param.h> | |
36 | ||
37 | #include <kern/counters.h> | |
38 | #include <kern/cpu_data.h> | |
39 | #include <kern/mach_param.h> | |
40 | #include <kern/task.h> | |
41 | #include <kern/thread.h> | |
42 | #include <kern/sched_prim.h> | |
43 | #include <kern/misc_protos.h> | |
44 | #include <kern/assert.h> | |
45 | #include <kern/debug.h> | |
46 | #include <kern/spl.h> | |
47 | #include <kern/syscall_sw.h> | |
48 | #include <ipc/ipc_port.h> | |
49 | #include <vm/vm_kern.h> | |
50 | #include <vm/pmap.h> | |
51 | ||
52 | #include <i386/cpu_number.h> | |
53 | #include <i386/eflags.h> | |
54 | #include <i386/proc_reg.h> | |
55 | #include <i386/tss.h> | |
56 | #include <i386/user_ldt.h> | |
57 | #include <i386/fpu.h> | |
58 | #include <i386/machdep_call.h> | |
59 | #include <i386/vmparam.h> | |
60 | #include <i386/mp_desc.h> | |
61 | #include <i386/misc_protos.h> | |
62 | #include <i386/thread.h> | |
63 | #include <i386/trap.h> | |
64 | #include <i386/seg.h> | |
65 | #include <mach/i386/syscall_sw.h> | |
66 | #include <sys/syscall.h> | |
67 | #include <sys/kdebug.h> | |
68 | #include <sys/errno.h> | |
69 | #include <../bsd/sys/sysent.h> | |
70 | ||
71 | ||
72 | /* | |
73 | * Duplicate parent state in child | |
74 | * for U**X fork. | |
75 | */ | |
76 | kern_return_t | |
77 | machine_thread_dup( | |
78 | thread_t parent, | |
79 | thread_t child | |
80 | ) | |
81 | { | |
82 | ||
83 | pcb_t parent_pcb = THREAD_TO_PCB(parent); | |
84 | pcb_t child_pcb = THREAD_TO_PCB(child); | |
85 | ||
86 | /* | |
87 | * Copy over the x86_saved_state registers | |
88 | */ | |
89 | if (cpu_mode_is64bit()) { | |
90 | if (thread_is_64bit(parent)) | |
91 | bcopy(USER_REGS64(parent), USER_REGS64(child), sizeof(x86_saved_state64_t)); | |
92 | else | |
93 | bcopy(USER_REGS32(parent), USER_REGS32(child), sizeof(x86_saved_state_compat32_t)); | |
94 | } else | |
95 | bcopy(USER_REGS32(parent), USER_REGS32(child), sizeof(x86_saved_state32_t)); | |
96 | ||
97 | /* | |
98 | * Check to see if parent is using floating point | |
99 | * and if so, copy the registers to the child | |
100 | */ | |
101 | fpu_dup_fxstate(parent, child); | |
102 | ||
103 | #ifdef MACH_BSD | |
104 | /* | |
105 | * Copy the parent's cthread id and USER_CTHREAD descriptor, if 32-bit. | |
106 | */ | |
107 | child_pcb->cthread_self = parent_pcb->cthread_self; | |
108 | if (!thread_is_64bit(parent)) | |
109 | child_pcb->cthread_desc = parent_pcb->cthread_desc; | |
110 | ||
111 | /* | |
112 | * FIXME - should a user specified LDT, TSS and V86 info | |
113 | * be duplicated as well?? - probably not. | |
114 | */ | |
115 | // duplicate any use LDT entry that was set I think this is appropriate. | |
116 | if (parent_pcb->uldt_selector!= 0) { | |
117 | child_pcb->uldt_selector = parent_pcb->uldt_selector; | |
118 | child_pcb->uldt_desc = parent_pcb->uldt_desc; | |
119 | } | |
120 | #endif | |
121 | ||
122 | return (KERN_SUCCESS); | |
123 | } | |
124 | ||
125 | void thread_set_parent(thread_t parent, int pid); | |
126 | ||
127 | void | |
128 | thread_set_parent(thread_t parent, int pid) | |
129 | { | |
130 | pal_register_cache_state(parent, DIRTY); | |
131 | ||
132 | if (thread_is_64bit(parent)) { | |
133 | x86_saved_state64_t *iss64; | |
134 | ||
135 | iss64 = USER_REGS64(parent); | |
136 | ||
137 | iss64->rax = pid; | |
138 | iss64->rdx = 0; | |
139 | iss64->isf.rflags &= ~EFL_CF; | |
140 | } else { | |
141 | x86_saved_state32_t *iss32; | |
142 | ||
143 | iss32 = USER_REGS32(parent); | |
144 | ||
145 | iss32->eax = pid; | |
146 | iss32->edx = 0; | |
147 | iss32->efl &= ~EFL_CF; | |
148 | } | |
149 | } | |
150 | ||
151 | /* | |
152 | * thread_fast_set_cthread_self: Sets the machine kernel thread ID of the | |
153 | * current thread to the given thread ID; fast version for 32-bit processes | |
154 | * | |
155 | * Parameters: self Thread ID to set | |
156 | * | |
157 | * Returns: 0 Success | |
158 | * !0 Not success | |
159 | */ | |
160 | kern_return_t | |
161 | thread_fast_set_cthread_self(uint32_t self) | |
162 | { | |
163 | thread_t thread = current_thread(); | |
164 | pcb_t pcb = THREAD_TO_PCB(thread); | |
165 | struct real_descriptor desc = { | |
166 | .limit_low = 1, | |
167 | .limit_high = 0, | |
168 | .base_low = self & 0xffff, | |
169 | .base_med = (self >> 16) & 0xff, | |
170 | .base_high = (self >> 24) & 0xff, | |
171 | .access = ACC_P|ACC_PL_U|ACC_DATA_W, | |
172 | .granularity = SZ_32|SZ_G, | |
173 | }; | |
174 | ||
175 | current_thread()->machine.cthread_self = (uint64_t) self; /* preserve old func too */ | |
176 | ||
177 | /* assign descriptor */ | |
178 | mp_disable_preemption(); | |
179 | pcb->cthread_desc = desc; | |
180 | *ldt_desc_p(USER_CTHREAD) = desc; | |
181 | saved_state32(pcb->iss)->gs = USER_CTHREAD; | |
182 | mp_enable_preemption(); | |
183 | ||
184 | return (USER_CTHREAD); | |
185 | } | |
186 | ||
187 | /* | |
188 | * thread_fast_set_cthread_self64: Sets the machine kernel thread ID of the | |
189 | * current thread to the given thread ID; fast version for 64-bit processes | |
190 | * | |
191 | * Parameters: self Thread ID | |
192 | * | |
193 | * Returns: 0 Success | |
194 | * !0 Not success | |
195 | */ | |
196 | kern_return_t | |
197 | thread_fast_set_cthread_self64(uint64_t self) | |
198 | { | |
199 | pcb_t pcb = THREAD_TO_PCB(current_thread()); | |
200 | cpu_data_t *cdp; | |
201 | ||
202 | /* check for canonical address, set 0 otherwise */ | |
203 | if (!IS_USERADDR64_CANONICAL(self)) | |
204 | self = 0ULL; | |
205 | ||
206 | pcb->cthread_self = self; | |
207 | mp_disable_preemption(); | |
208 | cdp = current_cpu_datap(); | |
209 | #if defined(__x86_64__) | |
210 | if ((cdp->cpu_uber.cu_user_gs_base != pcb->cthread_self) || | |
211 | (pcb->cthread_self != rdmsr64(MSR_IA32_KERNEL_GS_BASE))) | |
212 | wrmsr64(MSR_IA32_KERNEL_GS_BASE, self); | |
213 | #endif | |
214 | cdp->cpu_uber.cu_user_gs_base = self; | |
215 | mp_enable_preemption(); | |
216 | return (USER_CTHREAD); /* N.B.: not a kern_return_t! */ | |
217 | } | |
218 | ||
219 | /* | |
220 | * thread_set_user_ldt routine is the interface for the user level | |
221 | * settable ldt entry feature. allowing a user to create arbitrary | |
222 | * ldt entries seems to be too large of a security hole, so instead | |
223 | * this mechanism is in place to allow user level processes to have | |
224 | * an ldt entry that can be used in conjunction with the FS register. | |
225 | * | |
226 | * Swapping occurs inside the pcb.c file along with initialization | |
227 | * when a thread is created. The basic functioning theory is that the | |
228 | * pcb->uldt_selector variable will contain either 0 meaning the | |
229 | * process has not set up any entry, or the selector to be used in | |
230 | * the FS register. pcb->uldt_desc contains the actual descriptor the | |
231 | * user has set up stored in machine usable ldt format. | |
232 | * | |
233 | * Currently one entry is shared by all threads (USER_SETTABLE), but | |
234 | * this could be changed in the future by changing how this routine | |
235 | * allocates the selector. There seems to be no real reason at this | |
236 | * time to have this added feature, but in the future it might be | |
237 | * needed. | |
238 | * | |
239 | * address is the linear address of the start of the data area size | |
240 | * is the size in bytes of the area flags should always be set to 0 | |
241 | * for now. in the future it could be used to set R/W permisions or | |
242 | * other functions. Currently the segment is created as a data segment | |
243 | * up to 1 megabyte in size with full read/write permisions only. | |
244 | * | |
245 | * this call returns the segment selector or -1 if any error occurs | |
246 | */ | |
247 | kern_return_t | |
248 | thread_set_user_ldt(uint32_t address, uint32_t size, uint32_t flags) | |
249 | { | |
250 | pcb_t pcb; | |
251 | struct fake_descriptor temp; | |
252 | ||
253 | if (flags != 0) | |
254 | return -1; // flags not supported | |
255 | if (size > 0xFFFFF) | |
256 | return -1; // size too big, 1 meg is the limit | |
257 | ||
258 | mp_disable_preemption(); | |
259 | ||
260 | // create a "fake" descriptor so we can use fix_desc() | |
261 | // to build a real one... | |
262 | // 32 bit default operation size | |
263 | // standard read/write perms for a data segment | |
264 | pcb = THREAD_TO_PCB(current_thread()); | |
265 | temp.offset = address; | |
266 | temp.lim_or_seg = size; | |
267 | temp.size_or_wdct = SZ_32; | |
268 | temp.access = ACC_P|ACC_PL_U|ACC_DATA_W; | |
269 | ||
270 | // turn this into a real descriptor | |
271 | fix_desc(&temp,1); | |
272 | ||
273 | // set up our data in the pcb | |
274 | pcb->uldt_desc = *(struct real_descriptor*)&temp; | |
275 | pcb->uldt_selector = USER_SETTABLE; // set the selector value | |
276 | ||
277 | // now set it up in the current table... | |
278 | *ldt_desc_p(USER_SETTABLE) = *(struct real_descriptor*)&temp; | |
279 | ||
280 | mp_enable_preemption(); | |
281 | ||
282 | return USER_SETTABLE; | |
283 | } |