]>
Commit | Line | Data |
---|---|---|
5ba3f43e | 1 | /* |
cb323159 | 2 | * Copyright (c) 2019 Apple Inc. All rights reserved. |
5ba3f43e A |
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 | ||
0a7de745 | 29 | #ifdef MACH_BSD |
5ba3f43e A |
30 | #include <mach_debug.h> |
31 | #include <mach_ldebug.h> | |
32 | ||
33 | #include <mach/kern_return.h> | |
34 | #include <mach/mach_traps.h> | |
35 | #include <mach/vm_param.h> | |
36 | ||
5ba3f43e A |
37 | #include <kern/cpu_data.h> |
38 | #include <arm/cpu_data_internal.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/spl.h> | |
46 | #include <kern/syscall_sw.h> | |
47 | #include <ipc/ipc_port.h> | |
48 | #include <vm/vm_kern.h> | |
49 | #include <mach/thread_status.h> | |
50 | #include <vm/pmap.h> | |
51 | ||
52 | #include <sys/kdebug.h> | |
53 | ||
54 | #include <sys/syscall.h> | |
55 | ||
f427ee49 A |
56 | #if CONFIG_MACF |
57 | #include <security/mac_mach_internal.h> | |
58 | #endif | |
59 | ||
5ba3f43e | 60 | extern void throttle_lowpri_io(int); |
f427ee49 | 61 | extern arm_debug_state64_t *find_or_allocate_debug_state64(thread_t thread); |
5ba3f43e A |
62 | void mach_syscall(struct arm_saved_state*); |
63 | typedef kern_return_t (*mach_call_t)(void *); | |
64 | ||
65 | struct mach_call_args { | |
66 | syscall_arg_t arg1; | |
67 | syscall_arg_t arg2; | |
68 | syscall_arg_t arg3; | |
69 | syscall_arg_t arg4; | |
70 | syscall_arg_t arg5; | |
71 | syscall_arg_t arg6; | |
72 | syscall_arg_t arg7; | |
73 | syscall_arg_t arg8; | |
74 | syscall_arg_t arg9; | |
75 | }; | |
76 | ||
77 | static void | |
0a7de745 | 78 | arm_set_mach_syscall_ret(struct arm_saved_state *state, int retval) |
5ba3f43e A |
79 | { |
80 | if (is_saved_state32(state)) { | |
81 | saved_state32(state)->r[0] = retval; | |
82 | } else { | |
83 | saved_state64(state)->x[0] = retval; | |
84 | } | |
85 | } | |
86 | ||
87 | static kern_return_t | |
88 | arm_get_mach_syscall_args(struct arm_saved_state *state, struct mach_call_args *dest, const mach_trap_t *trapp) | |
89 | { | |
90 | uint32_t reg_count; | |
91 | ||
92 | if (is_saved_state32(state)) { | |
93 | /* The trap table entry defines the number of 32-bit words to be copied in from userspace. */ | |
94 | reg_count = trapp->mach_trap_u32_words; | |
0a7de745 A |
95 | |
96 | /* | |
97 | * We get 7 contiguous words; r0-r6, hop over r7 | |
98 | * (frame pointer), optionally r8 | |
5ba3f43e A |
99 | */ |
100 | if (reg_count <= 7) { | |
101 | bcopy((char*)saved_state32(state), (char*)dest, sizeof(uint32_t) * reg_count); | |
102 | } else if (reg_count <= 9) { | |
103 | bcopy((char*)saved_state32(state), (char*)dest, sizeof(uint32_t) * 7); | |
0a7de745 A |
104 | bcopy((char*)&saved_state32(state)->r[8], ((char*)dest) + sizeof(uint32_t) * 7, |
105 | reg_count - 7); | |
5ba3f43e A |
106 | } else { |
107 | panic("Trap with %d words of args? We only support 9.", reg_count); | |
108 | } | |
109 | ||
110 | #if CONFIG_REQUIRES_U32_MUNGING | |
111 | trapp->mach_trap_arg_munge32(dest); | |
112 | #else | |
113 | #error U32 mach traps on ARM64 kernel requires munging | |
114 | #endif | |
0a7de745 | 115 | } else { |
5ba3f43e A |
116 | assert(is_saved_state64(state)); |
117 | bcopy((char*)saved_state64(state), (char*)dest, trapp->mach_trap_arg_count * sizeof(uint64_t)); | |
118 | } | |
119 | ||
120 | return KERN_SUCCESS; | |
121 | } | |
122 | ||
f427ee49 A |
123 | /** |
124 | * Marks or unmarks the given thread to be single stepped such | |
125 | * that it executes exactly one instruction and then takes an exception to | |
126 | * prevent further execution. | |
127 | * | |
128 | * @param thread 64 bit thread to be single stepped | |
129 | * @param on boolean value representing whether the thread should be | |
130 | * single stepped (on is true) or not (on is false) | |
131 | * | |
132 | * @returns KERN_SUCCESS if the status is successfully set or KERN_FAILURE if | |
133 | * it fails for any reason. | |
134 | */ | |
5ba3f43e | 135 | kern_return_t |
f427ee49 | 136 | thread_setsinglestep(thread_t thread, int on) |
5ba3f43e | 137 | { |
f427ee49 A |
138 | arm_debug_state64_t *thread_state = find_or_allocate_debug_state64(thread); |
139 | ||
140 | if (thread_state == NULL) { | |
141 | return KERN_FAILURE; | |
142 | } | |
143 | ||
144 | if (on) { | |
145 | thread_state->mdscr_el1 |= MDSCR_SS; | |
146 | } else { | |
147 | thread_state->mdscr_el1 &= ~MDSCR_SS; | |
148 | } | |
149 | ||
150 | if (thread == current_thread()) { | |
151 | arm_debug_set64(thread->machine.DebugData); | |
152 | } | |
153 | return KERN_SUCCESS; | |
5ba3f43e A |
154 | } |
155 | ||
156 | #if CONFIG_DTRACE | |
157 | ||
158 | vm_offset_t dtrace_get_cpu_int_stack_top(void); | |
159 | ||
160 | vm_offset_t | |
161 | dtrace_get_cpu_int_stack_top(void) | |
162 | { | |
163 | return getCpuDatap()->intstack_top; | |
164 | } | |
165 | #endif /* CONFIG_DTRACE */ | |
c3c9b80d | 166 | extern const char *const mach_syscall_name_table[]; |
5ba3f43e A |
167 | |
168 | /* ARM64_TODO: remove this. still TODO?*/ | |
169 | extern struct proc* current_proc(void); | |
170 | extern int proc_pid(struct proc*); | |
171 | ||
172 | void | |
173 | mach_syscall(struct arm_saved_state *state) | |
174 | { | |
175 | kern_return_t retval; | |
176 | mach_call_t mach_call; | |
cb323159 A |
177 | struct mach_call_args args = { |
178 | .arg1 = 0, | |
179 | .arg2 = 0, | |
180 | .arg3 = 0, | |
181 | .arg4 = 0, | |
182 | .arg5 = 0, | |
183 | .arg6 = 0, | |
184 | .arg7 = 0, | |
185 | .arg8 = 0, | |
186 | .arg9 = 0 | |
187 | }; | |
5ba3f43e A |
188 | int call_number = get_saved_state_svc_number(state); |
189 | int64_t exc_code; | |
190 | int argc; | |
191 | ||
192 | struct uthread *ut = get_bsdthread_info(current_thread()); | |
193 | uthread_reset_proc_refcount(ut); | |
194 | ||
195 | assert(call_number < 0); /* Otherwise it would be a Unix syscall */ | |
196 | call_number = -call_number; | |
197 | ||
198 | if (call_number >= MACH_TRAP_TABLE_COUNT) { | |
199 | goto bad; | |
200 | } | |
201 | ||
202 | DEBUG_KPRINT_SYSCALL_MACH( | |
203 | "mach_syscall: code=%d(%s) (pid %d, tid %lld)\n", | |
0a7de745 | 204 | call_number, mach_syscall_name_table[call_number], |
5ba3f43e A |
205 | proc_pid(current_proc()), thread_tid(current_thread())); |
206 | ||
207 | #if DEBUG_TRACE | |
208 | kprintf("mach_syscall(0x%08x) code=%d\n", state, call_number); | |
209 | #endif | |
210 | ||
211 | mach_call = (mach_call_t)mach_trap_table[call_number].mach_trap_function; | |
212 | ||
213 | if (mach_call == (mach_call_t)kern_invalid) { | |
214 | DEBUG_KPRINT_SYSCALL_MACH( | |
215 | "mach_syscall: kern_invalid 0x%x\n", call_number); | |
216 | goto bad; | |
217 | } | |
218 | ||
219 | argc = mach_trap_table[call_number].mach_trap_arg_count; | |
220 | if (argc) { | |
221 | retval = arm_get_mach_syscall_args(state, &args, &mach_trap_table[call_number]); | |
222 | if (retval != KERN_SUCCESS) { | |
223 | arm_set_mach_syscall_ret(state, retval); | |
224 | ||
225 | DEBUG_KPRINT_SYSCALL_MACH( | |
226 | "mach_syscall: retval=0x%x\n", retval); | |
227 | return; | |
228 | } | |
229 | } | |
230 | ||
231 | KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, | |
0a7de745 A |
232 | MACHDBG_CODE(DBG_MACH_EXCP_SC, (call_number)) | DBG_FUNC_START, |
233 | args.arg1, args.arg2, args.arg3, args.arg4, 0); | |
5ba3f43e | 234 | |
f427ee49 A |
235 | #if CONFIG_MACF |
236 | /* | |
237 | * Check syscall filter mask, if exists. | |
238 | * | |
239 | * Not all mach traps are filtered. e.g., mach_absolute_time() and | |
240 | * mach_continuous_time(). See handle_svc(). | |
241 | */ | |
242 | task_t task = current_task(); | |
243 | uint8_t *filter_mask = task->mach_trap_filter_mask; | |
244 | ||
245 | if (__improbable(filter_mask != NULL && | |
246 | !bitstr_test(filter_mask, call_number))) { | |
247 | if (mac_task_mach_trap_evaluate != NULL) { | |
248 | retval = mac_task_mach_trap_evaluate(get_bsdtask_info(task), | |
249 | call_number); | |
250 | if (retval) { | |
251 | goto skip_machcall; | |
252 | } | |
253 | } | |
254 | } | |
255 | #endif /* CONFIG_MACF */ | |
256 | ||
5ba3f43e A |
257 | retval = mach_call(&args); |
258 | ||
f427ee49 A |
259 | #if CONFIG_MACF |
260 | skip_machcall: | |
261 | #endif | |
262 | ||
5ba3f43e | 263 | DEBUG_KPRINT_SYSCALL_MACH("mach_syscall: retval=0x%x (pid %d, tid %lld)\n", retval, |
0a7de745 | 264 | proc_pid(current_proc()), thread_tid(current_thread())); |
5ba3f43e A |
265 | |
266 | KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, | |
0a7de745 A |
267 | MACHDBG_CODE(DBG_MACH_EXCP_SC, (call_number)) | DBG_FUNC_END, |
268 | retval, 0, 0, 0, 0); | |
5ba3f43e A |
269 | |
270 | arm_set_mach_syscall_ret(state, retval); | |
271 | ||
272 | throttle_lowpri_io(1); | |
273 | ||
274 | #if DEBUG || DEVELOPMENT | |
275 | kern_allocation_name_t | |
276 | prior __assert_only = thread_get_kernel_state(current_thread())->allocation_name; | |
277 | assertf(prior == NULL, "thread_set_allocation_name(\"%s\") not cleared", kern_allocation_get_name(prior)); | |
278 | #endif /* DEBUG || DEVELOPMENT */ | |
279 | ||
280 | #if PROC_REF_DEBUG | |
281 | if (__improbable(uthread_get_proc_refcount(ut) != 0)) { | |
282 | panic("system call returned with uu_proc_refcount != 0"); | |
283 | } | |
284 | #endif | |
285 | ||
286 | return; | |
287 | ||
288 | bad: | |
289 | exc_code = call_number; | |
290 | exception_triage(EXC_SYSCALL, &exc_code, 1); | |
291 | /* NOTREACHED */ | |
292 | panic("Returned from exception_triage()?\n"); | |
293 | } | |
294 | #endif /* MACH_BSD */ |