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 */ 76kern_return_t 77machine_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 125void thread_set_parent(thread_t parent, int pid); 126 127void 128thread_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 */ 160kern_return_t 161thread_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 */ 196kern_return_t 197thread_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 */ 247kern_return_t 248thread_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} 284