]>
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@ | |
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 | */ | |
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 | ||
36 | #include <kern/counters.h> | |
37 | #include <kern/cpu_data.h> | |
38 | #include <kern/mach_param.h> | |
39 | #include <kern/task.h> | |
40 | #include <kern/thread.h> | |
41 | #include <kern/sched_prim.h> | |
42 | #include <kern/misc_protos.h> | |
43 | #include <kern/assert.h> | |
44 | #include <kern/debug.h> | |
45 | #include <kern/spl.h> | |
46 | #include <kern/syscall_sw.h> | |
47 | #include <ipc/ipc_port.h> | |
48 | #include <vm/vm_kern.h> | |
49 | #include <vm/pmap.h> | |
50 | ||
51 | #include <i386/cpu_number.h> | |
52 | #include <i386/eflags.h> | |
53 | #include <i386/proc_reg.h> | |
54 | #include <i386/tss.h> | |
55 | #include <i386/user_ldt.h> | |
56 | #include <i386/fpu.h> | |
57 | #include <i386/machdep_call.h> | |
58 | #include <i386/vmparam.h> | |
59 | #include <i386/mp_desc.h> | |
60 | #include <i386/misc_protos.h> | |
61 | #include <i386/thread.h> | |
62 | #include <i386/trap.h> | |
63 | #include <i386/seg.h> | |
64 | #include <mach/i386/syscall_sw.h> | |
65 | #include <sys/syscall.h> | |
66 | #include <sys/kdebug.h> | |
67 | #include <sys/errno.h> | |
68 | #include <../bsd/sys/sysent.h> | |
69 | ||
70 | ||
71 | /* | |
72 | * Duplicate parent state in child | |
73 | * for U**X fork. | |
74 | */ | |
75 | kern_return_t | |
76 | machine_thread_dup( | |
77 | thread_t parent, | |
78 | thread_t child | |
79 | ) | |
80 | { | |
81 | ||
82 | pcb_t parent_pcb = THREAD_TO_PCB(parent); | |
83 | pcb_t child_pcb = THREAD_TO_PCB(child); | |
84 | ||
85 | /* | |
86 | * Copy over the x86_saved_state registers | |
87 | */ | |
39236c6e A |
88 | if (thread_is_64bit(parent)) |
89 | bcopy(USER_REGS64(parent), USER_REGS64(child), sizeof(x86_saved_state64_t)); | |
90 | else | |
6d2010ae A |
91 | bcopy(USER_REGS32(parent), USER_REGS32(child), sizeof(x86_saved_state32_t)); |
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 | ||
99 | #ifdef MACH_BSD | |
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; | |
104 | if (!thread_is_64bit(parent)) | |
105 | child_pcb->cthread_desc = parent_pcb->cthread_desc; | |
106 | ||
107 | /* | |
108 | * FIXME - should a user specified LDT, TSS and V86 info | |
109 | * be duplicated as well?? - probably not. | |
110 | */ | |
111 | // duplicate any use LDT entry that was set I think this is appropriate. | |
112 | if (parent_pcb->uldt_selector!= 0) { | |
113 | child_pcb->uldt_selector = parent_pcb->uldt_selector; | |
114 | child_pcb->uldt_desc = parent_pcb->uldt_desc; | |
115 | } | |
116 | #endif | |
117 | ||
118 | return (KERN_SUCCESS); | |
119 | } | |
120 | ||
121 | void thread_set_parent(thread_t parent, int pid); | |
122 | ||
123 | void | |
124 | thread_set_parent(thread_t parent, int pid) | |
125 | { | |
126 | pal_register_cache_state(parent, DIRTY); | |
127 | ||
128 | if (thread_is_64bit(parent)) { | |
129 | x86_saved_state64_t *iss64; | |
130 | ||
131 | iss64 = USER_REGS64(parent); | |
132 | ||
133 | iss64->rax = pid; | |
134 | iss64->rdx = 0; | |
135 | iss64->isf.rflags &= ~EFL_CF; | |
136 | } else { | |
137 | x86_saved_state32_t *iss32; | |
138 | ||
139 | iss32 = USER_REGS32(parent); | |
140 | ||
141 | iss32->eax = pid; | |
142 | iss32->edx = 0; | |
143 | iss32->efl &= ~EFL_CF; | |
144 | } | |
145 | } | |
146 | ||
147 | /* | |
148 | * thread_fast_set_cthread_self: Sets the machine kernel thread ID of the | |
149 | * current thread to the given thread ID; fast version for 32-bit processes | |
150 | * | |
151 | * Parameters: self Thread ID to set | |
152 | * | |
153 | * Returns: 0 Success | |
154 | * !0 Not success | |
155 | */ | |
156 | kern_return_t | |
157 | thread_fast_set_cthread_self(uint32_t self) | |
158 | { | |
fe8ab488 A |
159 | machine_thread_set_tsd_base(current_thread(), self); |
160 | return (USER_CTHREAD); /* N.B.: not a kern_return_t! */ | |
6d2010ae A |
161 | } |
162 | ||
163 | /* | |
164 | * thread_fast_set_cthread_self64: Sets the machine kernel thread ID of the | |
165 | * current thread to the given thread ID; fast version for 64-bit processes | |
166 | * | |
167 | * Parameters: self Thread ID | |
168 | * | |
169 | * Returns: 0 Success | |
170 | * !0 Not success | |
171 | */ | |
172 | kern_return_t | |
173 | thread_fast_set_cthread_self64(uint64_t self) | |
174 | { | |
fe8ab488 | 175 | machine_thread_set_tsd_base(current_thread(), self); |
6d2010ae A |
176 | return (USER_CTHREAD); /* N.B.: not a kern_return_t! */ |
177 | } | |
178 | ||
179 | /* | |
180 | * thread_set_user_ldt routine is the interface for the user level | |
181 | * settable ldt entry feature. allowing a user to create arbitrary | |
182 | * ldt entries seems to be too large of a security hole, so instead | |
183 | * this mechanism is in place to allow user level processes to have | |
184 | * an ldt entry that can be used in conjunction with the FS register. | |
185 | * | |
186 | * Swapping occurs inside the pcb.c file along with initialization | |
187 | * when a thread is created. The basic functioning theory is that the | |
188 | * pcb->uldt_selector variable will contain either 0 meaning the | |
189 | * process has not set up any entry, or the selector to be used in | |
190 | * the FS register. pcb->uldt_desc contains the actual descriptor the | |
191 | * user has set up stored in machine usable ldt format. | |
192 | * | |
193 | * Currently one entry is shared by all threads (USER_SETTABLE), but | |
194 | * this could be changed in the future by changing how this routine | |
195 | * allocates the selector. There seems to be no real reason at this | |
196 | * time to have this added feature, but in the future it might be | |
197 | * needed. | |
198 | * | |
199 | * address is the linear address of the start of the data area size | |
200 | * is the size in bytes of the area flags should always be set to 0 | |
201 | * for now. in the future it could be used to set R/W permisions or | |
202 | * other functions. Currently the segment is created as a data segment | |
203 | * up to 1 megabyte in size with full read/write permisions only. | |
204 | * | |
205 | * this call returns the segment selector or -1 if any error occurs | |
206 | */ | |
207 | kern_return_t | |
208 | thread_set_user_ldt(uint32_t address, uint32_t size, uint32_t flags) | |
209 | { | |
210 | pcb_t pcb; | |
211 | struct fake_descriptor temp; | |
212 | ||
213 | if (flags != 0) | |
214 | return -1; // flags not supported | |
215 | if (size > 0xFFFFF) | |
216 | return -1; // size too big, 1 meg is the limit | |
217 | ||
218 | mp_disable_preemption(); | |
219 | ||
220 | // create a "fake" descriptor so we can use fix_desc() | |
221 | // to build a real one... | |
222 | // 32 bit default operation size | |
223 | // standard read/write perms for a data segment | |
224 | pcb = THREAD_TO_PCB(current_thread()); | |
225 | temp.offset = address; | |
226 | temp.lim_or_seg = size; | |
227 | temp.size_or_wdct = SZ_32; | |
228 | temp.access = ACC_P|ACC_PL_U|ACC_DATA_W; | |
229 | ||
230 | // turn this into a real descriptor | |
231 | fix_desc(&temp,1); | |
232 | ||
233 | // set up our data in the pcb | |
234 | pcb->uldt_desc = *(struct real_descriptor*)&temp; | |
235 | pcb->uldt_selector = USER_SETTABLE; // set the selector value | |
236 | ||
237 | // now set it up in the current table... | |
238 | *ldt_desc_p(USER_SETTABLE) = *(struct real_descriptor*)&temp; | |
239 | ||
240 | mp_enable_preemption(); | |
241 | ||
242 | return USER_SETTABLE; | |
243 | } |