| 1 | /* |
| 2 | * Copyright (c) 2000-2016 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 | /* |
| 29 | * @OSF_COPYRIGHT@ |
| 30 | */ |
| 31 | /* |
| 32 | * Mach Operating System |
| 33 | * Copyright (c) 1991,1990 Carnegie Mellon University |
| 34 | * All Rights Reserved. |
| 35 | * |
| 36 | * Permission to use, copy, modify and distribute this software and its |
| 37 | * documentation is hereby granted, provided that both the copyright |
| 38 | * notice and this permission notice appear in all copies of the |
| 39 | * software, derivative works or modified versions, and any portions |
| 40 | * thereof, and that both notices appear in supporting documentation. |
| 41 | * |
| 42 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" |
| 43 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR |
| 44 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. |
| 45 | * |
| 46 | * Carnegie Mellon requests users of this software to return to |
| 47 | * |
| 48 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU |
| 49 | * School of Computer Science |
| 50 | * Carnegie Mellon University |
| 51 | * Pittsburgh PA 15213-3890 |
| 52 | * |
| 53 | * any improvements or extensions that they make and grant Carnegie Mellon |
| 54 | * the rights to redistribute these changes. |
| 55 | */ |
| 56 | |
| 57 | #include <kern/task.h> |
| 58 | #include <kern/thread.h> |
| 59 | #include <i386/misc_protos.h> |
| 60 | #include <i386/fpu.h> |
| 61 | |
| 62 | #if HYPERVISOR |
| 63 | #include <kern/hv_support.h> |
| 64 | #endif |
| 65 | |
| 66 | extern zone_t ids_zone; |
| 67 | |
| 68 | kern_return_t |
| 69 | machine_task_set_state( |
| 70 | task_t task, |
| 71 | int flavor, |
| 72 | thread_state_t state, |
| 73 | mach_msg_type_number_t state_count) |
| 74 | { |
| 75 | switch (flavor) { |
| 76 | case x86_DEBUG_STATE32: |
| 77 | { |
| 78 | x86_debug_state32_t *tstate = (x86_debug_state32_t*) state; |
| 79 | if ((task_has_64Bit_addr(task)) || |
| 80 | (state_count != x86_DEBUG_STATE32_COUNT) || |
| 81 | (!debug_state_is_valid32(tstate))) { |
| 82 | return KERN_INVALID_ARGUMENT; |
| 83 | } |
| 84 | |
| 85 | if (task->task_debug == NULL) { |
| 86 | task->task_debug = zalloc(ids_zone); |
| 87 | } |
| 88 | |
| 89 | copy_debug_state32(tstate, (x86_debug_state32_t*) task->task_debug, FALSE); |
| 90 | |
| 91 | return KERN_SUCCESS; |
| 92 | } |
| 93 | case x86_DEBUG_STATE64: |
| 94 | { |
| 95 | x86_debug_state64_t *tstate = (x86_debug_state64_t*) state; |
| 96 | |
| 97 | if ((!task_has_64Bit_addr(task)) || |
| 98 | (state_count != x86_DEBUG_STATE64_COUNT) || |
| 99 | (!debug_state_is_valid64(tstate))) { |
| 100 | return KERN_INVALID_ARGUMENT; |
| 101 | } |
| 102 | |
| 103 | if (task->task_debug == NULL) { |
| 104 | task->task_debug = zalloc(ids_zone); |
| 105 | } |
| 106 | |
| 107 | copy_debug_state64(tstate, (x86_debug_state64_t*) task->task_debug, FALSE); |
| 108 | |
| 109 | return KERN_SUCCESS; |
| 110 | } |
| 111 | case x86_DEBUG_STATE: |
| 112 | { |
| 113 | x86_debug_state_t *tstate = (x86_debug_state_t*) state; |
| 114 | |
| 115 | if (state_count != x86_DEBUG_STATE_COUNT) { |
| 116 | return KERN_INVALID_ARGUMENT; |
| 117 | } |
| 118 | |
| 119 | if ((tstate->dsh.flavor == x86_DEBUG_STATE32) && |
| 120 | (tstate->dsh.count == x86_DEBUG_STATE32_COUNT) && |
| 121 | (!task_has_64Bit_addr(task)) && |
| 122 | debug_state_is_valid32(&tstate->uds.ds32)) { |
| 123 | |
| 124 | if (task->task_debug == NULL) { |
| 125 | task->task_debug = zalloc(ids_zone); |
| 126 | } |
| 127 | |
| 128 | copy_debug_state32(&tstate->uds.ds32, (x86_debug_state32_t*) task->task_debug, FALSE); |
| 129 | return KERN_SUCCESS; |
| 130 | |
| 131 | } else if ((tstate->dsh.flavor == x86_DEBUG_STATE64) && |
| 132 | (tstate->dsh.count == x86_DEBUG_STATE64_COUNT) && |
| 133 | task_has_64Bit_addr(task) && |
| 134 | debug_state_is_valid64(&tstate->uds.ds64)) { |
| 135 | |
| 136 | if (task->task_debug == NULL) { |
| 137 | task->task_debug = zalloc(ids_zone); |
| 138 | } |
| 139 | |
| 140 | copy_debug_state64(&tstate->uds.ds64, (x86_debug_state64_t*) task->task_debug, FALSE); |
| 141 | return KERN_SUCCESS; |
| 142 | } else { |
| 143 | return KERN_INVALID_ARGUMENT; |
| 144 | } |
| 145 | } |
| 146 | default: |
| 147 | { |
| 148 | return KERN_INVALID_ARGUMENT; |
| 149 | } |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | kern_return_t |
| 154 | machine_task_get_state(task_t task, |
| 155 | int flavor, |
| 156 | thread_state_t state, |
| 157 | mach_msg_type_number_t *state_count) |
| 158 | { |
| 159 | switch (flavor) { |
| 160 | case x86_DEBUG_STATE32: |
| 161 | { |
| 162 | x86_debug_state32_t *tstate = (x86_debug_state32_t*) state; |
| 163 | |
| 164 | if ((task_has_64Bit_addr(task)) || (*state_count != x86_DEBUG_STATE32_COUNT)) { |
| 165 | return KERN_INVALID_ARGUMENT; |
| 166 | } |
| 167 | |
| 168 | if (task->task_debug == NULL) { |
| 169 | bzero(state, sizeof(*tstate)); |
| 170 | } else { |
| 171 | copy_debug_state32((x86_debug_state32_t*) task->task_debug, tstate, TRUE); |
| 172 | } |
| 173 | |
| 174 | return KERN_SUCCESS; |
| 175 | } |
| 176 | case x86_DEBUG_STATE64: |
| 177 | { |
| 178 | x86_debug_state64_t *tstate = (x86_debug_state64_t*) state; |
| 179 | |
| 180 | if ((!task_has_64Bit_addr(task)) || (*state_count != x86_DEBUG_STATE64_COUNT)) { |
| 181 | return KERN_INVALID_ARGUMENT; |
| 182 | } |
| 183 | |
| 184 | if (task->task_debug == NULL) { |
| 185 | bzero(state, sizeof(*tstate)); |
| 186 | } else { |
| 187 | copy_debug_state64((x86_debug_state64_t*) task->task_debug, tstate, TRUE); |
| 188 | } |
| 189 | |
| 190 | return KERN_SUCCESS; |
| 191 | } |
| 192 | case x86_DEBUG_STATE: |
| 193 | { |
| 194 | x86_debug_state_t *tstate = (x86_debug_state_t*)state; |
| 195 | |
| 196 | if (*state_count != x86_DEBUG_STATE_COUNT) |
| 197 | return(KERN_INVALID_ARGUMENT); |
| 198 | |
| 199 | if (task_has_64Bit_addr(task)) { |
| 200 | tstate->dsh.flavor = x86_DEBUG_STATE64; |
| 201 | tstate->dsh.count = x86_DEBUG_STATE64_COUNT; |
| 202 | |
| 203 | if (task->task_debug == NULL) { |
| 204 | bzero(&tstate->uds.ds64, sizeof(tstate->uds.ds64)); |
| 205 | } else { |
| 206 | copy_debug_state64((x86_debug_state64_t*)task->task_debug, &tstate->uds.ds64, TRUE); |
| 207 | } |
| 208 | } else { |
| 209 | tstate->dsh.flavor = x86_DEBUG_STATE32; |
| 210 | tstate->dsh.count = x86_DEBUG_STATE32_COUNT; |
| 211 | |
| 212 | if (task->task_debug == NULL) { |
| 213 | bzero(&tstate->uds.ds32, sizeof(tstate->uds.ds32)); |
| 214 | } else { |
| 215 | copy_debug_state32((x86_debug_state32_t*)task->task_debug, &tstate->uds.ds32, TRUE); |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | return KERN_SUCCESS; |
| 220 | } |
| 221 | default: |
| 222 | { |
| 223 | return KERN_INVALID_ARGUMENT; |
| 224 | } |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | /* |
| 229 | * This is called when a task is terminated, and also on exec(). |
| 230 | * Clear machine-dependent state that is stored on the task. |
| 231 | */ |
| 232 | void |
| 233 | machine_task_terminate(task_t task) |
| 234 | { |
| 235 | if (task) { |
| 236 | user_ldt_t user_ldt; |
| 237 | void *task_debug; |
| 238 | |
| 239 | #if HYPERVISOR |
| 240 | if (task->hv_task_target) { |
| 241 | hv_callbacks.task_destroy(task->hv_task_target); |
| 242 | task->hv_task_target = NULL; |
| 243 | } |
| 244 | #endif |
| 245 | |
| 246 | user_ldt = task->i386_ldt; |
| 247 | if (user_ldt != 0) { |
| 248 | task->i386_ldt = 0; |
| 249 | user_ldt_free(user_ldt); |
| 250 | } |
| 251 | |
| 252 | task_debug = task->task_debug; |
| 253 | if (task_debug != NULL) { |
| 254 | task->task_debug = NULL; |
| 255 | zfree(ids_zone, task_debug); |
| 256 | } |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | /* |
| 261 | * Set initial default state on a thread as stored in the MACHINE_TASK data. |
| 262 | * Note: currently only debug state is supported. |
| 263 | */ |
| 264 | kern_return_t |
| 265 | machine_thread_inherit_taskwide( |
| 266 | thread_t thread, |
| 267 | task_t parent_task) |
| 268 | { |
| 269 | if (parent_task->task_debug) { |
| 270 | int flavor; |
| 271 | mach_msg_type_number_t count; |
| 272 | |
| 273 | if (task_has_64Bit_addr(parent_task)) { |
| 274 | flavor = x86_DEBUG_STATE64; |
| 275 | count = x86_DEBUG_STATE64_COUNT; |
| 276 | } else { |
| 277 | flavor = x86_DEBUG_STATE32; |
| 278 | count = x86_DEBUG_STATE32_COUNT; |
| 279 | } |
| 280 | |
| 281 | return machine_thread_set_state(thread, flavor, parent_task->task_debug, count); |
| 282 | } |
| 283 | |
| 284 | return KERN_SUCCESS; |
| 285 | } |
| 286 | |
| 287 | void |
| 288 | machine_task_init(task_t new_task, |
| 289 | task_t parent_task, |
| 290 | boolean_t inherit_memory) |
| 291 | { |
| 292 | new_task->uexc_range_start = 0; |
| 293 | new_task->uexc_range_size = 0; |
| 294 | new_task->uexc_handler = 0; |
| 295 | |
| 296 | new_task->i386_ldt = 0; |
| 297 | |
| 298 | if (parent_task != TASK_NULL) { |
| 299 | if (inherit_memory && parent_task->i386_ldt) |
| 300 | new_task->i386_ldt = user_ldt_copy(parent_task->i386_ldt); |
| 301 | new_task->xstate = parent_task->xstate; |
| 302 | } else { |
| 303 | assert(fpu_default != UNDEFINED); |
| 304 | new_task->xstate = fpu_default; |
| 305 | } |
| 306 | } |
| 307 | |