]>
Commit | Line | Data |
---|---|---|
5ba3f43e | 1 | /* |
0a7de745 | 2 | * Copyright (c) 2007-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 | #include <debug.h> | |
29 | ||
30 | #include <types.h> | |
31 | ||
32 | #include <mach/mach_types.h> | |
33 | #include <mach/thread_status.h> | |
34 | #include <mach/vm_types.h> | |
35 | ||
36 | #include <kern/kern_types.h> | |
37 | #include <kern/task.h> | |
38 | #include <kern/thread.h> | |
39 | #include <kern/misc_protos.h> | |
40 | #include <kern/mach_param.h> | |
41 | #include <kern/spl.h> | |
42 | #include <kern/machine.h> | |
43 | #include <kern/kalloc.h> | |
44 | #include <kern/kpc.h> | |
45 | ||
46 | #include <arm/proc_reg.h> | |
47 | #include <arm/cpu_data_internal.h> | |
48 | #include <arm/misc_protos.h> | |
49 | #include <arm/cpuid.h> | |
50 | ||
51 | #include <vm/vm_map.h> | |
52 | #include <vm/vm_protos.h> | |
53 | ||
54 | #include <sys/kdebug.h> | |
55 | ||
56 | extern int debug_task; | |
57 | ||
58 | zone_t ads_zone; /* zone for debug_state area */ | |
59 | ||
60 | /* | |
61 | * Routine: consider_machine_collect | |
62 | * | |
63 | */ | |
64 | void | |
65 | consider_machine_collect(void) | |
66 | { | |
67 | pmap_gc(); | |
68 | } | |
69 | ||
70 | /* | |
71 | * Routine: consider_machine_adjust | |
72 | * | |
73 | */ | |
74 | void | |
75 | consider_machine_adjust(void) | |
76 | { | |
77 | } | |
78 | ||
79 | /* | |
80 | * Routine: machine_switch_context | |
81 | * | |
82 | */ | |
83 | thread_t | |
84 | machine_switch_context( | |
85 | thread_t old, | |
86 | thread_continue_t continuation, | |
87 | thread_t new) | |
88 | { | |
89 | thread_t retval; | |
90 | cpu_data_t *cpu_data_ptr; | |
91 | ||
92 | #define machine_switch_context_kprintf(x...) /* kprintf("machine_switch_con | |
93 | * text: " x) */ | |
94 | ||
95 | cpu_data_ptr = getCpuDatap(); | |
96 | if (old == new) | |
97 | panic("machine_switch_context"); | |
98 | ||
99 | kpc_off_cpu(old); | |
100 | ||
101 | pmap_set_pmap(new->map->pmap, new); | |
102 | ||
103 | new->machine.CpuDatap = cpu_data_ptr; | |
104 | ||
0a7de745 A |
105 | #if __SMP__ |
106 | /* TODO: Should this be ordered? */ | |
107 | old->machine.machine_thread_flags &= ~MACHINE_THREAD_FLAGS_ON_CPU; | |
108 | new->machine.machine_thread_flags |= MACHINE_THREAD_FLAGS_ON_CPU; | |
109 | #endif /* __SMP__ */ | |
110 | ||
5ba3f43e A |
111 | machine_switch_context_kprintf("old= %x contination = %x new = %x\n", old, continuation, new); |
112 | retval = Switch_context(old, continuation, new); | |
113 | assert(retval != NULL); | |
114 | ||
115 | return retval; | |
116 | } | |
117 | ||
cb323159 A |
118 | boolean_t |
119 | machine_thread_on_core(thread_t thread) | |
120 | { | |
121 | return thread->machine.machine_thread_flags & MACHINE_THREAD_FLAGS_ON_CPU; | |
122 | } | |
123 | ||
5ba3f43e A |
124 | /* |
125 | * Routine: machine_thread_create | |
126 | * | |
127 | */ | |
128 | kern_return_t | |
129 | machine_thread_create( | |
130 | thread_t thread, | |
131 | #if !__ARM_USER_PROTECT__ | |
132 | __unused | |
133 | #endif | |
134 | task_t task) | |
135 | { | |
136 | ||
137 | #define machine_thread_create_kprintf(x...) /* kprintf("machine_thread_create: " x) */ | |
138 | ||
139 | machine_thread_create_kprintf("thread = %x\n", thread); | |
140 | ||
141 | if (current_thread() != thread) { | |
142 | thread->machine.CpuDatap = (cpu_data_t *)0; | |
143 | } | |
144 | thread->machine.preemption_count = 0; | |
145 | thread->machine.cthread_self = 0; | |
5ba3f43e A |
146 | #if __ARM_USER_PROTECT__ |
147 | { | |
148 | struct pmap *new_pmap = vm_map_pmap(task->map); | |
149 | ||
150 | thread->machine.kptw_ttb = ((unsigned int) kernel_pmap->ttep) | TTBR_SETUP; | |
cb323159 | 151 | thread->machine.asid = new_pmap->hw_asid; |
5ba3f43e A |
152 | if (new_pmap->tte_index_max == NTTES) { |
153 | thread->machine.uptw_ttc = 2; | |
154 | thread->machine.uptw_ttb = ((unsigned int) new_pmap->ttep) | TTBR_SETUP; | |
155 | } else { | |
156 | thread->machine.uptw_ttc = 1; | |
157 | thread->machine.uptw_ttb = ((unsigned int) new_pmap->ttep ) | TTBR_SETUP; | |
158 | } | |
159 | } | |
160 | #endif | |
161 | machine_thread_state_initialize(thread); | |
162 | ||
163 | return (KERN_SUCCESS); | |
164 | } | |
165 | ||
166 | /* | |
167 | * Routine: machine_thread_destroy | |
168 | * | |
169 | */ | |
170 | void | |
171 | machine_thread_destroy( | |
172 | thread_t thread) | |
173 | { | |
174 | ||
175 | if (thread->machine.DebugData != NULL) { | |
176 | if (thread->machine.DebugData == getCpuDatap()->cpu_user_debug) | |
177 | arm_debug_set(NULL); | |
178 | zfree(ads_zone, thread->machine.DebugData); | |
179 | } | |
180 | } | |
181 | ||
182 | ||
183 | /* | |
184 | * Routine: machine_thread_init | |
185 | * | |
186 | */ | |
187 | void | |
188 | machine_thread_init(void) | |
189 | { | |
190 | ads_zone = zinit(sizeof(arm_debug_state_t), | |
191 | THREAD_CHUNK * (sizeof(arm_debug_state_t)), | |
192 | THREAD_CHUNK * (sizeof(arm_debug_state_t)), | |
193 | "arm debug state"); | |
194 | } | |
195 | ||
196 | ||
197 | /* | |
198 | * Routine: get_useraddr | |
199 | * | |
200 | */ | |
201 | user_addr_t | |
202 | get_useraddr() | |
203 | { | |
204 | return (current_thread()->machine.PcbData.pc); | |
205 | } | |
206 | ||
207 | /* | |
208 | * Routine: machine_stack_detach | |
209 | * | |
210 | */ | |
211 | vm_offset_t | |
212 | machine_stack_detach( | |
213 | thread_t thread) | |
214 | { | |
215 | vm_offset_t stack; | |
216 | ||
217 | KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED, MACH_STACK_DETACH), | |
218 | (uintptr_t)thread_tid(thread), thread->priority, thread->sched_pri, 0, 0); | |
219 | ||
220 | stack = thread->kernel_stack; | |
221 | thread->kernel_stack = 0; | |
222 | thread->machine.kstackptr = 0; | |
223 | ||
224 | return (stack); | |
225 | } | |
226 | ||
227 | ||
228 | /* | |
229 | * Routine: machine_stack_attach | |
230 | * | |
231 | */ | |
232 | void | |
233 | machine_stack_attach( | |
234 | thread_t thread, | |
235 | vm_offset_t stack) | |
236 | { | |
237 | struct arm_saved_state *savestate; | |
238 | ||
239 | #define machine_stack_attach_kprintf(x...) /* kprintf("machine_stack_attach: " x) */ | |
240 | ||
241 | KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED, MACH_STACK_ATTACH), | |
242 | (uintptr_t)thread_tid(thread), thread->priority, thread->sched_pri, 0, 0); | |
243 | ||
244 | thread->kernel_stack = stack; | |
245 | thread->machine.kstackptr = stack + kernel_stack_size - sizeof(struct thread_kernel_state); | |
246 | thread_initialize_kernel_state(thread); | |
247 | savestate = (struct arm_saved_state *) thread->machine.kstackptr; | |
248 | ||
249 | savestate->lr = (uint32_t) thread_continue; | |
250 | savestate->sp = thread->machine.kstackptr; | |
251 | savestate->r[7] = 0x0UL; | |
252 | savestate->r[9] = (uint32_t) NULL; | |
253 | savestate->cpsr = PSR_SVC_MODE | PSR_INTMASK; | |
94ff46dc | 254 | vfp_state_initialize(&savestate->VFPdata); |
5ba3f43e A |
255 | machine_stack_attach_kprintf("thread = %x pc = %x, sp = %x\n", thread, savestate->lr, savestate->sp); |
256 | } | |
257 | ||
258 | ||
259 | /* | |
260 | * Routine: machine_stack_handoff | |
261 | * | |
262 | */ | |
263 | void | |
264 | machine_stack_handoff( | |
265 | thread_t old, | |
266 | thread_t new) | |
267 | { | |
268 | vm_offset_t stack; | |
269 | cpu_data_t *cpu_data_ptr; | |
270 | ||
271 | kpc_off_cpu(old); | |
272 | ||
273 | stack = machine_stack_detach(old); | |
274 | cpu_data_ptr = getCpuDatap(); | |
275 | new->kernel_stack = stack; | |
276 | new->machine.kstackptr = stack + kernel_stack_size - sizeof(struct thread_kernel_state); | |
277 | if (stack == old->reserved_stack) { | |
278 | assert(new->reserved_stack); | |
279 | old->reserved_stack = new->reserved_stack; | |
280 | new->reserved_stack = stack; | |
281 | } | |
282 | ||
283 | pmap_set_pmap(new->map->pmap, new); | |
284 | new->machine.CpuDatap = cpu_data_ptr; | |
0a7de745 A |
285 | |
286 | #if __SMP__ | |
287 | /* TODO: Should this be ordered? */ | |
288 | old->machine.machine_thread_flags &= ~MACHINE_THREAD_FLAGS_ON_CPU; | |
289 | new->machine.machine_thread_flags |= MACHINE_THREAD_FLAGS_ON_CPU; | |
290 | #endif /* __SMP__ */ | |
291 | ||
5ba3f43e A |
292 | machine_set_current_thread(new); |
293 | thread_initialize_kernel_state(new); | |
294 | ||
295 | return; | |
296 | } | |
297 | ||
298 | ||
299 | /* | |
300 | * Routine: call_continuation | |
301 | * | |
302 | */ | |
303 | void | |
304 | call_continuation( | |
305 | thread_continue_t continuation, | |
306 | void *parameter, | |
d9a64523 A |
307 | wait_result_t wresult, |
308 | boolean_t enable_interrupts) | |
5ba3f43e A |
309 | { |
310 | #define call_continuation_kprintf(x...) /* kprintf("call_continuation_kprintf: | |
311 | * " x) */ | |
312 | ||
313 | call_continuation_kprintf("thread = %x continuation = %x, stack = %x\n", current_thread(), continuation, current_thread()->machine.kstackptr); | |
d9a64523 | 314 | Call_continuation(continuation, parameter, wresult, enable_interrupts); |
5ba3f43e A |
315 | } |
316 | ||
317 | void arm_debug_set(arm_debug_state_t *debug_state) | |
318 | { | |
319 | /* If this CPU supports the memory-mapped debug interface, use it, otherwise | |
320 | * attempt the Extended CP14 interface. The two routines need to be kept in sync, | |
321 | * functionality-wise. | |
322 | */ | |
323 | struct cpu_data *cpu_data_ptr; | |
324 | arm_debug_info_t *debug_info = arm_debug_info(); | |
325 | boolean_t intr; | |
326 | ||
327 | intr = ml_set_interrupts_enabled(FALSE); | |
328 | cpu_data_ptr = getCpuDatap(); | |
329 | ||
330 | // Set current user debug | |
331 | cpu_data_ptr->cpu_user_debug = debug_state; | |
332 | ||
333 | if (debug_info->memory_mapped_core_debug) { | |
334 | int i; | |
335 | uintptr_t debug_map = cpu_data_ptr->cpu_debug_interface_map; | |
336 | ||
337 | // unlock debug registers | |
338 | *(volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGLAR) = ARM_DBG_LOCK_ACCESS_KEY; | |
339 | ||
340 | // read DBGPRSR to clear the sticky power-down bit (necessary to access debug registers) | |
341 | *(volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGPRSR); | |
342 | ||
343 | // enable monitor mode (needed to set and use debug registers) | |
344 | *(volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGDSCR) |= ARM_DBGDSCR_MDBGEN; | |
345 | ||
346 | // first turn off all breakpoints/watchpoints | |
347 | for (i = 0; i < 16; i++) { | |
348 | ((volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGBCR))[i] = 0; | |
349 | ((volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGWCR))[i] = 0; | |
350 | } | |
351 | ||
352 | // if (debug_state == NULL) disable monitor mode | |
353 | if (debug_state == NULL) { | |
354 | *(volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGDSCR) &= ~ARM_DBGDSCR_MDBGEN; | |
355 | } else { | |
356 | for (i = 0; i < 16; i++) { | |
357 | ((volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGBVR))[i] = debug_state->bvr[i]; | |
358 | ((volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGBCR))[i] = debug_state->bcr[i]; | |
359 | ((volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGWVR))[i] = debug_state->wvr[i]; | |
360 | ((volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGWCR))[i] = debug_state->wcr[i]; | |
361 | } | |
362 | } | |
363 | ||
364 | // lock debug registers | |
365 | *(volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGLAR) = 0; | |
366 | ||
367 | } else if (debug_info->coprocessor_core_debug) { | |
368 | arm_debug_set_cp14(debug_state); | |
369 | } | |
370 | ||
371 | (void) ml_set_interrupts_enabled(intr); | |
372 | ||
373 | return; | |
374 | } | |
375 | ||
376 | /* | |
377 | * Duplicate one arm_debug_state_t to another. "all" parameter | |
378 | * is ignored in the case of ARM -- Is this the right assumption? | |
379 | */ | |
380 | void | |
381 | copy_debug_state( | |
382 | arm_debug_state_t *src, | |
383 | arm_debug_state_t *target, | |
384 | __unused boolean_t all) | |
385 | { | |
386 | bcopy(src, target, sizeof(arm_debug_state_t)); | |
387 | } | |
388 | ||
389 | kern_return_t | |
390 | machine_thread_set_tsd_base( | |
391 | thread_t thread, | |
392 | mach_vm_offset_t tsd_base) | |
393 | { | |
394 | ||
395 | if (thread->task == kernel_task) { | |
396 | return KERN_INVALID_ARGUMENT; | |
397 | } | |
398 | ||
399 | if (tsd_base & 0x3) { | |
400 | return KERN_INVALID_ARGUMENT; | |
401 | } | |
402 | ||
403 | if (tsd_base > UINT32_MAX) | |
404 | tsd_base = 0ULL; | |
405 | ||
406 | thread->machine.cthread_self = tsd_base; | |
407 | ||
408 | /* For current thread, make the TSD base active immediately */ | |
409 | if (thread == current_thread()) { | |
410 | ||
411 | mp_disable_preemption(); | |
412 | __asm__ volatile( | |
413 | "mrc p15, 0, r6, c13, c0, 3\n" | |
414 | "and r6, r6, #3\n" | |
415 | "orr r6, r6, %0\n" | |
416 | "mcr p15, 0, r6, c13, c0, 3\n" | |
417 | : /* output */ | |
418 | : "r"((uint32_t)tsd_base) /* input */ | |
419 | : "r6" /* clobbered register */ | |
420 | ); | |
421 | mp_enable_preemption(); | |
422 | ||
423 | } | |
424 | ||
425 | return KERN_SUCCESS; | |
426 | } | |
0a7de745 A |
427 | |
428 | void | |
429 | machine_tecs(__unused thread_t thr) | |
430 | { | |
431 | } | |
432 | ||
433 | int | |
434 | machine_csv(__unused cpuvn_e cve) | |
435 | { | |
436 | return 0; | |
437 | } |