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