1/*
2 * Copyright (c) 2000-2008 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
61extern zone_t ids_zone;
62
63kern_return_t
64machine_task_set_state(
65		task_t task,
66		int flavor,
67		thread_state_t state,
68		mach_msg_type_number_t state_count)
69{
70	switch (flavor) {
71		case x86_DEBUG_STATE32:
72		{
73			x86_debug_state32_t *tstate = (x86_debug_state32_t*) state;
74			if ((task_has_64BitAddr(task)) ||
75					(state_count != x86_DEBUG_STATE32_COUNT) ||
76					(!debug_state_is_valid32(tstate))) {
77				return KERN_INVALID_ARGUMENT;
78			}
79
80			if (task->task_debug == NULL) {
81				task->task_debug = zalloc(ids_zone);
82			}
83
84			copy_debug_state32(tstate, (x86_debug_state32_t*) task->task_debug, FALSE);
85
86			return KERN_SUCCESS;
87			break;
88		}
89		case x86_DEBUG_STATE64:
90		{
91			x86_debug_state64_t *tstate = (x86_debug_state64_t*) state;
92
93			if ((!task_has_64BitAddr(task)) ||
94					(state_count != x86_DEBUG_STATE64_COUNT) ||
95					(!debug_state_is_valid64(tstate))) {
96				return KERN_INVALID_ARGUMENT;
97			}
98
99			if (task->task_debug == NULL) {
100				task->task_debug = zalloc(ids_zone);
101			}
102
103			copy_debug_state64(tstate, (x86_debug_state64_t*) task->task_debug, FALSE);
104
105			return KERN_SUCCESS;
106			break;
107		}
108		case x86_DEBUG_STATE:
109		{
110			x86_debug_state_t *tstate = (x86_debug_state_t*) state;
111
112			if (state_count != x86_DEBUG_STATE_COUNT) {
113				return KERN_INVALID_ARGUMENT;
114			}
115
116			if ((tstate->dsh.flavor == x86_DEBUG_STATE32) &&
117					(tstate->dsh.count == x86_DEBUG_STATE32_COUNT) &&
118					(!task_has_64BitAddr(task)) &&
119					debug_state_is_valid32(&tstate->uds.ds32)) {
120
121				if (task->task_debug == NULL) {
122					task->task_debug = zalloc(ids_zone);
123				}
124
125				copy_debug_state32(&tstate->uds.ds32, (x86_debug_state32_t*) task->task_debug, FALSE);
126				return KERN_SUCCESS;
127
128			} else if ((tstate->dsh.flavor == x86_DEBUG_STATE64) &&
129					(tstate->dsh.count == x86_DEBUG_STATE64_COUNT) &&
130					task_has_64BitAddr(task) &&
131					debug_state_is_valid64(&tstate->uds.ds64)) {
132
133				if (task->task_debug == NULL) {
134					task->task_debug = zalloc(ids_zone);
135				}
136
137				copy_debug_state64(&tstate->uds.ds64, (x86_debug_state64_t*) task->task_debug, FALSE);
138				return KERN_SUCCESS;
139			} else {
140				return KERN_INVALID_ARGUMENT;
141			}
142
143			break;
144		}
145		default:
146		{
147			return KERN_INVALID_ARGUMENT;
148			break;
149		}
150	}
151}
152
153kern_return_t
154machine_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_64BitAddr(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			break;
176		}
177		case x86_DEBUG_STATE64:
178		{
179			x86_debug_state64_t *tstate = (x86_debug_state64_t*) state;
180
181			if ((!task_has_64BitAddr(task)) || (*state_count != x86_DEBUG_STATE64_COUNT)) {
182				return KERN_INVALID_ARGUMENT;
183			}
184
185			if (task->task_debug == NULL) {
186				bzero(state, sizeof(*tstate));
187			} else {
188				copy_debug_state64((x86_debug_state64_t*) task->task_debug, tstate, TRUE);
189			}
190
191			return KERN_SUCCESS;
192			break;
193		}
194		case x86_DEBUG_STATE:
195		{
196			x86_debug_state_t   *tstate = (x86_debug_state_t*)state;
197
198			if (*state_count != x86_DEBUG_STATE_COUNT)
199				return(KERN_INVALID_ARGUMENT);
200
201			if (task_has_64BitAddr(task)) {
202				tstate->dsh.flavor = x86_DEBUG_STATE64;
203				tstate->dsh.count  = x86_DEBUG_STATE64_COUNT;
204
205				if (task->task_debug == NULL) {
206					bzero(&tstate->uds.ds64, sizeof(tstate->uds.ds64));
207				} else {
208					copy_debug_state64((x86_debug_state64_t*)task->task_debug, &tstate->uds.ds64, TRUE);
209				}
210			} else {
211				tstate->dsh.flavor = x86_DEBUG_STATE32;
212				tstate->dsh.count  = x86_DEBUG_STATE32_COUNT;
213
214				if (task->task_debug == NULL) {
215					bzero(&tstate->uds.ds32, sizeof(tstate->uds.ds32));
216				} else {
217					copy_debug_state32((x86_debug_state32_t*)task->task_debug, &tstate->uds.ds32, TRUE);
218				}
219			}
220
221			return KERN_SUCCESS;
222			break;
223		}
224		default:
225		{
226			return KERN_INVALID_ARGUMENT;
227			break;
228		}
229	}
230}
231
232/*
233 * This is called when a task is terminated, and also on exec().
234 * Clear machine-dependent state that is stored on the task.
235 */
236void
237machine_task_terminate(task_t task)
238{
239	if (task) {
240		user_ldt_t user_ldt;
241		void *task_debug;
242
243		user_ldt = task->i386_ldt;
244		if (user_ldt != 0) {
245			task->i386_ldt = 0;
246			user_ldt_free(user_ldt);
247		}
248
249		task_debug = task->task_debug;
250		if (task_debug != NULL) {
251			task->task_debug = NULL;
252			zfree(ids_zone, task_debug);
253		}
254	}
255}
256
257/*
258 * Set initial default state on a thread as stored in the MACHINE_TASK data.
259 * Note: currently only debug state is supported.
260 */
261kern_return_t
262machine_thread_inherit_taskwide(
263				thread_t thread,
264				task_t parent_task)
265{
266	if (parent_task->task_debug) {
267		int flavor;
268		mach_msg_type_number_t count;
269
270		if (task_has_64BitAddr(parent_task)) {
271			flavor = x86_DEBUG_STATE64;
272			count = x86_DEBUG_STATE64_COUNT;
273		} else {
274			flavor = x86_DEBUG_STATE32;
275			count = x86_DEBUG_STATE32_COUNT;
276		}
277
278		return machine_thread_set_state(thread, flavor, parent_task->task_debug, count);
279	}
280
281	return KERN_SUCCESS;
282}
283