]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
91447636 | 2 | * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved. |
1c79356b | 3 | * |
8f6c56a5 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
8f6c56a5 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. | |
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 | |
8ad349bb | 24 | * limitations under the License. |
8f6c56a5 A |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
1c79356b A |
27 | */ |
28 | #ifdef MACH_BSD | |
1c79356b A |
29 | #include <mach_rt.h> |
30 | #include <mach_debug.h> | |
31 | #include <mach_ldebug.h> | |
32 | ||
33 | #include <mach/kern_return.h> | |
91447636 | 34 | #include <mach/mach_traps.h> |
1c79356b A |
35 | #include <mach/thread_status.h> |
36 | #include <mach/vm_param.h> | |
1c79356b A |
37 | |
38 | #include <kern/counters.h> | |
39 | #include <kern/cpu_data.h> | |
40 | #include <kern/mach_param.h> | |
41 | #include <kern/task.h> | |
42 | #include <kern/thread.h> | |
1c79356b A |
43 | #include <kern/sched_prim.h> |
44 | #include <kern/misc_protos.h> | |
45 | #include <kern/assert.h> | |
46 | #include <kern/spl.h> | |
55e303ae | 47 | #include <kern/syscall_sw.h> |
1c79356b A |
48 | #include <ipc/ipc_port.h> |
49 | #include <vm/vm_kern.h> | |
50 | #include <vm/pmap.h> | |
51 | ||
91447636 A |
52 | #include <i386/cpu_data.h> |
53 | #include <i386/cpu_number.h> | |
1c79356b A |
54 | #include <i386/thread.h> |
55 | #include <i386/eflags.h> | |
56 | #include <i386/proc_reg.h> | |
57 | #include <i386/seg.h> | |
58 | #include <i386/tss.h> | |
59 | #include <i386/user_ldt.h> | |
60 | #include <i386/fpu.h> | |
61 | #include <i386/iopb_entries.h> | |
62 | #include <i386/machdep_call.h> | |
91447636 A |
63 | #include <i386/misc_protos.h> |
64 | #include <i386/cpu_data.h> | |
65 | #include <i386/cpu_number.h> | |
66 | #include <i386/mp_desc.h> | |
67 | #include <i386/vmparam.h> | |
89b3af67 A |
68 | #include <i386/trap.h> |
69 | #include <mach/i386/syscall_sw.h> | |
9bccf70c | 70 | #include <sys/syscall.h> |
91447636 | 71 | #include <sys/kdebug.h> |
9bccf70c | 72 | #include <sys/ktrace.h> |
89b3af67 | 73 | #include <sys/errno.h> |
91447636 A |
74 | #include <../bsd/sys/sysent.h> |
75 | ||
76 | extern struct proc *current_proc(void); | |
89b3af67 | 77 | extern struct proc * kernproc; |
1c79356b A |
78 | |
79 | kern_return_t | |
80 | thread_userstack( | |
81 | thread_t, | |
82 | int, | |
83 | thread_state_t, | |
84 | unsigned int, | |
91447636 | 85 | mach_vm_offset_t *, |
89b3af67 | 86 | int * |
1c79356b A |
87 | ); |
88 | ||
89 | kern_return_t | |
90 | thread_entrypoint( | |
91 | thread_t, | |
92 | int, | |
93 | thread_state_t, | |
94 | unsigned int, | |
91447636 | 95 | mach_vm_offset_t * |
1c79356b A |
96 | ); |
97 | ||
89b3af67 A |
98 | void * find_user_regs(thread_t); |
99 | ||
1c79356b A |
100 | unsigned int get_msr_exportmask(void); |
101 | ||
102 | unsigned int get_msr_nbits(void); | |
103 | ||
104 | unsigned int get_msr_rbits(void); | |
105 | ||
55e303ae A |
106 | kern_return_t |
107 | thread_compose_cthread_desc(unsigned int addr, pcb_t pcb); | |
108 | ||
91447636 A |
109 | void IOSleep(int); |
110 | ||
1c79356b A |
111 | /* |
112 | * thread_userstack: | |
113 | * | |
114 | * Return the user stack pointer from the machine | |
115 | * dependent thread state info. | |
116 | */ | |
117 | kern_return_t | |
118 | thread_userstack( | |
89b3af67 A |
119 | __unused thread_t thread, |
120 | int flavor, | |
121 | thread_state_t tstate, | |
122 | __unused unsigned int count, | |
123 | user_addr_t *user_stack, | |
124 | int *customstack | |
125 | ) | |
1c79356b | 126 | { |
0b4e3aa0 | 127 | if (customstack) |
89b3af67 | 128 | *customstack = 0; |
9bccf70c | 129 | |
1c79356b | 130 | switch (flavor) { |
89b3af67 A |
131 | case OLD_i386_THREAD_STATE: |
132 | case x86_THREAD_STATE32: | |
133 | { | |
134 | x86_thread_state32_t *state25; | |
135 | ||
136 | state25 = (x86_thread_state32_t *) tstate; | |
137 | ||
9bccf70c A |
138 | if (state25->esp) |
139 | *user_stack = state25->esp; | |
91447636 | 140 | else |
89b3af67 | 141 | *user_stack = VM_USRSTACK32; |
9bccf70c A |
142 | if (customstack && state25->esp) |
143 | *customstack = 1; | |
144 | else | |
145 | *customstack = 0; | |
1c79356b | 146 | break; |
89b3af67 | 147 | } |
c0fea474 | 148 | |
89b3af67 A |
149 | case x86_THREAD_STATE64: |
150 | { | |
151 | x86_thread_state64_t *state25; | |
152 | ||
153 | state25 = (x86_thread_state64_t *) tstate; | |
1c79356b | 154 | |
89b3af67 A |
155 | if (state25->rsp) |
156 | *user_stack = state25->rsp; | |
91447636 | 157 | else |
89b3af67 A |
158 | *user_stack = VM_USRSTACK64; |
159 | if (customstack && state25->rsp) | |
9bccf70c A |
160 | *customstack = 1; |
161 | else | |
162 | *customstack = 0; | |
89b3af67 A |
163 | break; |
164 | } | |
165 | ||
166 | default : | |
1c79356b A |
167 | return (KERN_INVALID_ARGUMENT); |
168 | } | |
169 | ||
170 | return (KERN_SUCCESS); | |
171 | } | |
172 | ||
89b3af67 | 173 | |
1c79356b A |
174 | kern_return_t |
175 | thread_entrypoint( | |
89b3af67 A |
176 | __unused thread_t thread, |
177 | int flavor, | |
178 | thread_state_t tstate, | |
179 | __unused unsigned int count, | |
180 | mach_vm_offset_t *entry_point | |
181 | ) | |
1c79356b | 182 | { |
89b3af67 A |
183 | /* |
184 | * Set a default. | |
185 | */ | |
186 | if (*entry_point == 0) | |
187 | *entry_point = VM_MIN_ADDRESS; | |
1c79356b | 188 | |
89b3af67 A |
189 | switch (flavor) { |
190 | case OLD_i386_THREAD_STATE: | |
191 | case x86_THREAD_STATE32: | |
192 | { | |
193 | x86_thread_state32_t *state25; | |
194 | ||
195 | state25 = (x86_thread_state32_t *) tstate; | |
196 | *entry_point = state25->eip ? state25->eip: VM_MIN_ADDRESS; | |
197 | break; | |
198 | } | |
8f6c56a5 | 199 | |
89b3af67 A |
200 | case x86_THREAD_STATE64: |
201 | { | |
202 | x86_thread_state64_t *state25; | |
203 | ||
204 | state25 = (x86_thread_state64_t *) tstate; | |
205 | *entry_point = state25->rip ? state25->rip: VM_MIN_ADDRESS64; | |
206 | break; | |
207 | } | |
208 | } | |
1c79356b A |
209 | return (KERN_SUCCESS); |
210 | } | |
211 | ||
1c79356b A |
212 | |
213 | /* | |
214 | * Duplicate parent state in child | |
215 | * for U**X fork. | |
216 | */ | |
55e303ae A |
217 | kern_return_t |
218 | machine_thread_dup( | |
91447636 A |
219 | thread_t parent, |
220 | thread_t child | |
1c79356b A |
221 | ) |
222 | { | |
89b3af67 A |
223 | |
224 | pcb_t parent_pcb; | |
225 | pcb_t child_pcb; | |
8ad349bb | 226 | |
89b3af67 A |
227 | if ((child_pcb = child->machine.pcb) == NULL || |
228 | (parent_pcb = parent->machine.pcb) == NULL) | |
55e303ae | 229 | return (KERN_FAILURE); |
89b3af67 A |
230 | /* |
231 | * Copy over the i386_saved_state registers | |
232 | */ | |
233 | if (cpu_mode_is64bit()) { | |
234 | if (thread_is_64bit(parent)) | |
235 | bcopy(USER_REGS64(parent), USER_REGS64(child), sizeof(x86_saved_state64_t)); | |
236 | else | |
237 | bcopy(USER_REGS32(parent), USER_REGS32(child), sizeof(x86_saved_state_compat32_t)); | |
238 | } else | |
239 | bcopy(USER_REGS32(parent), USER_REGS32(child), sizeof(x86_saved_state32_t)); | |
1c79356b | 240 | |
89b3af67 A |
241 | /* |
242 | * Check to see if parent is using floating point | |
8f6c56a5 | 243 | * and if so, copy the registers to the child |
5d5c5d0d | 244 | */ |
89b3af67 | 245 | fpu_dup_fxstate(parent, child); |
5d5c5d0d | 246 | |
89b3af67 A |
247 | #ifdef MACH_BSD |
248 | /* | |
249 | * Copy the parent's cthread id and USER_CTHREAD descriptor, if 32-bit. | |
250 | */ | |
251 | child_pcb->cthread_self = parent_pcb->cthread_self; | |
252 | if (!thread_is_64bit(parent)) | |
253 | child_pcb->cthread_desc = parent_pcb->cthread_desc; | |
254 | ||
255 | /* | |
256 | * FIXME - should a user specified LDT, TSS and V86 info | |
1c79356b A |
257 | * be duplicated as well?? - probably not. |
258 | */ | |
91447636 | 259 | // duplicate any use LDT entry that was set I think this is appropriate. |
89b3af67 A |
260 | if (parent_pcb->uldt_selector!= 0) { |
261 | child_pcb->uldt_selector = parent_pcb->uldt_selector; | |
262 | child_pcb->uldt_desc = parent_pcb->uldt_desc; | |
91447636 A |
263 | } |
264 | #endif | |
265 | ||
55e303ae | 266 | return (KERN_SUCCESS); |
1c79356b A |
267 | } |
268 | ||
269 | /* | |
270 | * FIXME - thread_set_child | |
271 | */ | |
272 | ||
91447636 | 273 | void thread_set_child(thread_t child, int pid); |
1c79356b | 274 | void |
91447636 | 275 | thread_set_child(thread_t child, int pid) |
1c79356b | 276 | { |
89b3af67 A |
277 | |
278 | if (thread_is_64bit(child)) { | |
279 | x86_saved_state64_t *iss64; | |
280 | ||
281 | iss64 = USER_REGS64(child); | |
282 | ||
283 | iss64->rax = pid; | |
284 | iss64->rdx = 1; | |
285 | iss64->isf.rflags &= ~EFL_CF; | |
286 | } else { | |
287 | x86_saved_state32_t *iss32; | |
288 | ||
289 | iss32 = USER_REGS32(child); | |
290 | ||
291 | iss32->eax = pid; | |
292 | iss32->edx = 1; | |
293 | iss32->efl &= ~EFL_CF; | |
294 | } | |
1c79356b | 295 | } |
89b3af67 A |
296 | |
297 | ||
91447636 | 298 | void thread_set_parent(thread_t parent, int pid); |
0b4e3aa0 | 299 | void |
91447636 | 300 | thread_set_parent(thread_t parent, int pid) |
0b4e3aa0 | 301 | { |
89b3af67 A |
302 | |
303 | if (thread_is_64bit(parent)) { | |
304 | x86_saved_state64_t *iss64; | |
305 | ||
306 | iss64 = USER_REGS64(parent); | |
307 | ||
308 | iss64->rax = pid; | |
309 | iss64->rdx = 0; | |
310 | iss64->isf.rflags &= ~EFL_CF; | |
311 | } else { | |
312 | x86_saved_state32_t *iss32; | |
313 | ||
314 | iss32 = USER_REGS32(parent); | |
315 | ||
316 | iss32->eax = pid; | |
317 | iss32->edx = 0; | |
318 | iss32->efl &= ~EFL_CF; | |
319 | } | |
0b4e3aa0 | 320 | } |
1c79356b A |
321 | |
322 | ||
323 | ||
1c79356b A |
324 | /* |
325 | * System Call handling code | |
326 | */ | |
327 | ||
89b3af67 | 328 | extern struct proc * i386_current_proc(void); |
91447636 A |
329 | |
330 | extern long fuword(vm_offset_t); | |
331 | ||
1c79356b | 332 | |
91447636 A |
333 | /* following implemented in bsd/dev/i386/unix_signal.c */ |
334 | int __pthread_cset(struct sysent *); | |
1c79356b | 335 | |
91447636 | 336 | void __pthread_creset(struct sysent *); |
1c79356b | 337 | |
1c79356b A |
338 | |
339 | void | |
89b3af67 | 340 | machdep_syscall(x86_saved_state_t *state) |
8f6c56a5 | 341 | { |
89b3af67 A |
342 | int args[machdep_call_count]; |
343 | int trapno; | |
344 | int nargs; | |
345 | machdep_call_t *entry; | |
346 | x86_saved_state32_t *regs; | |
347 | ||
348 | assert(is_saved_state32(state)); | |
349 | regs = saved_state32(state); | |
1c79356b | 350 | |
89b3af67 A |
351 | trapno = regs->eax; |
352 | #if DEBUG_TRACE | |
353 | kprintf("machdep_syscall(0x%08x) code=%d\n", regs, trapno); | |
354 | #endif | |
1c79356b | 355 | |
89b3af67 A |
356 | if (trapno < 0 || trapno >= machdep_call_count) { |
357 | regs->eax = (unsigned int)kern_invalid(NULL); | |
1c79356b | 358 | |
91447636 A |
359 | thread_exception_return(); |
360 | /* NOTREACHED */ | |
361 | } | |
89b3af67 A |
362 | entry = &machdep_call_table[trapno]; |
363 | nargs = entry->nargs; | |
91447636 | 364 | |
89b3af67 A |
365 | if (nargs != 0) { |
366 | if (copyin((user_addr_t) regs->uesp + sizeof (int), | |
367 | (char *) args, (nargs * sizeof (int)))) { | |
368 | regs->eax = KERN_INVALID_ADDRESS; | |
8f6c56a5 | 369 | |
89b3af67 A |
370 | thread_exception_return(); |
371 | /* NOTREACHED */ | |
372 | } | |
1c79356b | 373 | } |
89b3af67 A |
374 | switch (nargs) { |
375 | case 0: | |
376 | regs->eax = (*entry->routine.args_0)(); | |
377 | break; | |
378 | case 1: | |
379 | regs->eax = (*entry->routine.args_1)(args[0]); | |
380 | break; | |
381 | case 2: | |
382 | regs->eax = (*entry->routine.args_2)(args[0], args[1]); | |
383 | break; | |
384 | case 3: | |
385 | if (!entry->bsd_style) | |
386 | regs->eax = (*entry->routine.args_3)(args[0], args[1], args[2]); | |
387 | else { | |
388 | int error; | |
389 | int rval; | |
390 | ||
391 | error = (*entry->routine.args_bsd_3)(&rval, args[0], args[1], args[2]); | |
392 | if (error) { | |
393 | regs->eax = error; | |
394 | regs->efl |= EFL_CF; /* carry bit */ | |
395 | } else { | |
396 | regs->eax = rval; | |
397 | regs->efl &= ~EFL_CF; | |
398 | } | |
399 | } | |
400 | break; | |
401 | case 4: | |
402 | regs->eax = (*entry->routine.args_4)(args[0], args[1], args[2], args[3]); | |
403 | break; | |
1c79356b | 404 | |
89b3af67 A |
405 | default: |
406 | panic("machdep_syscall: too many args"); | |
8f6c56a5 | 407 | } |
89b3af67 A |
408 | if (current_thread()->funnel_lock) |
409 | (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); | |
8f6c56a5 | 410 | |
89b3af67 A |
411 | thread_exception_return(); |
412 | /* NOTREACHED */ | |
1c79356b A |
413 | } |
414 | ||
415 | ||
416 | void | |
89b3af67 | 417 | machdep_syscall64(x86_saved_state_t *state) |
1c79356b | 418 | { |
89b3af67 A |
419 | int trapno; |
420 | machdep_call_t *entry; | |
421 | x86_saved_state64_t *regs; | |
1c79356b | 422 | |
89b3af67 A |
423 | assert(is_saved_state64(state)); |
424 | regs = saved_state64(state); | |
1c79356b | 425 | |
89b3af67 | 426 | trapno = regs->rax & SYSCALL_NUMBER_MASK; |
1c79356b | 427 | |
89b3af67 A |
428 | if (trapno < 0 || trapno >= machdep_call_count) { |
429 | regs->rax = (unsigned int)kern_invalid(NULL); | |
1c79356b | 430 | |
89b3af67 A |
431 | thread_exception_return(); |
432 | /* NOTREACHED */ | |
1c79356b | 433 | } |
89b3af67 | 434 | entry = &machdep_call_table64[trapno]; |
1c79356b | 435 | |
89b3af67 A |
436 | switch (entry->nargs) { |
437 | case 0: | |
438 | regs->rax = (*entry->routine.args_0)(); | |
8f6c56a5 | 439 | break; |
89b3af67 A |
440 | case 1: |
441 | regs->rax = (*entry->routine.args64_1)(regs->rdi); | |
55e303ae A |
442 | break; |
443 | default: | |
89b3af67 | 444 | panic("machdep_syscall64: too many args"); |
55e303ae | 445 | } |
89b3af67 A |
446 | if (current_thread()->funnel_lock) |
447 | (void) thread_funnel_set(current_thread()->funnel_lock, FALSE); | |
8f6c56a5 | 448 | |
89b3af67 A |
449 | thread_exception_return(); |
450 | /* NOTREACHED */ | |
1c79356b A |
451 | } |
452 | ||
453 | ||
55e303ae A |
454 | kern_return_t |
455 | thread_compose_cthread_desc(unsigned int addr, pcb_t pcb) | |
456 | { | |
457 | struct real_descriptor desc; | |
55e303ae | 458 | |
91447636 A |
459 | mp_disable_preemption(); |
460 | ||
55e303ae A |
461 | desc.limit_low = 1; |
462 | desc.limit_high = 0; | |
463 | desc.base_low = addr & 0xffff; | |
464 | desc.base_med = (addr >> 16) & 0xff; | |
465 | desc.base_high = (addr >> 24) & 0xff; | |
466 | desc.access = ACC_P|ACC_PL_U|ACC_DATA_W; | |
467 | desc.granularity = SZ_32|SZ_G; | |
468 | pcb->cthread_desc = desc; | |
91447636 A |
469 | *ldt_desc_p(USER_CTHREAD) = desc; |
470 | ||
471 | mp_enable_preemption(); | |
472 | ||
55e303ae A |
473 | return(KERN_SUCCESS); |
474 | } | |
475 | ||
1c79356b | 476 | kern_return_t |
91447636 | 477 | thread_set_cthread_self(uint32_t self) |
1c79356b | 478 | { |
89b3af67 | 479 | current_thread()->machine.pcb->cthread_self = (uint64_t) self; |
1c79356b A |
480 | |
481 | return (KERN_SUCCESS); | |
482 | } | |
483 | ||
484 | kern_return_t | |
485 | thread_get_cthread_self(void) | |
486 | { | |
91447636 | 487 | return ((kern_return_t)current_thread()->machine.pcb->cthread_self); |
1c79356b A |
488 | } |
489 | ||
55e303ae | 490 | kern_return_t |
91447636 | 491 | thread_fast_set_cthread_self(uint32_t self) |
55e303ae | 492 | { |
89b3af67 A |
493 | pcb_t pcb; |
494 | x86_saved_state32_t *iss; | |
495 | ||
496 | pcb = (pcb_t)current_thread()->machine.pcb; | |
497 | thread_compose_cthread_desc(self, pcb); | |
498 | pcb->cthread_self = (uint64_t) self; /* preserve old func too */ | |
499 | iss = saved_state32(pcb->iss); | |
500 | iss->gs = USER_CTHREAD; | |
501 | ||
502 | return (USER_CTHREAD); | |
503 | } | |
504 | ||
505 | kern_return_t | |
506 | thread_fast_set_cthread_self64(uint64_t self) | |
507 | { | |
508 | pcb_t pcb; | |
509 | x86_saved_state64_t *iss; | |
510 | ||
511 | pcb = current_thread()->machine.pcb; | |
512 | ||
513 | /* check for canonical address, set 0 otherwise */ | |
514 | if (!IS_USERADDR64_CANONICAL(self)) | |
515 | self = 0ULL; | |
516 | pcb->cthread_self = self; | |
517 | current_cpu_datap()->cpu_uber.cu_user_gs_base = self; | |
518 | ||
519 | /* XXX for 64-in-32 */ | |
520 | iss = saved_state64(pcb->iss); | |
521 | iss->gs = USER_CTHREAD; | |
522 | thread_compose_cthread_desc((uint32_t) self, pcb); | |
523 | ||
524 | return (USER_CTHREAD); | |
55e303ae A |
525 | } |
526 | ||
91447636 A |
527 | /* |
528 | * thread_set_user_ldt routine is the interface for the user level | |
529 | * settable ldt entry feature. allowing a user to create arbitrary | |
530 | * ldt entries seems to be too large of a security hole, so instead | |
531 | * this mechanism is in place to allow user level processes to have | |
532 | * an ldt entry that can be used in conjunction with the FS register. | |
533 | * | |
534 | * Swapping occurs inside the pcb.c file along with initialization | |
535 | * when a thread is created. The basic functioning theory is that the | |
536 | * pcb->uldt_selector variable will contain either 0 meaning the | |
537 | * process has not set up any entry, or the selector to be used in | |
538 | * the FS register. pcb->uldt_desc contains the actual descriptor the | |
539 | * user has set up stored in machine usable ldt format. | |
540 | * | |
541 | * Currently one entry is shared by all threads (USER_SETTABLE), but | |
542 | * this could be changed in the future by changing how this routine | |
543 | * allocates the selector. There seems to be no real reason at this | |
544 | * time to have this added feature, but in the future it might be | |
545 | * needed. | |
546 | * | |
547 | * address is the linear address of the start of the data area size | |
548 | * is the size in bytes of the area flags should always be set to 0 | |
549 | * for now. in the future it could be used to set R/W permisions or | |
550 | * other functions. Currently the segment is created as a data segment | |
551 | * up to 1 megabyte in size with full read/write permisions only. | |
552 | * | |
553 | * this call returns the segment selector or -1 if any error occurs | |
554 | */ | |
555 | kern_return_t | |
556 | thread_set_user_ldt(uint32_t address, uint32_t size, uint32_t flags) | |
557 | { | |
558 | pcb_t pcb; | |
559 | struct fake_descriptor temp; | |
560 | int mycpu; | |
561 | ||
562 | if (flags != 0) | |
563 | return -1; // flags not supported | |
564 | if (size > 0xFFFFF) | |
565 | return -1; // size too big, 1 meg is the limit | |
566 | ||
567 | mp_disable_preemption(); | |
568 | mycpu = cpu_number(); | |
569 | ||
570 | // create a "fake" descriptor so we can use fix_desc() | |
571 | // to build a real one... | |
572 | // 32 bit default operation size | |
573 | // standard read/write perms for a data segment | |
574 | pcb = (pcb_t)current_thread()->machine.pcb; | |
575 | temp.offset = address; | |
576 | temp.lim_or_seg = size; | |
577 | temp.size_or_wdct = SZ_32; | |
578 | temp.access = ACC_P|ACC_PL_U|ACC_DATA_W; | |
579 | ||
580 | // turn this into a real descriptor | |
581 | fix_desc(&temp,1); | |
582 | ||
583 | // set up our data in the pcb | |
584 | pcb->uldt_desc = *(struct real_descriptor*)&temp; | |
585 | pcb->uldt_selector = USER_SETTABLE; // set the selector value | |
586 | ||
587 | // now set it up in the current table... | |
588 | *ldt_desc_p(USER_SETTABLE) = *(struct real_descriptor*)&temp; | |
589 | ||
590 | mp_enable_preemption(); | |
591 | ||
592 | return USER_SETTABLE; | |
593 | } | |
c0fea474 | 594 | |
89b3af67 | 595 | #endif /* MACH_BSD */ |
5d5c5d0d | 596 | |
8ad349bb | 597 | |
89b3af67 | 598 | typedef kern_return_t (*mach_call_t)(void *); |
5d5c5d0d | 599 | |
89b3af67 A |
600 | struct mach_call_args { |
601 | syscall_arg_t arg1; | |
602 | syscall_arg_t arg2; | |
603 | syscall_arg_t arg3; | |
604 | syscall_arg_t arg4; | |
605 | syscall_arg_t arg5; | |
606 | syscall_arg_t arg6; | |
607 | syscall_arg_t arg7; | |
608 | syscall_arg_t arg8; | |
609 | syscall_arg_t arg9; | |
610 | }; | |
5d5c5d0d | 611 | |
5d5c5d0d | 612 | |
89b3af67 A |
613 | static kern_return_t |
614 | mach_call_arg_munger32(uint32_t sp, int nargs, int call_number, struct mach_call_args *args); | |
5d5c5d0d | 615 | |
8f6c56a5 | 616 | |
89b3af67 A |
617 | static kern_return_t |
618 | mach_call_arg_munger32(uint32_t sp, int nargs, int call_number, struct mach_call_args *args) | |
619 | { | |
620 | unsigned int args32[9]; | |
5d5c5d0d | 621 | |
89b3af67 A |
622 | if (copyin((user_addr_t)(sp + sizeof(int)), (char *)args32, nargs * sizeof (int))) |
623 | return KERN_INVALID_ARGUMENT; | |
5d5c5d0d | 624 | |
89b3af67 A |
625 | switch (nargs) { |
626 | case 9: args->arg9 = args32[8]; | |
627 | case 8: args->arg8 = args32[7]; | |
628 | case 7: args->arg7 = args32[6]; | |
629 | case 6: args->arg6 = args32[5]; | |
630 | case 5: args->arg5 = args32[4]; | |
631 | case 4: args->arg4 = args32[3]; | |
632 | case 3: args->arg3 = args32[2]; | |
633 | case 2: args->arg2 = args32[1]; | |
634 | case 1: args->arg1 = args32[0]; | |
635 | } | |
636 | if (call_number == 90) { | |
637 | /* munge_l for mach_wait_until_trap() */ | |
638 | args->arg1 = (((uint64_t)(args32[0])) | ((((uint64_t)(args32[1]))<<32))); | |
639 | } | |
640 | if (call_number == 93) { | |
641 | /* munge_wl for mk_timer_arm_trap() */ | |
642 | args->arg2 = (((uint64_t)(args32[1])) | ((((uint64_t)(args32[2]))<<32))); | |
643 | } | |
5d5c5d0d | 644 | |
89b3af67 | 645 | return KERN_SUCCESS; |
8f6c56a5 | 646 | } |
5d5c5d0d | 647 | |
8f6c56a5 | 648 | |
89b3af67 A |
649 | __private_extern__ void |
650 | mach_call_munger(x86_saved_state_t *state); | |
651 | ||
5d5c5d0d A |
652 | |
653 | __private_extern__ | |
89b3af67 A |
654 | void |
655 | mach_call_munger(x86_saved_state_t *state) | |
5d5c5d0d | 656 | { |
5d5c5d0d | 657 | int argc; |
89b3af67 | 658 | int call_number; |
5d5c5d0d | 659 | mach_call_t mach_call; |
8f6c56a5 A |
660 | kern_return_t retval; |
661 | struct mach_call_args args = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | |
89b3af67 A |
662 | x86_saved_state32_t *regs; |
663 | ||
664 | assert(is_saved_state32(state)); | |
665 | regs = saved_state32(state); | |
666 | ||
667 | call_number = -(regs->eax); | |
668 | #if DEBUG_TRACE | |
669 | kprintf("mach_call_munger(0x%08x) code=%d\n", regs, call_number); | |
670 | #endif | |
671 | ||
672 | if (call_number < 0 || call_number >= mach_trap_count) { | |
673 | i386_exception(EXC_SYSCALL, call_number, 1); | |
674 | /* NOTREACHED */ | |
675 | } | |
676 | mach_call = (mach_call_t)mach_trap_table[call_number].mach_trap_function; | |
8ad349bb | 677 | |
89b3af67 A |
678 | if (mach_call == (mach_call_t)kern_invalid) { |
679 | i386_exception(EXC_SYSCALL, call_number, 1); | |
680 | /* NOTREACHED */ | |
681 | } | |
5d5c5d0d | 682 | argc = mach_trap_table[call_number].mach_trap_arg_count; |
89b3af67 A |
683 | |
684 | if (argc) { | |
685 | retval = mach_call_arg_munger32(regs->uesp, argc, call_number, &args); | |
686 | ||
687 | if (retval != KERN_SUCCESS) { | |
688 | regs->eax = retval; | |
689 | ||
690 | thread_exception_return(); | |
691 | /* NOTREACHED */ | |
692 | } | |
5d5c5d0d | 693 | } |
89b3af67 A |
694 | KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC, (call_number)) | DBG_FUNC_START, |
695 | (int) args.arg1, (int) args.arg2, (int) args.arg3, (int) args.arg4, 0); | |
5d5c5d0d | 696 | |
89b3af67 A |
697 | retval = mach_call(&args); |
698 | ||
699 | KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC,(call_number)) | DBG_FUNC_END, | |
700 | retval, 0, 0, 0, 0); | |
701 | regs->eax = retval; | |
702 | ||
703 | thread_exception_return(); | |
704 | /* NOTREACHED */ | |
705 | } | |
706 | ||
707 | ||
708 | ||
709 | __private_extern__ void | |
710 | mach_call_munger64(x86_saved_state_t *state); | |
711 | ||
712 | ||
713 | __private_extern__ | |
714 | void | |
715 | mach_call_munger64(x86_saved_state_t *state) | |
716 | { | |
717 | int call_number; | |
718 | int argc; | |
719 | mach_call_t mach_call; | |
720 | x86_saved_state64_t *regs; | |
721 | ||
722 | assert(is_saved_state64(state)); | |
723 | regs = saved_state64(state); | |
724 | ||
725 | call_number = regs->rax & SYSCALL_NUMBER_MASK; | |
726 | ||
8f6c56a5 | 727 | KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC, (call_number)) | DBG_FUNC_START, |
89b3af67 | 728 | (int) regs->rdi, (int) regs->rsi, (int) regs->rdx, (int) regs->r10, 0); |
8f6c56a5 | 729 | |
89b3af67 A |
730 | if (call_number < 0 || call_number >= mach_trap_count) { |
731 | i386_exception(EXC_SYSCALL, regs->rax, 1); | |
732 | /* NOTREACHED */ | |
733 | } | |
8f6c56a5 | 734 | mach_call = (mach_call_t)mach_trap_table[call_number].mach_trap_function; |
8f6c56a5 | 735 | |
89b3af67 A |
736 | if (mach_call == (mach_call_t)kern_invalid) { |
737 | i386_exception(EXC_SYSCALL, regs->rax, 1); | |
738 | /* NOTREACHED */ | |
739 | } | |
740 | argc = mach_trap_table[call_number].mach_trap_arg_count; | |
741 | ||
742 | if (argc > 6) { | |
743 | int copyin_count; | |
744 | ||
745 | copyin_count = (argc - 6) * sizeof(uint64_t); | |
746 | ||
747 | if (copyin((user_addr_t)(regs->isf.rsp + sizeof(user_addr_t)), (char *)®s->v_arg6, copyin_count)) { | |
748 | regs->rax = KERN_INVALID_ARGUMENT; | |
749 | ||
750 | thread_exception_return(); | |
751 | /* NOTREACHED */ | |
752 | } | |
753 | } | |
754 | regs->rax = (uint64_t)mach_call((void *)(®s->rdi)); | |
755 | ||
91447636 | 756 | KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC,(call_number)) | DBG_FUNC_END, |
89b3af67 | 757 | (int)regs->rax, 0, 0, 0, 0); |
91447636 | 758 | |
89b3af67 A |
759 | thread_exception_return(); |
760 | /* NOTREACHED */ | |
91447636 A |
761 | } |
762 | ||
89b3af67 A |
763 | |
764 | ||
91447636 A |
765 | /* |
766 | * thread_setuserstack: | |
767 | * | |
768 | * Sets the user stack pointer into the machine | |
769 | * dependent thread state info. | |
770 | */ | |
771 | void | |
772 | thread_setuserstack( | |
773 | thread_t thread, | |
774 | mach_vm_address_t user_stack) | |
775 | { | |
89b3af67 A |
776 | if (thread_is_64bit(thread)) { |
777 | x86_saved_state64_t *iss64; | |
778 | ||
779 | iss64 = USER_REGS64(thread); | |
5d5c5d0d | 780 | |
89b3af67 A |
781 | iss64->isf.rsp = (uint64_t)user_stack; |
782 | } else { | |
783 | x86_saved_state32_t *iss32; | |
784 | ||
785 | iss32 = USER_REGS32(thread); | |
786 | ||
787 | iss32->uesp = CAST_DOWN(unsigned int, user_stack); | |
788 | } | |
91447636 A |
789 | } |
790 | ||
791 | /* | |
792 | * thread_adjuserstack: | |
793 | * | |
794 | * Returns the adjusted user stack pointer from the machine | |
795 | * dependent thread state info. Used for small (<2G) deltas. | |
796 | */ | |
797 | uint64_t | |
798 | thread_adjuserstack( | |
799 | thread_t thread, | |
800 | int adjust) | |
801 | { | |
89b3af67 A |
802 | if (thread_is_64bit(thread)) { |
803 | x86_saved_state64_t *iss64; | |
5d5c5d0d | 804 | |
89b3af67 A |
805 | iss64 = USER_REGS64(thread); |
806 | ||
807 | iss64->isf.rsp += adjust; | |
808 | ||
809 | return iss64->isf.rsp; | |
810 | } else { | |
811 | x86_saved_state32_t *iss32; | |
812 | ||
813 | iss32 = USER_REGS32(thread); | |
814 | ||
815 | iss32->uesp += adjust; | |
816 | ||
817 | return CAST_USER_ADDR_T(iss32->uesp); | |
818 | } | |
91447636 A |
819 | } |
820 | ||
821 | /* | |
822 | * thread_setentrypoint: | |
823 | * | |
824 | * Sets the user PC into the machine | |
825 | * dependent thread state info. | |
826 | */ | |
827 | void | |
89b3af67 | 828 | thread_setentrypoint(thread_t thread, mach_vm_address_t entry) |
5d5c5d0d | 829 | { |
89b3af67 A |
830 | if (thread_is_64bit(thread)) { |
831 | x86_saved_state64_t *iss64; | |
5d5c5d0d | 832 | |
89b3af67 A |
833 | iss64 = USER_REGS64(thread); |
834 | ||
835 | iss64->isf.rip = (uint64_t)entry; | |
836 | } else { | |
837 | x86_saved_state32_t *iss32; | |
838 | ||
839 | iss32 = USER_REGS32(thread); | |
840 | ||
841 | iss32->eip = CAST_DOWN(unsigned int, entry); | |
842 | } | |
843 | } | |
844 | ||
845 | ||
846 | void | |
847 | thread_setsinglestep(thread_t thread, int on) | |
848 | { | |
849 | if (thread_is_64bit(thread)) { | |
850 | x86_saved_state64_t *iss64; | |
851 | ||
852 | iss64 = USER_REGS64(thread); | |
853 | ||
854 | if (on) | |
855 | iss64->isf.rflags |= EFL_TF; | |
856 | else | |
857 | iss64->isf.rflags &= ~EFL_TF; | |
858 | } else { | |
859 | x86_saved_state32_t *iss32; | |
860 | ||
861 | iss32 = USER_REGS32(thread); | |
862 | ||
863 | if (on) | |
864 | iss32->efl |= EFL_TF; | |
865 | else | |
866 | iss32->efl &= ~EFL_TF; | |
867 | } | |
868 | } | |
869 | ||
870 | ||
871 | ||
872 | /* XXX this should be a struct savearea so that CHUD will work better on x86 */ | |
873 | void * | |
874 | find_user_regs( | |
875 | thread_t thread) | |
876 | { | |
877 | return USER_STATE(thread); | |
878 | } | |
91447636 | 879 |