#include <debug.h>
#include <types.h>
#include <mach/mach_types.h>
#include <mach/thread_status.h>
#include <mach/vm_types.h>
#include <kern/kern_types.h>
#include <kern/task.h>
#include <kern/thread.h>
#include <kern/misc_protos.h>
#include <kern/mach_param.h>
#include <kern/spl.h>
#include <kern/machine.h>
#include <kern/kalloc.h>
#include <kern/kpc.h>
#include <arm/proc_reg.h>
#include <arm/cpu_data_internal.h>
#include <arm/misc_protos.h>
#include <arm/cpuid.h>
#include <vm/vm_map.h>
#include <vm/vm_protos.h>
#include <sys/kdebug.h>
extern int debug_task;
zone_t ads_zone;
void
consider_machine_collect(void)
{
pmap_gc();
}
void
consider_machine_adjust(void)
{
}
thread_t
machine_switch_context(
thread_t old,
thread_continue_t continuation,
thread_t new)
{
thread_t retval;
cpu_data_t *cpu_data_ptr;
#define machine_switch_context_kprintf(x...)
cpu_data_ptr = getCpuDatap();
if (old == new)
panic("machine_switch_context");
kpc_off_cpu(old);
pmap_set_pmap(new->map->pmap, new);
new->machine.CpuDatap = cpu_data_ptr;
machine_switch_context_kprintf("old= %x contination = %x new = %x\n", old, continuation, new);
retval = Switch_context(old, continuation, new);
assert(retval != NULL);
return retval;
}
kern_return_t
machine_thread_create(
thread_t thread,
#if !__ARM_USER_PROTECT__
__unused
#endif
task_t task)
{
#define machine_thread_create_kprintf(x...)
machine_thread_create_kprintf("thread = %x\n", thread);
if (current_thread() != thread) {
thread->machine.CpuDatap = (cpu_data_t *)0;
}
thread->machine.preemption_count = 0;
thread->machine.cthread_self = 0;
thread->machine.cthread_data = 0;
#if __ARM_USER_PROTECT__
{
struct pmap *new_pmap = vm_map_pmap(task->map);
thread->machine.kptw_ttb = ((unsigned int) kernel_pmap->ttep) | TTBR_SETUP;
thread->machine.asid = new_pmap->asid;
if (new_pmap->tte_index_max == NTTES) {
thread->machine.uptw_ttc = 2;
thread->machine.uptw_ttb = ((unsigned int) new_pmap->ttep) | TTBR_SETUP;
} else {
thread->machine.uptw_ttc = 1;
thread->machine.uptw_ttb = ((unsigned int) new_pmap->ttep ) | TTBR_SETUP;
}
}
#endif
machine_thread_state_initialize(thread);
return (KERN_SUCCESS);
}
void
machine_thread_destroy(
thread_t thread)
{
if (thread->machine.DebugData != NULL) {
if (thread->machine.DebugData == getCpuDatap()->cpu_user_debug)
arm_debug_set(NULL);
zfree(ads_zone, thread->machine.DebugData);
}
}
void
machine_thread_init(void)
{
ads_zone = zinit(sizeof(arm_debug_state_t),
THREAD_CHUNK * (sizeof(arm_debug_state_t)),
THREAD_CHUNK * (sizeof(arm_debug_state_t)),
"arm debug state");
}
user_addr_t
get_useraddr()
{
return (current_thread()->machine.PcbData.pc);
}
vm_offset_t
machine_stack_detach(
thread_t thread)
{
vm_offset_t stack;
KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED, MACH_STACK_DETACH),
(uintptr_t)thread_tid(thread), thread->priority, thread->sched_pri, 0, 0);
stack = thread->kernel_stack;
thread->kernel_stack = 0;
thread->machine.kstackptr = 0;
return (stack);
}
void
machine_stack_attach(
thread_t thread,
vm_offset_t stack)
{
struct arm_saved_state *savestate;
#define machine_stack_attach_kprintf(x...)
KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED, MACH_STACK_ATTACH),
(uintptr_t)thread_tid(thread), thread->priority, thread->sched_pri, 0, 0);
thread->kernel_stack = stack;
thread->machine.kstackptr = stack + kernel_stack_size - sizeof(struct thread_kernel_state);
thread_initialize_kernel_state(thread);
savestate = (struct arm_saved_state *) thread->machine.kstackptr;
savestate->lr = (uint32_t) thread_continue;
savestate->sp = thread->machine.kstackptr;
savestate->r[7] = 0x0UL;
savestate->r[9] = (uint32_t) NULL;
savestate->cpsr = PSR_SVC_MODE | PSR_INTMASK;
machine_stack_attach_kprintf("thread = %x pc = %x, sp = %x\n", thread, savestate->lr, savestate->sp);
}
void
machine_stack_handoff(
thread_t old,
thread_t new)
{
vm_offset_t stack;
cpu_data_t *cpu_data_ptr;
kpc_off_cpu(old);
stack = machine_stack_detach(old);
cpu_data_ptr = getCpuDatap();
new->kernel_stack = stack;
new->machine.kstackptr = stack + kernel_stack_size - sizeof(struct thread_kernel_state);
if (stack == old->reserved_stack) {
assert(new->reserved_stack);
old->reserved_stack = new->reserved_stack;
new->reserved_stack = stack;
}
pmap_set_pmap(new->map->pmap, new);
new->machine.CpuDatap = cpu_data_ptr;
machine_set_current_thread(new);
thread_initialize_kernel_state(new);
return;
}
void
call_continuation(
thread_continue_t continuation,
void *parameter,
wait_result_t wresult)
{
#define call_continuation_kprintf(x...)
call_continuation_kprintf("thread = %x continuation = %x, stack = %x\n", current_thread(), continuation, current_thread()->machine.kstackptr);
Call_continuation(continuation, parameter, wresult, current_thread()->machine.kstackptr);
}
void arm_debug_set(arm_debug_state_t *debug_state)
{
struct cpu_data *cpu_data_ptr;
arm_debug_info_t *debug_info = arm_debug_info();
boolean_t intr;
intr = ml_set_interrupts_enabled(FALSE);
cpu_data_ptr = getCpuDatap();
cpu_data_ptr->cpu_user_debug = debug_state;
if (debug_info->memory_mapped_core_debug) {
int i;
uintptr_t debug_map = cpu_data_ptr->cpu_debug_interface_map;
*(volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGLAR) = ARM_DBG_LOCK_ACCESS_KEY;
*(volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGPRSR);
*(volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGDSCR) |= ARM_DBGDSCR_MDBGEN;
for (i = 0; i < 16; i++) {
((volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGBCR))[i] = 0;
((volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGWCR))[i] = 0;
}
if (debug_state == NULL) {
*(volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGDSCR) &= ~ARM_DBGDSCR_MDBGEN;
} else {
for (i = 0; i < 16; i++) {
((volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGBVR))[i] = debug_state->bvr[i];
((volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGBCR))[i] = debug_state->bcr[i];
((volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGWVR))[i] = debug_state->wvr[i];
((volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGWCR))[i] = debug_state->wcr[i];
}
}
*(volatile uint32_t *)(debug_map + ARM_DEBUG_OFFSET_DBGLAR) = 0;
} else if (debug_info->coprocessor_core_debug) {
arm_debug_set_cp14(debug_state);
}
(void) ml_set_interrupts_enabled(intr);
return;
}
void
copy_debug_state(
arm_debug_state_t *src,
arm_debug_state_t *target,
__unused boolean_t all)
{
bcopy(src, target, sizeof(arm_debug_state_t));
}
kern_return_t
machine_thread_set_tsd_base(
thread_t thread,
mach_vm_offset_t tsd_base)
{
if (thread->task == kernel_task) {
return KERN_INVALID_ARGUMENT;
}
if (tsd_base & 0x3) {
return KERN_INVALID_ARGUMENT;
}
if (tsd_base > UINT32_MAX)
tsd_base = 0ULL;
thread->machine.cthread_self = tsd_base;
if (thread == current_thread()) {
mp_disable_preemption();
__asm__ volatile(
"mrc p15, 0, r6, c13, c0, 3\n"
"and r6, r6, #3\n"
"orr r6, r6, %0\n"
"mcr p15, 0, r6, c13, c0, 3\n"
:
: "r"((uint32_t)tsd_base)
: "r6"
);
mp_enable_preemption();
}
return KERN_SUCCESS;
}