2 * Copyright (c) 2007-2019 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 #include <mach/mach_types.h>
33 #include <mach/thread_status.h>
34 #include <mach/vm_types.h>
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>
42 #include <kern/machine.h>
43 #include <kern/kalloc.h>
46 #include <arm/proc_reg.h>
47 #include <arm/cpu_data_internal.h>
48 #include <arm/misc_protos.h>
49 #include <arm/cpuid.h>
51 #include <vm/vm_map.h>
52 #include <vm/vm_protos.h>
54 #include <sys/kdebug.h>
56 extern int debug_task
;
58 zone_t ads_zone
; /* zone for debug_state area */
61 * Routine: consider_machine_collect
65 consider_machine_collect(void)
71 * Routine: consider_machine_adjust
75 consider_machine_adjust(void)
80 * Routine: machine_switch_context
84 machine_switch_context(
86 thread_continue_t continuation
,
90 cpu_data_t
*cpu_data_ptr
;
92 #define machine_switch_context_kprintf(x...) /* kprintf("machine_switch_con
95 cpu_data_ptr
= getCpuDatap();
97 panic("machine_switch_context");
101 pmap_set_pmap(new->map
->pmap
, new);
103 new->machine
.CpuDatap
= cpu_data_ptr
;
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
;
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
);
119 machine_thread_on_core(thread_t thread
)
121 return thread
->machine
.machine_thread_flags
& MACHINE_THREAD_FLAGS_ON_CPU
;
125 * Routine: machine_thread_create
129 machine_thread_create(
131 #if !__ARM_USER_PROTECT__
137 #define machine_thread_create_kprintf(x...) /* kprintf("machine_thread_create: " x) */
139 machine_thread_create_kprintf("thread = %x\n", thread
);
141 if (current_thread() != thread
) {
142 thread
->machine
.CpuDatap
= (cpu_data_t
*)0;
144 thread
->machine
.preemption_count
= 0;
145 thread
->machine
.cthread_self
= 0;
146 #if __ARM_USER_PROTECT__
148 struct pmap
*new_pmap
= vm_map_pmap(task
->map
);
150 thread
->machine
.kptw_ttb
= ((unsigned int) kernel_pmap
->ttep
) | TTBR_SETUP
;
151 thread
->machine
.asid
= new_pmap
->hw_asid
;
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
;
156 thread
->machine
.uptw_ttc
= 1;
157 thread
->machine
.uptw_ttb
= ((unsigned int) new_pmap
->ttep
) | TTBR_SETUP
;
161 machine_thread_state_initialize(thread
);
163 return (KERN_SUCCESS
);
167 * Routine: machine_thread_destroy
171 machine_thread_destroy(
175 if (thread
->machine
.DebugData
!= NULL
) {
176 if (thread
->machine
.DebugData
== getCpuDatap()->cpu_user_debug
)
178 zfree(ads_zone
, thread
->machine
.DebugData
);
184 * Routine: machine_thread_init
188 machine_thread_init(void)
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
)),
197 * Routine: machine_thread_template_init
201 machine_thread_template_init(thread_t __unused thr_template
)
203 /* Nothing to do on this platform. */
207 * Routine: get_useraddr
213 return (current_thread()->machine
.PcbData
.pc
);
217 * Routine: machine_stack_detach
221 machine_stack_detach(
226 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED
, MACH_STACK_DETACH
),
227 (uintptr_t)thread_tid(thread
), thread
->priority
, thread
->sched_pri
, 0, 0);
229 stack
= thread
->kernel_stack
;
230 thread
->kernel_stack
= 0;
231 thread
->machine
.kstackptr
= 0;
238 * Routine: machine_stack_attach
242 machine_stack_attach(
246 struct arm_saved_state
*savestate
;
248 #define machine_stack_attach_kprintf(x...) /* kprintf("machine_stack_attach: " x) */
250 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED
, MACH_STACK_ATTACH
),
251 (uintptr_t)thread_tid(thread
), thread
->priority
, thread
->sched_pri
, 0, 0);
253 thread
->kernel_stack
= stack
;
254 thread
->machine
.kstackptr
= stack
+ kernel_stack_size
- sizeof(struct thread_kernel_state
);
255 thread_initialize_kernel_state(thread
);
256 savestate
= (struct arm_saved_state
*) thread
->machine
.kstackptr
;
258 savestate
->lr
= (uint32_t) thread_continue
;
259 savestate
->sp
= thread
->machine
.kstackptr
;
260 savestate
->r
[7] = 0x0UL
;
261 savestate
->r
[9] = (uint32_t) NULL
;
262 savestate
->cpsr
= PSR_SVC_MODE
| PSR_INTMASK
;
263 vfp_state_initialize(&savestate
->VFPdata
);
264 machine_stack_attach_kprintf("thread = %x pc = %x, sp = %x\n", thread
, savestate
->lr
, savestate
->sp
);
269 * Routine: machine_stack_handoff
273 machine_stack_handoff(
278 cpu_data_t
*cpu_data_ptr
;
282 stack
= machine_stack_detach(old
);
283 cpu_data_ptr
= getCpuDatap();
284 new->kernel_stack
= stack
;
285 new->machine
.kstackptr
= stack
+ kernel_stack_size
- sizeof(struct thread_kernel_state
);
286 if (stack
== old
->reserved_stack
) {
287 assert(new->reserved_stack
);
288 old
->reserved_stack
= new->reserved_stack
;
289 new->reserved_stack
= stack
;
292 pmap_set_pmap(new->map
->pmap
, new);
293 new->machine
.CpuDatap
= cpu_data_ptr
;
296 /* TODO: Should this be ordered? */
297 old
->machine
.machine_thread_flags
&= ~MACHINE_THREAD_FLAGS_ON_CPU
;
298 new->machine
.machine_thread_flags
|= MACHINE_THREAD_FLAGS_ON_CPU
;
301 machine_set_current_thread(new);
302 thread_initialize_kernel_state(new);
309 * Routine: call_continuation
314 thread_continue_t continuation
,
316 wait_result_t wresult
,
317 boolean_t enable_interrupts
)
319 #define call_continuation_kprintf(x...) /* kprintf("call_continuation_kprintf:
322 call_continuation_kprintf("thread = %x continuation = %x, stack = %x\n", current_thread(), continuation
, current_thread()->machine
.kstackptr
);
323 Call_continuation(continuation
, parameter
, wresult
, enable_interrupts
);
326 void arm_debug_set(arm_debug_state_t
*debug_state
)
328 /* If this CPU supports the memory-mapped debug interface, use it, otherwise
329 * attempt the Extended CP14 interface. The two routines need to be kept in sync,
330 * functionality-wise.
332 struct cpu_data
*cpu_data_ptr
;
333 arm_debug_info_t
*debug_info
= arm_debug_info();
336 intr
= ml_set_interrupts_enabled(FALSE
);
337 cpu_data_ptr
= getCpuDatap();
339 // Set current user debug
340 cpu_data_ptr
->cpu_user_debug
= debug_state
;
342 if (debug_info
->memory_mapped_core_debug
) {
344 uintptr_t debug_map
= cpu_data_ptr
->cpu_debug_interface_map
;
346 // unlock debug registers
347 *(volatile uint32_t *)(debug_map
+ ARM_DEBUG_OFFSET_DBGLAR
) = ARM_DBG_LOCK_ACCESS_KEY
;
349 // read DBGPRSR to clear the sticky power-down bit (necessary to access debug registers)
350 *(volatile uint32_t *)(debug_map
+ ARM_DEBUG_OFFSET_DBGPRSR
);
352 // enable monitor mode (needed to set and use debug registers)
353 *(volatile uint32_t *)(debug_map
+ ARM_DEBUG_OFFSET_DBGDSCR
) |= ARM_DBGDSCR_MDBGEN
;
355 // first turn off all breakpoints/watchpoints
356 for (i
= 0; i
< 16; i
++) {
357 ((volatile uint32_t *)(debug_map
+ ARM_DEBUG_OFFSET_DBGBCR
))[i
] = 0;
358 ((volatile uint32_t *)(debug_map
+ ARM_DEBUG_OFFSET_DBGWCR
))[i
] = 0;
361 // if (debug_state == NULL) disable monitor mode
362 if (debug_state
== NULL
) {
363 *(volatile uint32_t *)(debug_map
+ ARM_DEBUG_OFFSET_DBGDSCR
) &= ~ARM_DBGDSCR_MDBGEN
;
365 for (i
= 0; i
< 16; i
++) {
366 ((volatile uint32_t *)(debug_map
+ ARM_DEBUG_OFFSET_DBGBVR
))[i
] = debug_state
->bvr
[i
];
367 ((volatile uint32_t *)(debug_map
+ ARM_DEBUG_OFFSET_DBGBCR
))[i
] = debug_state
->bcr
[i
];
368 ((volatile uint32_t *)(debug_map
+ ARM_DEBUG_OFFSET_DBGWVR
))[i
] = debug_state
->wvr
[i
];
369 ((volatile uint32_t *)(debug_map
+ ARM_DEBUG_OFFSET_DBGWCR
))[i
] = debug_state
->wcr
[i
];
373 // lock debug registers
374 *(volatile uint32_t *)(debug_map
+ ARM_DEBUG_OFFSET_DBGLAR
) = 0;
376 } else if (debug_info
->coprocessor_core_debug
) {
377 arm_debug_set_cp14(debug_state
);
380 (void) ml_set_interrupts_enabled(intr
);
386 * Duplicate one arm_debug_state_t to another. "all" parameter
387 * is ignored in the case of ARM -- Is this the right assumption?
391 arm_debug_state_t
*src
,
392 arm_debug_state_t
*target
,
393 __unused boolean_t all
)
395 bcopy(src
, target
, sizeof(arm_debug_state_t
));
399 machine_thread_set_tsd_base(
401 mach_vm_offset_t tsd_base
)
404 if (thread
->task
== kernel_task
) {
405 return KERN_INVALID_ARGUMENT
;
408 if (tsd_base
& 0x3) {
409 return KERN_INVALID_ARGUMENT
;
412 if (tsd_base
> UINT32_MAX
)
415 thread
->machine
.cthread_self
= tsd_base
;
417 /* For current thread, make the TSD base active immediately */
418 if (thread
== current_thread()) {
420 mp_disable_preemption();
422 "mrc p15, 0, r6, c13, c0, 3\n"
425 "mcr p15, 0, r6, c13, c0, 3\n"
427 : "r"((uint32_t)tsd_base
) /* input */
428 : "r6" /* clobbered register */
430 mp_enable_preemption();
438 machine_tecs(__unused thread_t thr
)
443 machine_csv(__unused cpuvn_e cve
)