]>
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 | ||
37 | #include <kern/counters.h> | |
38 | #include <kern/cpu_data.h> | |
39 | #include <arm/cpu_data_internal.h> | |
40 | #include <kern/mach_param.h> | |
41 | #include <kern/task.h> | |
42 | #include <kern/thread.h> | |
43 | #include <kern/sched_prim.h> | |
44 | #include <kern/misc_protos.h> | |
45 | #include <kern/assert.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 <mach/thread_status.h> | |
51 | #include <vm/pmap.h> | |
52 | ||
53 | #include <sys/kdebug.h> | |
54 | ||
55 | #include <sys/syscall.h> | |
56 | ||
57 | extern void throttle_lowpri_io(int); | |
58 | void mach_syscall(struct arm_saved_state*); | |
59 | typedef kern_return_t (*mach_call_t)(void *); | |
60 | ||
61 | struct mach_call_args { | |
62 | syscall_arg_t arg1; | |
63 | syscall_arg_t arg2; | |
64 | syscall_arg_t arg3; | |
65 | syscall_arg_t arg4; | |
66 | syscall_arg_t arg5; | |
67 | syscall_arg_t arg6; | |
68 | syscall_arg_t arg7; | |
69 | syscall_arg_t arg8; | |
70 | syscall_arg_t arg9; | |
71 | }; | |
72 | ||
73 | static void | |
0a7de745 | 74 | arm_set_mach_syscall_ret(struct arm_saved_state *state, int retval) |
5ba3f43e A |
75 | { |
76 | if (is_saved_state32(state)) { | |
77 | saved_state32(state)->r[0] = retval; | |
78 | } else { | |
79 | saved_state64(state)->x[0] = retval; | |
80 | } | |
81 | } | |
82 | ||
83 | static kern_return_t | |
84 | arm_get_mach_syscall_args(struct arm_saved_state *state, struct mach_call_args *dest, const mach_trap_t *trapp) | |
85 | { | |
86 | uint32_t reg_count; | |
87 | ||
88 | if (is_saved_state32(state)) { | |
89 | /* The trap table entry defines the number of 32-bit words to be copied in from userspace. */ | |
90 | reg_count = trapp->mach_trap_u32_words; | |
0a7de745 A |
91 | |
92 | /* | |
93 | * We get 7 contiguous words; r0-r6, hop over r7 | |
94 | * (frame pointer), optionally r8 | |
5ba3f43e A |
95 | */ |
96 | if (reg_count <= 7) { | |
97 | bcopy((char*)saved_state32(state), (char*)dest, sizeof(uint32_t) * reg_count); | |
98 | } else if (reg_count <= 9) { | |
99 | bcopy((char*)saved_state32(state), (char*)dest, sizeof(uint32_t) * 7); | |
0a7de745 A |
100 | bcopy((char*)&saved_state32(state)->r[8], ((char*)dest) + sizeof(uint32_t) * 7, |
101 | reg_count - 7); | |
5ba3f43e A |
102 | } else { |
103 | panic("Trap with %d words of args? We only support 9.", reg_count); | |
104 | } | |
105 | ||
106 | #if CONFIG_REQUIRES_U32_MUNGING | |
107 | trapp->mach_trap_arg_munge32(dest); | |
108 | #else | |
109 | #error U32 mach traps on ARM64 kernel requires munging | |
110 | #endif | |
0a7de745 | 111 | } else { |
5ba3f43e A |
112 | assert(is_saved_state64(state)); |
113 | bcopy((char*)saved_state64(state), (char*)dest, trapp->mach_trap_arg_count * sizeof(uint64_t)); | |
114 | } | |
115 | ||
116 | return KERN_SUCCESS; | |
117 | } | |
118 | ||
119 | kern_return_t | |
120 | thread_setsinglestep(__unused thread_t thread, __unused int on) | |
121 | { | |
0a7de745 | 122 | return KERN_FAILURE; /* XXX TODO */ |
5ba3f43e A |
123 | } |
124 | ||
125 | #if CONFIG_DTRACE | |
126 | ||
127 | vm_offset_t dtrace_get_cpu_int_stack_top(void); | |
128 | ||
129 | vm_offset_t | |
130 | dtrace_get_cpu_int_stack_top(void) | |
131 | { | |
132 | return getCpuDatap()->intstack_top; | |
133 | } | |
134 | #endif /* CONFIG_DTRACE */ | |
135 | extern const char *mach_syscall_name_table[]; | |
136 | ||
137 | /* ARM64_TODO: remove this. still TODO?*/ | |
138 | extern struct proc* current_proc(void); | |
139 | extern int proc_pid(struct proc*); | |
140 | ||
141 | void | |
142 | mach_syscall(struct arm_saved_state *state) | |
143 | { | |
144 | kern_return_t retval; | |
145 | mach_call_t mach_call; | |
cb323159 A |
146 | struct mach_call_args args = { |
147 | .arg1 = 0, | |
148 | .arg2 = 0, | |
149 | .arg3 = 0, | |
150 | .arg4 = 0, | |
151 | .arg5 = 0, | |
152 | .arg6 = 0, | |
153 | .arg7 = 0, | |
154 | .arg8 = 0, | |
155 | .arg9 = 0 | |
156 | }; | |
5ba3f43e A |
157 | int call_number = get_saved_state_svc_number(state); |
158 | int64_t exc_code; | |
159 | int argc; | |
160 | ||
161 | struct uthread *ut = get_bsdthread_info(current_thread()); | |
162 | uthread_reset_proc_refcount(ut); | |
163 | ||
164 | assert(call_number < 0); /* Otherwise it would be a Unix syscall */ | |
165 | call_number = -call_number; | |
166 | ||
167 | if (call_number >= MACH_TRAP_TABLE_COUNT) { | |
168 | goto bad; | |
169 | } | |
170 | ||
171 | DEBUG_KPRINT_SYSCALL_MACH( | |
172 | "mach_syscall: code=%d(%s) (pid %d, tid %lld)\n", | |
0a7de745 | 173 | call_number, mach_syscall_name_table[call_number], |
5ba3f43e A |
174 | proc_pid(current_proc()), thread_tid(current_thread())); |
175 | ||
176 | #if DEBUG_TRACE | |
177 | kprintf("mach_syscall(0x%08x) code=%d\n", state, call_number); | |
178 | #endif | |
179 | ||
180 | mach_call = (mach_call_t)mach_trap_table[call_number].mach_trap_function; | |
181 | ||
182 | if (mach_call == (mach_call_t)kern_invalid) { | |
183 | DEBUG_KPRINT_SYSCALL_MACH( | |
184 | "mach_syscall: kern_invalid 0x%x\n", call_number); | |
185 | goto bad; | |
186 | } | |
187 | ||
188 | argc = mach_trap_table[call_number].mach_trap_arg_count; | |
189 | if (argc) { | |
190 | retval = arm_get_mach_syscall_args(state, &args, &mach_trap_table[call_number]); | |
191 | if (retval != KERN_SUCCESS) { | |
192 | arm_set_mach_syscall_ret(state, retval); | |
193 | ||
194 | DEBUG_KPRINT_SYSCALL_MACH( | |
195 | "mach_syscall: retval=0x%x\n", retval); | |
196 | return; | |
197 | } | |
198 | } | |
199 | ||
200 | KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, | |
0a7de745 A |
201 | MACHDBG_CODE(DBG_MACH_EXCP_SC, (call_number)) | DBG_FUNC_START, |
202 | args.arg1, args.arg2, args.arg3, args.arg4, 0); | |
5ba3f43e A |
203 | |
204 | retval = mach_call(&args); | |
205 | ||
206 | DEBUG_KPRINT_SYSCALL_MACH("mach_syscall: retval=0x%x (pid %d, tid %lld)\n", retval, | |
0a7de745 | 207 | proc_pid(current_proc()), thread_tid(current_thread())); |
5ba3f43e A |
208 | |
209 | KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, | |
0a7de745 A |
210 | MACHDBG_CODE(DBG_MACH_EXCP_SC, (call_number)) | DBG_FUNC_END, |
211 | retval, 0, 0, 0, 0); | |
5ba3f43e A |
212 | |
213 | arm_set_mach_syscall_ret(state, retval); | |
214 | ||
215 | throttle_lowpri_io(1); | |
216 | ||
217 | #if DEBUG || DEVELOPMENT | |
218 | kern_allocation_name_t | |
219 | prior __assert_only = thread_get_kernel_state(current_thread())->allocation_name; | |
220 | assertf(prior == NULL, "thread_set_allocation_name(\"%s\") not cleared", kern_allocation_get_name(prior)); | |
221 | #endif /* DEBUG || DEVELOPMENT */ | |
222 | ||
223 | #if PROC_REF_DEBUG | |
224 | if (__improbable(uthread_get_proc_refcount(ut) != 0)) { | |
225 | panic("system call returned with uu_proc_refcount != 0"); | |
226 | } | |
227 | #endif | |
228 | ||
229 | return; | |
230 | ||
231 | bad: | |
232 | exc_code = call_number; | |
233 | exception_triage(EXC_SYSCALL, &exc_code, 1); | |
234 | /* NOTREACHED */ | |
235 | panic("Returned from exception_triage()?\n"); | |
236 | } | |
237 | #endif /* MACH_BSD */ |