| 1 | /* |
| 2 | * Copyright (c) 2010-2012 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_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 | __unused boolean_t is_corpse |
| 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 (thread_is_64bit_addr(parent)) |
| 90 | bcopy(USER_REGS64(parent), USER_REGS64(child), sizeof(x86_saved_state64_t)); |
| 91 | else |
| 92 | bcopy(USER_REGS32(parent), USER_REGS32(child), sizeof(x86_saved_state32_t)); |
| 93 | |
| 94 | /* |
| 95 | * Check to see if parent is using floating point |
| 96 | * and if so, copy the registers to the child |
| 97 | */ |
| 98 | fpu_dup_fxstate(parent, child); |
| 99 | |
| 100 | #ifdef MACH_BSD |
| 101 | /* |
| 102 | * Copy the parent's cthread id and USER_CTHREAD descriptor, if 32-bit. |
| 103 | */ |
| 104 | child_pcb->cthread_self = parent_pcb->cthread_self; |
| 105 | if (!thread_is_64bit_addr(parent)) |
| 106 | child_pcb->cthread_desc = parent_pcb->cthread_desc; |
| 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. |
| 113 | if (parent_pcb->uldt_selector!= 0) { |
| 114 | child_pcb->uldt_selector = parent_pcb->uldt_selector; |
| 115 | child_pcb->uldt_desc = parent_pcb->uldt_desc; |
| 116 | } |
| 117 | #endif |
| 118 | |
| 119 | return (KERN_SUCCESS); |
| 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 | |
| 129 | if (thread_is_64bit_addr(parent)) { |
| 130 | x86_saved_state64_t *iss64; |
| 131 | |
| 132 | iss64 = USER_REGS64(parent); |
| 133 | |
| 134 | iss64->rax = pid; |
| 135 | iss64->rdx = 0; |
| 136 | iss64->isf.rflags &= ~EFL_CF; |
| 137 | } else { |
| 138 | x86_saved_state32_t *iss32; |
| 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 |
| 153 | * |
| 154 | * Returns: 0 Success |
| 155 | * !0 Not success |
| 156 | */ |
| 157 | kern_return_t |
| 158 | thread_fast_set_cthread_self(uint32_t self) |
| 159 | { |
| 160 | machine_thread_set_tsd_base(current_thread(), self); |
| 161 | return (USER_CTHREAD); /* N.B.: not a kern_return_t! */ |
| 162 | } |
| 163 | |
| 164 | /* |
| 165 | * thread_fast_set_cthread_self64: Sets the machine kernel thread ID of the |
| 166 | * current thread to the given thread ID; fast version for 64-bit processes |
| 167 | * |
| 168 | * Parameters: self Thread ID |
| 169 | * |
| 170 | * Returns: 0 Success |
| 171 | * !0 Not success |
| 172 | */ |
| 173 | kern_return_t |
| 174 | thread_fast_set_cthread_self64(uint64_t self) |
| 175 | { |
| 176 | machine_thread_set_tsd_base(current_thread(), self); |
| 177 | return (USER_CTHREAD); /* N.B.: not a kern_return_t! */ |
| 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 | |
| 214 | if (flags != 0) |
| 215 | return -1; // flags not supported |
| 216 | if (size > 0xFFFFF) |
| 217 | return -1; // size too big, 1 meg is the limit |
| 218 | |
| 219 | mp_disable_preemption(); |
| 220 | |
| 221 | // create a "fake" descriptor so we can use fix_desc() |
| 222 | // to build a real one... |
| 223 | // 32 bit default operation size |
| 224 | // standard read/write perms for a data segment |
| 225 | pcb = THREAD_TO_PCB(current_thread()); |
| 226 | temp.offset = address; |
| 227 | temp.lim_or_seg = size; |
| 228 | temp.size_or_wdct = SZ_32; |
| 229 | temp.access = ACC_P|ACC_PL_U|ACC_DATA_W; |
| 230 | |
| 231 | // turn this into a real descriptor |
| 232 | fix_desc(&temp,1); |
| 233 | |
| 234 | // set up our data in the pcb |
| 235 | pcb->uldt_desc = *(struct real_descriptor*)&temp; |
| 236 | pcb->uldt_selector = USER_SETTABLE; // set the selector value |
| 237 | |
| 238 | // now set it up in the current table... |
| 239 | *ldt_desc_p(USER_SETTABLE) = *(struct real_descriptor*)&temp; |
| 240 | |
| 241 | mp_enable_preemption(); |
| 242 | |
| 243 | return USER_SETTABLE; |
| 244 | } |
| 245 | |